blob: b455898df63c5d8b53913ab0c19ff45b337b349b [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 Berg7fee47782012-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 Berg7fee47782012-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 Berg7fee47782012-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 Berg7fee47782012-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 Berg7fee47782012-06-15 14:09:58 +0200164 else
165 tmp = NULL;
166
Johannes Berg7fee47782012-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 Berg2e161f782010-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 },
401 [NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 },
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 },
Johannes Berg55682962007-09-20 13:09:35 -0400413};
414
Johannes Berge31b8212010-10-05 19:39:30 +0200415/* policy for the key attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000416static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
Johannes Bergfffd0932009-07-08 14:22:54 +0200417 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
Johannes Bergb9454e82009-07-08 13:29:08 +0200418 [NL80211_KEY_IDX] = { .type = NLA_U8 },
419 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
Jouni Malinen81962262011-11-02 23:36:31 +0200420 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergb9454e82009-07-08 13:29:08 +0200421 [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
422 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
Johannes Berge31b8212010-10-05 19:39:30 +0200423 [NL80211_KEY_TYPE] = { .type = NLA_U32 },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100424 [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
425};
426
427/* policy for the key default flags */
428static const struct nla_policy
429nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
430 [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
431 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
Johannes Bergb9454e82009-07-08 13:29:08 +0200432};
433
Johannes Bergf83ace32016-10-17 08:04:07 +0200434#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +0200435/* policy for WoWLAN attributes */
436static const struct nla_policy
437nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
438 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
439 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
440 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
441 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
Johannes Berg77dbbb12011-07-13 10:48:55 +0200442 [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
443 [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
444 [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
445 [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100446 [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300447 [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100448};
449
450static const struct nla_policy
451nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
452 [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
453 [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
454 [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN },
455 [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
456 [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
457 [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 },
458 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
459 .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
460 },
461 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
462 .len = sizeof(struct nl80211_wowlan_tcp_data_token)
463 },
464 [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
465 [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
466 [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200467};
Johannes Bergf83ace32016-10-17 08:04:07 +0200468#endif /* CONFIG_PM */
Johannes Bergff1b6e62011-05-04 15:37:28 +0200469
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -0700470/* policy for coalesce rule attributes */
471static const struct nla_policy
472nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
473 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
474 [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
475 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
476};
477
Johannes Berge5497d72011-07-05 16:35:40 +0200478/* policy for GTK rekey offload attributes */
479static const struct nla_policy
480nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
481 [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
482 [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
483 [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
484};
485
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300486static const struct nla_policy
487nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
Johannes Berg4a4ab0d2012-06-13 11:17:11 +0200488 [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300489 .len = IEEE80211_MAX_SSID_LEN },
Thomas Pedersen88e920b2012-06-21 11:09:54 -0700490 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300491};
492
Avraham Stern3b06d272015-10-12 09:51:34 +0300493static const struct nla_policy
494nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
495 [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
496 [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
497};
498
Arend van Spriel38de03d2016-03-02 20:37:18 +0100499static const struct nla_policy
500nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
501 [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
502 [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
503 [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
504 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
505 },
506};
507
Ayala Bekera442b762016-09-20 17:31:15 +0300508/* policy for NAN function attributes */
509static const struct nla_policy
510nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
511 [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
512 [NL80211_NAN_FUNC_SERVICE_ID] = { .type = NLA_BINARY,
513 .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
514 [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
515 [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
516 [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
517 [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
518 [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
519 [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { .len = ETH_ALEN },
520 [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
521 [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
522 [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
523 .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
524 [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
525 [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
526 [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
527 [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
528 [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
529};
530
531/* policy for Service Response Filter attributes */
532static const struct nla_policy
533nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
534 [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
535 [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
536 .len = NL80211_NAN_FUNC_SRF_MAX_LEN },
537 [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
538 [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
539};
540
Johannes Berg97990a02013-04-19 01:02:55 +0200541static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
542 struct netlink_callback *cb,
543 struct cfg80211_registered_device **rdev,
544 struct wireless_dev **wdev)
Holger Schuriga0438972009-11-11 11:30:02 +0100545{
Johannes Berg67748892010-10-04 21:14:06 +0200546 int err;
547
Johannes Berg67748892010-10-04 21:14:06 +0200548 rtnl_lock();
549
Johannes Berg97990a02013-04-19 01:02:55 +0200550 if (!cb->args[0]) {
551 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +0200552 genl_family_attrbuf(&nl80211_fam),
553 nl80211_fam.maxattr, nl80211_policy);
Johannes Berg97990a02013-04-19 01:02:55 +0200554 if (err)
555 goto out_unlock;
556
Johannes Bergc90c39d2016-10-24 14:40:01 +0200557 *wdev = __cfg80211_wdev_from_attrs(
558 sock_net(skb->sk),
559 genl_family_attrbuf(&nl80211_fam));
Johannes Berg97990a02013-04-19 01:02:55 +0200560 if (IS_ERR(*wdev)) {
561 err = PTR_ERR(*wdev);
562 goto out_unlock;
563 }
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800564 *rdev = wiphy_to_rdev((*wdev)->wiphy);
Johannes Bergc319d502013-07-30 22:34:28 +0200565 /* 0 is the first index - add 1 to parse only once */
566 cb->args[0] = (*rdev)->wiphy_idx + 1;
Johannes Berg97990a02013-04-19 01:02:55 +0200567 cb->args[1] = (*wdev)->identifier;
568 } else {
Johannes Bergc319d502013-07-30 22:34:28 +0200569 /* subtract the 1 again here */
570 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
Johannes Berg97990a02013-04-19 01:02:55 +0200571 struct wireless_dev *tmp;
572
573 if (!wiphy) {
574 err = -ENODEV;
575 goto out_unlock;
576 }
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800577 *rdev = wiphy_to_rdev(wiphy);
Johannes Berg97990a02013-04-19 01:02:55 +0200578 *wdev = NULL;
579
Johannes Berg53873f12016-05-03 16:52:04 +0300580 list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
Johannes Berg97990a02013-04-19 01:02:55 +0200581 if (tmp->identifier == cb->args[1]) {
582 *wdev = tmp;
583 break;
584 }
585 }
Johannes Berg97990a02013-04-19 01:02:55 +0200586
587 if (!*wdev) {
588 err = -ENODEV;
589 goto out_unlock;
590 }
Johannes Berg67748892010-10-04 21:14:06 +0200591 }
592
Johannes Berg67748892010-10-04 21:14:06 +0200593 return 0;
Johannes Berg97990a02013-04-19 01:02:55 +0200594 out_unlock:
Johannes Berg67748892010-10-04 21:14:06 +0200595 rtnl_unlock();
596 return err;
597}
598
Johannes Berg97990a02013-04-19 01:02:55 +0200599static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
Johannes Berg67748892010-10-04 21:14:06 +0200600{
Johannes Berg67748892010-10-04 21:14:06 +0200601 rtnl_unlock();
602}
603
Johannes Bergf4a11bb2009-03-27 12:40:28 +0100604/* IE validation */
605static bool is_valid_ie_attr(const struct nlattr *attr)
606{
607 const u8 *pos;
608 int len;
609
610 if (!attr)
611 return true;
612
613 pos = nla_data(attr);
614 len = nla_len(attr);
615
616 while (len) {
617 u8 elemlen;
618
619 if (len < 2)
620 return false;
621 len -= 2;
622
623 elemlen = pos[1];
624 if (elemlen > len)
625 return false;
626
627 len -= elemlen;
628 pos += 2 + elemlen;
629 }
630
631 return true;
632}
633
Johannes Berg55682962007-09-20 13:09:35 -0400634/* message building helper */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000635static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
Johannes Berg55682962007-09-20 13:09:35 -0400636 int flags, u8 cmd)
637{
638 /* since there is no private header just add the generic one */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000639 return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -0400640}
641
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400642static int nl80211_msg_put_channel(struct sk_buff *msg,
Johannes Bergcdc89b92013-02-18 23:54:36 +0100643 struct ieee80211_channel *chan,
644 bool large)
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400645{
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200646 /* Some channels must be completely excluded from the
647 * list to protect old user-space tools from breaking
648 */
649 if (!large && chan->flags &
650 (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
651 return 0;
652
David S. Miller9360ffd2012-03-29 04:41:26 -0400653 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
654 chan->center_freq))
655 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400656
David S. Miller9360ffd2012-03-29 04:41:26 -0400657 if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
658 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
659 goto nla_put_failure;
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200660 if (chan->flags & IEEE80211_CHAN_NO_IR) {
661 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
662 goto nla_put_failure;
663 if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
664 goto nla_put_failure;
665 }
Johannes Bergcdc89b92013-02-18 23:54:36 +0100666 if (chan->flags & IEEE80211_CHAN_RADAR) {
667 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
668 goto nla_put_failure;
669 if (large) {
670 u32 time;
671
672 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
673
674 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
675 chan->dfs_state))
676 goto nla_put_failure;
677 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
678 time))
679 goto nla_put_failure;
Janusz Dziedzic089027e2014-02-21 19:46:12 +0100680 if (nla_put_u32(msg,
681 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
682 chan->dfs_cac_ms))
683 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +0100684 }
685 }
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400686
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100687 if (large) {
688 if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
689 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
690 goto nla_put_failure;
691 if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
692 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
693 goto nla_put_failure;
694 if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
695 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
696 goto nla_put_failure;
697 if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
698 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
699 goto nla_put_failure;
David Spinadel570dbde2014-02-23 09:12:59 +0200700 if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
701 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
702 goto nla_put_failure;
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300703 if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
704 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
David Spinadel570dbde2014-02-23 09:12:59 +0200705 goto nla_put_failure;
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200706 if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
707 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
708 goto nla_put_failure;
709 if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
710 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
711 goto nla_put_failure;
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100712 }
713
David S. Miller9360ffd2012-03-29 04:41:26 -0400714 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
715 DBM_TO_MBM(chan->max_power)))
716 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400717
718 return 0;
719
720 nla_put_failure:
721 return -ENOBUFS;
722}
723
Johannes Berg55682962007-09-20 13:09:35 -0400724/* netlink command implementations */
725
Johannes Bergb9454e82009-07-08 13:29:08 +0200726struct key_parse {
727 struct key_params p;
728 int idx;
Johannes Berge31b8212010-10-05 19:39:30 +0200729 int type;
Johannes Bergb9454e82009-07-08 13:29:08 +0200730 bool def, defmgmt;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100731 bool def_uni, def_multi;
Johannes Bergb9454e82009-07-08 13:29:08 +0200732};
733
734static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
735{
736 struct nlattr *tb[NL80211_KEY_MAX + 1];
737 int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
738 nl80211_key_policy);
739 if (err)
740 return err;
741
742 k->def = !!tb[NL80211_KEY_DEFAULT];
743 k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
744
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100745 if (k->def) {
746 k->def_uni = true;
747 k->def_multi = true;
748 }
749 if (k->defmgmt)
750 k->def_multi = true;
751
Johannes Bergb9454e82009-07-08 13:29:08 +0200752 if (tb[NL80211_KEY_IDX])
753 k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
754
755 if (tb[NL80211_KEY_DATA]) {
756 k->p.key = nla_data(tb[NL80211_KEY_DATA]);
757 k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
758 }
759
760 if (tb[NL80211_KEY_SEQ]) {
761 k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
762 k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
763 }
764
765 if (tb[NL80211_KEY_CIPHER])
766 k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
767
Johannes Berge31b8212010-10-05 19:39:30 +0200768 if (tb[NL80211_KEY_TYPE]) {
769 k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
770 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
771 return -EINVAL;
772 }
773
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100774 if (tb[NL80211_KEY_DEFAULT_TYPES]) {
775 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700776
Johannes Berg2da8f412012-01-20 13:52:37 +0100777 err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
778 tb[NL80211_KEY_DEFAULT_TYPES],
779 nl80211_key_default_policy);
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100780 if (err)
781 return err;
782
783 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
784 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
785 }
786
Johannes Bergb9454e82009-07-08 13:29:08 +0200787 return 0;
788}
789
790static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
791{
792 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
793 k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
794 k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
795 }
796
797 if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
798 k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
799 k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
800 }
801
802 if (info->attrs[NL80211_ATTR_KEY_IDX])
803 k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
804
805 if (info->attrs[NL80211_ATTR_KEY_CIPHER])
806 k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
807
808 k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
809 k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
810
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100811 if (k->def) {
812 k->def_uni = true;
813 k->def_multi = true;
814 }
815 if (k->defmgmt)
816 k->def_multi = true;
817
Johannes Berge31b8212010-10-05 19:39:30 +0200818 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
819 k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
820 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
821 return -EINVAL;
822 }
823
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100824 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
825 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
826 int err = nla_parse_nested(
827 kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
828 info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
829 nl80211_key_default_policy);
830 if (err)
831 return err;
832
833 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
834 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
835 }
836
Johannes Bergb9454e82009-07-08 13:29:08 +0200837 return 0;
838}
839
840static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
841{
842 int err;
843
844 memset(k, 0, sizeof(*k));
845 k->idx = -1;
Johannes Berge31b8212010-10-05 19:39:30 +0200846 k->type = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +0200847
848 if (info->attrs[NL80211_ATTR_KEY])
849 err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
850 else
851 err = nl80211_parse_key_old(info, k);
852
853 if (err)
854 return err;
855
856 if (k->def && k->defmgmt)
857 return -EINVAL;
858
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100859 if (k->defmgmt) {
860 if (k->def_uni || !k->def_multi)
861 return -EINVAL;
862 }
863
Johannes Bergb9454e82009-07-08 13:29:08 +0200864 if (k->idx != -1) {
865 if (k->defmgmt) {
866 if (k->idx < 4 || k->idx > 5)
867 return -EINVAL;
868 } else if (k->def) {
869 if (k->idx < 0 || k->idx > 3)
870 return -EINVAL;
871 } else {
872 if (k->idx < 0 || k->idx > 5)
873 return -EINVAL;
874 }
875 }
876
877 return 0;
878}
879
Johannes Bergfffd0932009-07-08 14:22:54 +0200880static struct cfg80211_cached_keys *
881nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +0530882 struct nlattr *keys, bool *no_ht)
Johannes Bergfffd0932009-07-08 14:22:54 +0200883{
884 struct key_parse parse;
885 struct nlattr *key;
886 struct cfg80211_cached_keys *result;
887 int rem, err, def = 0;
Johannes Bergf1c1f172016-09-13 17:08:23 +0200888 bool have_key = false;
889
890 nla_for_each_nested(key, keys, rem) {
891 have_key = true;
892 break;
893 }
894
895 if (!have_key)
896 return NULL;
Johannes Bergfffd0932009-07-08 14:22:54 +0200897
898 result = kzalloc(sizeof(*result), GFP_KERNEL);
899 if (!result)
900 return ERR_PTR(-ENOMEM);
901
902 result->def = -1;
Johannes Bergfffd0932009-07-08 14:22:54 +0200903
904 nla_for_each_nested(key, keys, rem) {
905 memset(&parse, 0, sizeof(parse));
906 parse.idx = -1;
907
908 err = nl80211_parse_key_new(key, &parse);
909 if (err)
910 goto error;
911 err = -EINVAL;
912 if (!parse.p.key)
913 goto error;
Johannes Berg42ee2312016-09-13 15:51:03 +0200914 if (parse.idx < 0 || parse.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +0200915 goto error;
916 if (parse.def) {
917 if (def)
918 goto error;
919 def = 1;
920 result->def = parse.idx;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100921 if (!parse.def_uni || !parse.def_multi)
922 goto error;
Johannes Bergfffd0932009-07-08 14:22:54 +0200923 } else if (parse.defmgmt)
924 goto error;
925 err = cfg80211_validate_key_settings(rdev, &parse.p,
Johannes Berge31b8212010-10-05 19:39:30 +0200926 parse.idx, false, NULL);
Johannes Bergfffd0932009-07-08 14:22:54 +0200927 if (err)
928 goto error;
Johannes Berg386b1f22016-09-13 16:10:02 +0200929 if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
930 parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
931 err = -EINVAL;
932 goto error;
933 }
Johannes Bergfffd0932009-07-08 14:22:54 +0200934 result->params[parse.idx].cipher = parse.p.cipher;
935 result->params[parse.idx].key_len = parse.p.key_len;
936 result->params[parse.idx].key = result->data[parse.idx];
937 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
Sujith Manoharande7044e2012-10-18 10:19:28 +0530938
Johannes Berg386b1f22016-09-13 16:10:02 +0200939 /* must be WEP key if we got here */
940 if (no_ht)
941 *no_ht = true;
Johannes Bergfffd0932009-07-08 14:22:54 +0200942 }
943
Johannes Bergf1c1f172016-09-13 17:08:23 +0200944 if (result->def < 0) {
945 err = -EINVAL;
946 goto error;
947 }
948
Johannes Bergfffd0932009-07-08 14:22:54 +0200949 return result;
950 error:
951 kfree(result);
952 return ERR_PTR(err);
953}
954
955static int nl80211_key_allowed(struct wireless_dev *wdev)
956{
957 ASSERT_WDEV_LOCK(wdev);
958
Johannes Bergfffd0932009-07-08 14:22:54 +0200959 switch (wdev->iftype) {
960 case NL80211_IFTYPE_AP:
961 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +0200962 case NL80211_IFTYPE_P2P_GO:
Thomas Pedersenff973af2011-05-03 16:57:12 -0700963 case NL80211_IFTYPE_MESH_POINT:
Johannes Bergfffd0932009-07-08 14:22:54 +0200964 break;
965 case NL80211_IFTYPE_ADHOC:
Johannes Bergfffd0932009-07-08 14:22:54 +0200966 case NL80211_IFTYPE_STATION:
Johannes Berg074ac8d2010-09-16 14:58:22 +0200967 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Bergceca7b72013-05-16 00:55:45 +0200968 if (!wdev->current_bss)
Johannes Bergfffd0932009-07-08 14:22:54 +0200969 return -ENOLINK;
970 break;
Johannes Bergde4fcba2014-10-31 14:16:12 +0100971 case NL80211_IFTYPE_UNSPECIFIED:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100972 case NL80211_IFTYPE_OCB:
Johannes Bergde4fcba2014-10-31 14:16:12 +0100973 case NL80211_IFTYPE_MONITOR:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300974 case NL80211_IFTYPE_NAN:
Johannes Bergde4fcba2014-10-31 14:16:12 +0100975 case NL80211_IFTYPE_P2P_DEVICE:
976 case NL80211_IFTYPE_WDS:
977 case NUM_NL80211_IFTYPES:
Johannes Bergfffd0932009-07-08 14:22:54 +0200978 return -EINVAL;
979 }
980
981 return 0;
982}
983
Jouni Malinen664834d2014-01-15 00:01:44 +0200984static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
985 struct nlattr *tb)
986{
987 struct ieee80211_channel *chan;
988
989 if (tb == NULL)
990 return NULL;
991 chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
992 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
993 return NULL;
994 return chan;
995}
996
Johannes Berg7527a782011-05-13 10:58:57 +0200997static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
998{
999 struct nlattr *nl_modes = nla_nest_start(msg, attr);
1000 int i;
1001
1002 if (!nl_modes)
1003 goto nla_put_failure;
1004
1005 i = 0;
1006 while (ifmodes) {
David S. Miller9360ffd2012-03-29 04:41:26 -04001007 if ((ifmodes & 1) && nla_put_flag(msg, i))
1008 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001009 ifmodes >>= 1;
1010 i++;
1011 }
1012
1013 nla_nest_end(msg, nl_modes);
1014 return 0;
1015
1016nla_put_failure:
1017 return -ENOBUFS;
1018}
1019
1020static int nl80211_put_iface_combinations(struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +01001021 struct sk_buff *msg,
1022 bool large)
Johannes Berg7527a782011-05-13 10:58:57 +02001023{
1024 struct nlattr *nl_combis;
1025 int i, j;
1026
1027 nl_combis = nla_nest_start(msg,
1028 NL80211_ATTR_INTERFACE_COMBINATIONS);
1029 if (!nl_combis)
1030 goto nla_put_failure;
1031
1032 for (i = 0; i < wiphy->n_iface_combinations; i++) {
1033 const struct ieee80211_iface_combination *c;
1034 struct nlattr *nl_combi, *nl_limits;
1035
1036 c = &wiphy->iface_combinations[i];
1037
1038 nl_combi = nla_nest_start(msg, i + 1);
1039 if (!nl_combi)
1040 goto nla_put_failure;
1041
1042 nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS);
1043 if (!nl_limits)
1044 goto nla_put_failure;
1045
1046 for (j = 0; j < c->n_limits; j++) {
1047 struct nlattr *nl_limit;
1048
1049 nl_limit = nla_nest_start(msg, j + 1);
1050 if (!nl_limit)
1051 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04001052 if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
1053 c->limits[j].max))
1054 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001055 if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
1056 c->limits[j].types))
1057 goto nla_put_failure;
1058 nla_nest_end(msg, nl_limit);
1059 }
1060
1061 nla_nest_end(msg, nl_limits);
1062
David S. Miller9360ffd2012-03-29 04:41:26 -04001063 if (c->beacon_int_infra_match &&
1064 nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
1065 goto nla_put_failure;
1066 if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
1067 c->num_different_channels) ||
1068 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
1069 c->max_interfaces))
1070 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +01001071 if (large &&
Felix Fietkau8c48b502014-05-05 11:48:40 +02001072 (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
1073 c->radar_detect_widths) ||
1074 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
1075 c->radar_detect_regions)))
Johannes Bergcdc89b92013-02-18 23:54:36 +01001076 goto nla_put_failure;
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05301077 if (c->beacon_int_min_gcd &&
1078 nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
1079 c->beacon_int_min_gcd))
1080 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001081
1082 nla_nest_end(msg, nl_combi);
1083 }
1084
1085 nla_nest_end(msg, nl_combis);
1086
1087 return 0;
1088nla_put_failure:
1089 return -ENOBUFS;
1090}
1091
Johannes Berg3713b4e2013-02-14 16:19:38 +01001092#ifdef CONFIG_PM
Johannes Bergb56cf722013-02-20 01:02:38 +01001093static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
1094 struct sk_buff *msg)
1095{
Johannes Berg964dc9e2013-06-03 17:25:34 +02001096 const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
Johannes Bergb56cf722013-02-20 01:02:38 +01001097 struct nlattr *nl_tcp;
1098
1099 if (!tcp)
1100 return 0;
1101
1102 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
1103 if (!nl_tcp)
1104 return -ENOBUFS;
1105
1106 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1107 tcp->data_payload_max))
1108 return -ENOBUFS;
1109
1110 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1111 tcp->data_payload_max))
1112 return -ENOBUFS;
1113
1114 if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
1115 return -ENOBUFS;
1116
1117 if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
1118 sizeof(*tcp->tok), tcp->tok))
1119 return -ENOBUFS;
1120
1121 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
1122 tcp->data_interval_max))
1123 return -ENOBUFS;
1124
1125 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
1126 tcp->wake_payload_max))
1127 return -ENOBUFS;
1128
1129 nla_nest_end(msg, nl_tcp);
1130 return 0;
1131}
1132
Johannes Berg3713b4e2013-02-14 16:19:38 +01001133static int nl80211_send_wowlan(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001134 struct cfg80211_registered_device *rdev,
Johannes Bergb56cf722013-02-20 01:02:38 +01001135 bool large)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001136{
1137 struct nlattr *nl_wowlan;
1138
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001139 if (!rdev->wiphy.wowlan)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001140 return 0;
1141
1142 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
1143 if (!nl_wowlan)
1144 return -ENOBUFS;
1145
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001146 if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001147 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001148 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001149 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001150 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001151 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001152 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001153 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001154 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001155 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001156 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001157 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001158 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001159 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001160 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001161 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1162 return -ENOBUFS;
1163
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001164 if (rdev->wiphy.wowlan->n_patterns) {
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07001165 struct nl80211_pattern_support pat = {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001166 .max_patterns = rdev->wiphy.wowlan->n_patterns,
1167 .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
1168 .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
1169 .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001170 };
1171
1172 if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1173 sizeof(pat), &pat))
1174 return -ENOBUFS;
1175 }
1176
Luciano Coelho75453cc2015-01-09 14:06:37 +02001177 if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
1178 nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
1179 rdev->wiphy.wowlan->max_nd_match_sets))
1180 return -ENOBUFS;
1181
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001182 if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
Johannes Bergb56cf722013-02-20 01:02:38 +01001183 return -ENOBUFS;
1184
Johannes Berg3713b4e2013-02-14 16:19:38 +01001185 nla_nest_end(msg, nl_wowlan);
1186
1187 return 0;
1188}
1189#endif
1190
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001191static int nl80211_send_coalesce(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001192 struct cfg80211_registered_device *rdev)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001193{
1194 struct nl80211_coalesce_rule_support rule;
1195
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001196 if (!rdev->wiphy.coalesce)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001197 return 0;
1198
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001199 rule.max_rules = rdev->wiphy.coalesce->n_rules;
1200 rule.max_delay = rdev->wiphy.coalesce->max_delay;
1201 rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
1202 rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
1203 rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
1204 rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001205
1206 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1207 return -ENOBUFS;
1208
1209 return 0;
1210}
1211
Johannes Berg3713b4e2013-02-14 16:19:38 +01001212static int nl80211_send_band_rateinfo(struct sk_buff *msg,
1213 struct ieee80211_supported_band *sband)
1214{
1215 struct nlattr *nl_rates, *nl_rate;
1216 struct ieee80211_rate *rate;
1217 int i;
1218
1219 /* add HT info */
1220 if (sband->ht_cap.ht_supported &&
1221 (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1222 sizeof(sband->ht_cap.mcs),
1223 &sband->ht_cap.mcs) ||
1224 nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1225 sband->ht_cap.cap) ||
1226 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1227 sband->ht_cap.ampdu_factor) ||
1228 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1229 sband->ht_cap.ampdu_density)))
1230 return -ENOBUFS;
1231
1232 /* add VHT info */
1233 if (sband->vht_cap.vht_supported &&
1234 (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1235 sizeof(sband->vht_cap.vht_mcs),
1236 &sband->vht_cap.vht_mcs) ||
1237 nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1238 sband->vht_cap.cap)))
1239 return -ENOBUFS;
1240
1241 /* add bitrates */
1242 nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
1243 if (!nl_rates)
1244 return -ENOBUFS;
1245
1246 for (i = 0; i < sband->n_bitrates; i++) {
1247 nl_rate = nla_nest_start(msg, i);
1248 if (!nl_rate)
1249 return -ENOBUFS;
1250
1251 rate = &sband->bitrates[i];
1252 if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1253 rate->bitrate))
1254 return -ENOBUFS;
1255 if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1256 nla_put_flag(msg,
1257 NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1258 return -ENOBUFS;
1259
1260 nla_nest_end(msg, nl_rate);
1261 }
1262
1263 nla_nest_end(msg, nl_rates);
1264
1265 return 0;
1266}
1267
1268static int
1269nl80211_send_mgmt_stypes(struct sk_buff *msg,
1270 const struct ieee80211_txrx_stypes *mgmt_stypes)
1271{
1272 u16 stypes;
1273 struct nlattr *nl_ftypes, *nl_ifs;
1274 enum nl80211_iftype ift;
1275 int i;
1276
1277 if (!mgmt_stypes)
1278 return 0;
1279
1280 nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
1281 if (!nl_ifs)
1282 return -ENOBUFS;
1283
1284 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1285 nl_ftypes = nla_nest_start(msg, ift);
1286 if (!nl_ftypes)
1287 return -ENOBUFS;
1288 i = 0;
1289 stypes = mgmt_stypes[ift].tx;
1290 while (stypes) {
1291 if ((stypes & 1) &&
1292 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1293 (i << 4) | IEEE80211_FTYPE_MGMT))
1294 return -ENOBUFS;
1295 stypes >>= 1;
1296 i++;
1297 }
1298 nla_nest_end(msg, nl_ftypes);
1299 }
1300
1301 nla_nest_end(msg, nl_ifs);
1302
1303 nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
1304 if (!nl_ifs)
1305 return -ENOBUFS;
1306
1307 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1308 nl_ftypes = nla_nest_start(msg, ift);
1309 if (!nl_ftypes)
1310 return -ENOBUFS;
1311 i = 0;
1312 stypes = mgmt_stypes[ift].rx;
1313 while (stypes) {
1314 if ((stypes & 1) &&
1315 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1316 (i << 4) | IEEE80211_FTYPE_MGMT))
1317 return -ENOBUFS;
1318 stypes >>= 1;
1319 i++;
1320 }
1321 nla_nest_end(msg, nl_ftypes);
1322 }
1323 nla_nest_end(msg, nl_ifs);
1324
1325 return 0;
1326}
1327
Johannes Berg17948992016-10-26 11:42:04 +02001328#define CMD(op, n) \
1329 do { \
1330 if (rdev->ops->op) { \
1331 i++; \
1332 if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1333 goto nla_put_failure; \
1334 } \
1335 } while (0)
1336
1337static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
1338 struct sk_buff *msg)
1339{
1340 int i = 0;
1341
1342 /*
1343 * do *NOT* add anything into this function, new things need to be
1344 * advertised only to new versions of userspace that can deal with
1345 * the split (and they can't possibly care about new features...
1346 */
1347 CMD(add_virtual_intf, NEW_INTERFACE);
1348 CMD(change_virtual_intf, SET_INTERFACE);
1349 CMD(add_key, NEW_KEY);
1350 CMD(start_ap, START_AP);
1351 CMD(add_station, NEW_STATION);
1352 CMD(add_mpath, NEW_MPATH);
1353 CMD(update_mesh_config, SET_MESH_CONFIG);
1354 CMD(change_bss, SET_BSS);
1355 CMD(auth, AUTHENTICATE);
1356 CMD(assoc, ASSOCIATE);
1357 CMD(deauth, DEAUTHENTICATE);
1358 CMD(disassoc, DISASSOCIATE);
1359 CMD(join_ibss, JOIN_IBSS);
1360 CMD(join_mesh, JOIN_MESH);
1361 CMD(set_pmksa, SET_PMKSA);
1362 CMD(del_pmksa, DEL_PMKSA);
1363 CMD(flush_pmksa, FLUSH_PMKSA);
1364 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1365 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1366 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1367 CMD(mgmt_tx, FRAME);
1368 CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1369 if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1370 i++;
1371 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1372 goto nla_put_failure;
1373 }
1374 if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
1375 rdev->ops->join_mesh) {
1376 i++;
1377 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1378 goto nla_put_failure;
1379 }
1380 CMD(set_wds_peer, SET_WDS_PEER);
1381 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1382 CMD(tdls_mgmt, TDLS_MGMT);
1383 CMD(tdls_oper, TDLS_OPER);
1384 }
1385 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
1386 CMD(sched_scan_start, START_SCHED_SCAN);
1387 CMD(probe_client, PROBE_CLIENT);
1388 CMD(set_noack_map, SET_NOACK_MAP);
1389 if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1390 i++;
1391 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1392 goto nla_put_failure;
1393 }
1394 CMD(start_p2p_device, START_P2P_DEVICE);
1395 CMD(set_mcast_rate, SET_MCAST_RATE);
1396#ifdef CONFIG_NL80211_TESTMODE
1397 CMD(testmode_cmd, TESTMODE);
1398#endif
1399
1400 if (rdev->ops->connect || rdev->ops->auth) {
1401 i++;
1402 if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1403 goto nla_put_failure;
1404 }
1405
1406 if (rdev->ops->disconnect || rdev->ops->deauth) {
1407 i++;
1408 if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1409 goto nla_put_failure;
1410 }
1411
1412 return i;
1413 nla_put_failure:
1414 return -ENOBUFS;
1415}
1416
Johannes Berg86e8cf92013-06-19 10:57:22 +02001417struct nl80211_dump_wiphy_state {
1418 s64 filter_wiphy;
1419 long start;
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301420 long split_start, band_start, chan_start, capa_start;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001421 bool split;
1422};
1423
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001424static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
Johannes Berg3bb20552014-05-26 13:52:25 +02001425 enum nl80211_commands cmd,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001426 struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001427 int flags, struct nl80211_dump_wiphy_state *state)
Johannes Berg55682962007-09-20 13:09:35 -04001428{
1429 void *hdr;
Johannes Bergee688b002008-01-24 19:38:39 +01001430 struct nlattr *nl_bands, *nl_band;
1431 struct nlattr *nl_freqs, *nl_freq;
Johannes Berg8fdc6212009-03-14 09:34:01 +01001432 struct nlattr *nl_cmds;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001433 enum nl80211_band band;
Johannes Bergee688b002008-01-24 19:38:39 +01001434 struct ieee80211_channel *chan;
Johannes Bergee688b002008-01-24 19:38:39 +01001435 int i;
Johannes Berg2e161f782010-08-12 15:38:38 +02001436 const struct ieee80211_txrx_stypes *mgmt_stypes =
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001437 rdev->wiphy.mgmt_stypes;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001438 u32 features;
Johannes Berg55682962007-09-20 13:09:35 -04001439
Johannes Berg3bb20552014-05-26 13:52:25 +02001440 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04001441 if (!hdr)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001442 return -ENOBUFS;
1443
Johannes Berg86e8cf92013-06-19 10:57:22 +02001444 if (WARN_ON(!state))
1445 return -EINVAL;
Johannes Berg55682962007-09-20 13:09:35 -04001446
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001447 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001448 nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001449 wiphy_name(&rdev->wiphy)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04001450 nla_put_u32(msg, NL80211_ATTR_GENERATION,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001451 cfg80211_rdev_list_generation))
David S. Miller9360ffd2012-03-29 04:41:26 -04001452 goto nla_put_failure;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02001453
Johannes Berg3bb20552014-05-26 13:52:25 +02001454 if (cmd != NL80211_CMD_NEW_WIPHY)
1455 goto finish;
1456
Johannes Berg86e8cf92013-06-19 10:57:22 +02001457 switch (state->split_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001458 case 0:
1459 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001460 rdev->wiphy.retry_short) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001461 nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001462 rdev->wiphy.retry_long) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001463 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001464 rdev->wiphy.frag_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001465 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001466 rdev->wiphy.rts_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001467 nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001468 rdev->wiphy.coverage_class) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001469 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001470 rdev->wiphy.max_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001471 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001472 rdev->wiphy.max_sched_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001473 nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001474 rdev->wiphy.max_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001475 nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001476 rdev->wiphy.max_sched_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001477 nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
Avraham Stern3b06d272015-10-12 09:51:34 +03001478 rdev->wiphy.max_match_sets) ||
1479 nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
1480 rdev->wiphy.max_sched_scan_plans) ||
1481 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
1482 rdev->wiphy.max_sched_scan_plan_interval) ||
1483 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
1484 rdev->wiphy.max_sched_scan_plan_iterations))
Johannes Bergee688b002008-01-24 19:38:39 +01001485 goto nla_put_failure;
1486
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001487 if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001488 nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
1489 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001490 if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001491 nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
1492 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001493 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001494 nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
1495 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001496 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001497 nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
1498 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001499 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001500 nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
1501 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001502 if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001503 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
David S. Miller9360ffd2012-03-29 04:41:26 -04001504 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001505 state->split_start++;
1506 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001507 break;
1508 case 1:
1509 if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001510 sizeof(u32) * rdev->wiphy.n_cipher_suites,
1511 rdev->wiphy.cipher_suites))
Mahesh Palivelabf0c111e2012-06-22 07:27:46 +00001512 goto nla_put_failure;
1513
Johannes Berg3713b4e2013-02-14 16:19:38 +01001514 if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001515 rdev->wiphy.max_num_pmkids))
Johannes Bergee688b002008-01-24 19:38:39 +01001516 goto nla_put_failure;
1517
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001518 if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001519 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
1520 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001521
Johannes Berg3713b4e2013-02-14 16:19:38 +01001522 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001523 rdev->wiphy.available_antennas_tx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001524 nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001525 rdev->wiphy.available_antennas_rx))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001526 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001527
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001528 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001529 nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001530 rdev->wiphy.probe_resp_offload))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001531 goto nla_put_failure;
Jouni Malinene2f367f262008-11-21 19:01:30 +02001532
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001533 if ((rdev->wiphy.available_antennas_tx ||
1534 rdev->wiphy.available_antennas_rx) &&
1535 rdev->ops->get_antenna) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001536 u32 tx_ant = 0, rx_ant = 0;
1537 int res;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07001538
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001539 res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001540 if (!res) {
1541 if (nla_put_u32(msg,
1542 NL80211_ATTR_WIPHY_ANTENNA_TX,
1543 tx_ant) ||
1544 nla_put_u32(msg,
1545 NL80211_ATTR_WIPHY_ANTENNA_RX,
1546 rx_ant))
1547 goto nla_put_failure;
1548 }
Johannes Bergee688b002008-01-24 19:38:39 +01001549 }
1550
Johannes Berg86e8cf92013-06-19 10:57:22 +02001551 state->split_start++;
1552 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001553 break;
1554 case 2:
1555 if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001556 rdev->wiphy.interface_modes))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001557 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001558 state->split_start++;
1559 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001560 break;
1561 case 3:
1562 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
1563 if (!nl_bands)
Johannes Bergee688b002008-01-24 19:38:39 +01001564 goto nla_put_failure;
1565
Johannes Berg86e8cf92013-06-19 10:57:22 +02001566 for (band = state->band_start;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001567 band < NUM_NL80211_BANDS; band++) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001568 struct ieee80211_supported_band *sband;
1569
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001570 sband = rdev->wiphy.bands[band];
Johannes Berg3713b4e2013-02-14 16:19:38 +01001571
1572 if (!sband)
1573 continue;
1574
1575 nl_band = nla_nest_start(msg, band);
1576 if (!nl_band)
Johannes Bergee688b002008-01-24 19:38:39 +01001577 goto nla_put_failure;
1578
Johannes Berg86e8cf92013-06-19 10:57:22 +02001579 switch (state->chan_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001580 case 0:
1581 if (nl80211_send_band_rateinfo(msg, sband))
1582 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001583 state->chan_start++;
1584 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001585 break;
1586 default:
1587 /* add frequencies */
1588 nl_freqs = nla_nest_start(
1589 msg, NL80211_BAND_ATTR_FREQS);
1590 if (!nl_freqs)
1591 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001592
Johannes Berg86e8cf92013-06-19 10:57:22 +02001593 for (i = state->chan_start - 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001594 i < sband->n_channels;
1595 i++) {
1596 nl_freq = nla_nest_start(msg, i);
1597 if (!nl_freq)
1598 goto nla_put_failure;
1599
1600 chan = &sband->channels[i];
1601
Johannes Berg86e8cf92013-06-19 10:57:22 +02001602 if (nl80211_msg_put_channel(
1603 msg, chan,
1604 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001605 goto nla_put_failure;
1606
1607 nla_nest_end(msg, nl_freq);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001608 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001609 break;
1610 }
1611 if (i < sband->n_channels)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001612 state->chan_start = i + 2;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001613 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001614 state->chan_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001615 nla_nest_end(msg, nl_freqs);
1616 }
1617
1618 nla_nest_end(msg, nl_band);
1619
Johannes Berg86e8cf92013-06-19 10:57:22 +02001620 if (state->split) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001621 /* start again here */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001622 if (state->chan_start)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001623 band--;
1624 break;
1625 }
Johannes Bergee688b002008-01-24 19:38:39 +01001626 }
Johannes Berg3713b4e2013-02-14 16:19:38 +01001627 nla_nest_end(msg, nl_bands);
Johannes Bergee688b002008-01-24 19:38:39 +01001628
Johannes Berg57fbcce2016-04-12 15:56:15 +02001629 if (band < NUM_NL80211_BANDS)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001630 state->band_start = band + 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001631 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001632 state->band_start = 0;
Johannes Bergee688b002008-01-24 19:38:39 +01001633
Johannes Berg3713b4e2013-02-14 16:19:38 +01001634 /* if bands & channels are done, continue outside */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001635 if (state->band_start == 0 && state->chan_start == 0)
1636 state->split_start++;
1637 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001638 break;
1639 case 4:
1640 nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
1641 if (!nl_cmds)
David S. Miller9360ffd2012-03-29 04:41:26 -04001642 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001643
Johannes Berg17948992016-10-26 11:42:04 +02001644 i = nl80211_add_commands_unsplit(rdev, msg);
1645 if (i < 0)
1646 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001647 if (state->split) {
Arend van Spriel5de17982013-04-18 15:49:00 +02001648 CMD(crit_proto_start, CRIT_PROTOCOL_START);
1649 CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001650 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02001651 CMD(channel_switch, CHANNEL_SWITCH);
Johannes Berg02df00e2014-06-10 14:06:25 +02001652 CMD(set_qos_map, SET_QOS_MAP);
Johannes Berg723e73a2014-10-22 09:25:06 +02001653 if (rdev->wiphy.features &
1654 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
Johannes Berg960d01a2014-09-09 22:55:35 +03001655 CMD(add_tx_ts, ADD_TX_TS);
Michael Braunce0ce132016-10-10 19:12:22 +02001656 CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
vamsi krishna088e8df2016-10-27 16:51:11 +03001657 CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
Arend van Spriel5de17982013-04-18 15:49:00 +02001658 }
Johannes Berg8fdc6212009-03-14 09:34:01 +01001659#undef CMD
Samuel Ortizb23aa672009-07-01 21:26:54 +02001660
Johannes Berg3713b4e2013-02-14 16:19:38 +01001661 nla_nest_end(msg, nl_cmds);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001662 state->split_start++;
1663 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001664 break;
1665 case 5:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001666 if (rdev->ops->remain_on_channel &&
1667 (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001668 nla_put_u32(msg,
1669 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001670 rdev->wiphy.max_remain_on_channel_duration))
Johannes Berg2e161f782010-08-12 15:38:38 +02001671 goto nla_put_failure;
1672
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001673 if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001674 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
1675 goto nla_put_failure;
Johannes Berg2e161f782010-08-12 15:38:38 +02001676
Johannes Berg3713b4e2013-02-14 16:19:38 +01001677 if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
1678 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001679 state->split_start++;
1680 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001681 break;
1682 case 6:
Johannes Bergdfb89c52012-06-27 09:23:48 +02001683#ifdef CONFIG_PM
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001684 if (nl80211_send_wowlan(msg, rdev, state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001685 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001686 state->split_start++;
1687 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001688 break;
1689#else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001690 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001691#endif
1692 case 7:
1693 if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001694 rdev->wiphy.software_iftypes))
Johannes Bergff1b6e62011-05-04 15:37:28 +02001695 goto nla_put_failure;
1696
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001697 if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001698 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001699 goto nla_put_failure;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001700
Johannes Berg86e8cf92013-06-19 10:57:22 +02001701 state->split_start++;
1702 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001703 break;
1704 case 8:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001705 if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001706 nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001707 rdev->wiphy.ap_sme_capa))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001708 goto nla_put_failure;
1709
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001710 features = rdev->wiphy.features;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001711 /*
1712 * We can only add the per-channel limit information if the
1713 * dump is split, otherwise it makes it too big. Therefore
1714 * only advertise it in that case.
1715 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001716 if (state->split)
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001717 features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
1718 if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001719 goto nla_put_failure;
1720
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001721 if (rdev->wiphy.ht_capa_mod_mask &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001722 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001723 sizeof(*rdev->wiphy.ht_capa_mod_mask),
1724 rdev->wiphy.ht_capa_mod_mask))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001725 goto nla_put_failure;
1726
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001727 if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
1728 rdev->wiphy.max_acl_mac_addrs &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001729 nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001730 rdev->wiphy.max_acl_mac_addrs))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001731 goto nla_put_failure;
1732
1733 /*
1734 * Any information below this point is only available to
1735 * applications that can deal with it being split. This
1736 * helps ensure that newly added capabilities don't break
1737 * older tools by overrunning their buffers.
1738 *
1739 * We still increment split_start so that in the split
1740 * case we'll continue with more data in the next round,
1741 * but break unconditionally so unsplit data stops here.
1742 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001743 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001744 break;
1745 case 9:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001746 if (rdev->wiphy.extended_capabilities &&
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001747 (nla_put(msg, NL80211_ATTR_EXT_CAPA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001748 rdev->wiphy.extended_capabilities_len,
1749 rdev->wiphy.extended_capabilities) ||
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001750 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001751 rdev->wiphy.extended_capabilities_len,
1752 rdev->wiphy.extended_capabilities_mask)))
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001753 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001754
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001755 if (rdev->wiphy.vht_capa_mod_mask &&
Johannes Bergee2aca32013-02-21 17:36:01 +01001756 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001757 sizeof(*rdev->wiphy.vht_capa_mod_mask),
1758 rdev->wiphy.vht_capa_mod_mask))
Johannes Bergee2aca32013-02-21 17:36:01 +01001759 goto nla_put_failure;
1760
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001761 state->split_start++;
1762 break;
1763 case 10:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001764 if (nl80211_send_coalesce(msg, rdev))
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001765 goto nla_put_failure;
1766
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001767 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001768 (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
1769 nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
1770 goto nla_put_failure;
Jouni Malinenb43504c2014-01-15 00:01:08 +02001771
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001772 if (rdev->wiphy.max_ap_assoc_sta &&
Jouni Malinenb43504c2014-01-15 00:01:08 +02001773 nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001774 rdev->wiphy.max_ap_assoc_sta))
Jouni Malinenb43504c2014-01-15 00:01:08 +02001775 goto nla_put_failure;
1776
Johannes Bergad7e7182013-11-13 13:37:47 +01001777 state->split_start++;
1778 break;
1779 case 11:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001780 if (rdev->wiphy.n_vendor_commands) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001781 const struct nl80211_vendor_cmd_info *info;
1782 struct nlattr *nested;
Johannes Bergad7e7182013-11-13 13:37:47 +01001783
Johannes Berg567ffc32013-12-18 14:43:31 +01001784 nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
1785 if (!nested)
Johannes Bergad7e7182013-11-13 13:37:47 +01001786 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01001787
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001788 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
1789 info = &rdev->wiphy.vendor_commands[i].info;
Johannes Berg567ffc32013-12-18 14:43:31 +01001790 if (nla_put(msg, i + 1, sizeof(*info), info))
1791 goto nla_put_failure;
1792 }
1793 nla_nest_end(msg, nested);
1794 }
1795
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001796 if (rdev->wiphy.n_vendor_events) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001797 const struct nl80211_vendor_cmd_info *info;
1798 struct nlattr *nested;
1799
1800 nested = nla_nest_start(msg,
1801 NL80211_ATTR_VENDOR_EVENTS);
1802 if (!nested)
1803 goto nla_put_failure;
1804
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001805 for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
1806 info = &rdev->wiphy.vendor_events[i];
Johannes Berg567ffc32013-12-18 14:43:31 +01001807 if (nla_put(msg, i + 1, sizeof(*info), info))
1808 goto nla_put_failure;
1809 }
1810 nla_nest_end(msg, nested);
1811 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03001812 state->split_start++;
1813 break;
1814 case 12:
1815 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
1816 nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
1817 rdev->wiphy.max_num_csa_counters))
1818 goto nla_put_failure;
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001819
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02001820 if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
1821 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
1822 goto nla_put_failure;
1823
Gautam Kumar Shuklad75bb062014-12-23 16:55:19 +01001824 if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
1825 sizeof(rdev->wiphy.ext_features),
1826 rdev->wiphy.ext_features))
1827 goto nla_put_failure;
1828
Arend van Spriel38de03d2016-03-02 20:37:18 +01001829 if (rdev->wiphy.bss_select_support) {
1830 struct nlattr *nested;
1831 u32 bss_select_support = rdev->wiphy.bss_select_support;
1832
1833 nested = nla_nest_start(msg, NL80211_ATTR_BSS_SELECT);
1834 if (!nested)
1835 goto nla_put_failure;
1836
1837 i = 0;
1838 while (bss_select_support) {
1839 if ((bss_select_support & 1) &&
1840 nla_put_flag(msg, i))
1841 goto nla_put_failure;
1842 i++;
1843 bss_select_support >>= 1;
1844 }
1845 nla_nest_end(msg, nested);
1846 }
1847
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301848 state->split_start++;
1849 break;
1850 case 13:
1851 if (rdev->wiphy.num_iftype_ext_capab &&
1852 rdev->wiphy.iftype_ext_capab) {
1853 struct nlattr *nested_ext_capab, *nested;
1854
1855 nested = nla_nest_start(msg,
1856 NL80211_ATTR_IFTYPE_EXT_CAPA);
1857 if (!nested)
1858 goto nla_put_failure;
1859
1860 for (i = state->capa_start;
1861 i < rdev->wiphy.num_iftype_ext_capab; i++) {
1862 const struct wiphy_iftype_ext_capab *capab;
1863
1864 capab = &rdev->wiphy.iftype_ext_capab[i];
1865
1866 nested_ext_capab = nla_nest_start(msg, i);
1867 if (!nested_ext_capab ||
1868 nla_put_u32(msg, NL80211_ATTR_IFTYPE,
1869 capab->iftype) ||
1870 nla_put(msg, NL80211_ATTR_EXT_CAPA,
1871 capab->extended_capabilities_len,
1872 capab->extended_capabilities) ||
1873 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
1874 capab->extended_capabilities_len,
1875 capab->extended_capabilities_mask))
1876 goto nla_put_failure;
1877
1878 nla_nest_end(msg, nested_ext_capab);
1879 if (state->split)
1880 break;
1881 }
1882 nla_nest_end(msg, nested);
1883 if (i < rdev->wiphy.num_iftype_ext_capab) {
1884 state->capa_start = i + 1;
1885 break;
1886 }
1887 }
1888
Johannes Berg3713b4e2013-02-14 16:19:38 +01001889 /* done */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001890 state->split_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001891 break;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001892 }
Johannes Berg3bb20552014-05-26 13:52:25 +02001893 finish:
Johannes Berg053c0952015-01-16 22:09:00 +01001894 genlmsg_end(msg, hdr);
1895 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04001896
1897 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001898 genlmsg_cancel(msg, hdr);
1899 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04001900}
1901
Johannes Berg86e8cf92013-06-19 10:57:22 +02001902static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
1903 struct netlink_callback *cb,
1904 struct nl80211_dump_wiphy_state *state)
1905{
Johannes Bergc90c39d2016-10-24 14:40:01 +02001906 struct nlattr **tb = genl_family_attrbuf(&nl80211_fam);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001907 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
1908 tb, nl80211_fam.maxattr, nl80211_policy);
1909 /* ignore parse errors for backward compatibility */
1910 if (ret)
1911 return 0;
1912
1913 state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
1914 if (tb[NL80211_ATTR_WIPHY])
1915 state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
1916 if (tb[NL80211_ATTR_WDEV])
1917 state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
1918 if (tb[NL80211_ATTR_IFINDEX]) {
1919 struct net_device *netdev;
1920 struct cfg80211_registered_device *rdev;
1921 int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
1922
Ying Xue7f2b8562014-01-15 10:23:45 +08001923 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001924 if (!netdev)
1925 return -ENODEV;
1926 if (netdev->ieee80211_ptr) {
Zhao, Gangf26cbf42014-04-21 12:53:03 +08001927 rdev = wiphy_to_rdev(
Johannes Berg86e8cf92013-06-19 10:57:22 +02001928 netdev->ieee80211_ptr->wiphy);
1929 state->filter_wiphy = rdev->wiphy_idx;
1930 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001931 }
1932
1933 return 0;
1934}
1935
Johannes Berg55682962007-09-20 13:09:35 -04001936static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
1937{
Johannes Berg645e77d2013-03-01 14:03:49 +01001938 int idx = 0, ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001939 struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001940 struct cfg80211_registered_device *rdev;
Johannes Berg3a5a4232013-06-19 10:09:57 +02001941
Johannes Berg5fe231e2013-05-08 21:45:15 +02001942 rtnl_lock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02001943 if (!state) {
1944 state = kzalloc(sizeof(*state), GFP_KERNEL);
John W. Linville57ed5cd2013-06-28 13:18:21 -04001945 if (!state) {
1946 rtnl_unlock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02001947 return -ENOMEM;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001948 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001949 state->filter_wiphy = -1;
1950 ret = nl80211_dump_wiphy_parse(skb, cb, state);
1951 if (ret) {
1952 kfree(state);
1953 rtnl_unlock();
1954 return ret;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001955 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001956 cb->args[0] = (long)state;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001957 }
1958
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001959 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
1960 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02001961 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001962 if (++idx <= state->start)
Johannes Berg55682962007-09-20 13:09:35 -04001963 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001964 if (state->filter_wiphy != -1 &&
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001965 state->filter_wiphy != rdev->wiphy_idx)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001966 continue;
1967 /* attempt to fit multiple wiphy data chunks into the skb */
1968 do {
Johannes Berg3bb20552014-05-26 13:52:25 +02001969 ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
1970 skb,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001971 NETLINK_CB(cb->skb).portid,
1972 cb->nlh->nlmsg_seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001973 NLM_F_MULTI, state);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001974 if (ret < 0) {
1975 /*
1976 * If sending the wiphy data didn't fit (ENOBUFS
1977 * or EMSGSIZE returned), this SKB is still
1978 * empty (so it's not too big because another
1979 * wiphy dataset is already in the skb) and
1980 * we've not tried to adjust the dump allocation
1981 * yet ... then adjust the alloc size to be
1982 * bigger, and return 1 but with the empty skb.
1983 * This results in an empty message being RX'ed
1984 * in userspace, but that is ignored.
1985 *
1986 * We can then retry with the larger buffer.
1987 */
1988 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
Pontus Fuchsf12cb282014-01-16 15:00:40 +01001989 !skb->len && !state->split &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001990 cb->min_dump_alloc < 4096) {
1991 cb->min_dump_alloc = 4096;
Pontus Fuchsf12cb282014-01-16 15:00:40 +01001992 state->split_start = 0;
David S. Millerd98cae64e2013-06-19 16:49:39 -07001993 rtnl_unlock();
Johannes Berg3713b4e2013-02-14 16:19:38 +01001994 return 1;
1995 }
1996 idx--;
1997 break;
Johannes Berg645e77d2013-03-01 14:03:49 +01001998 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001999 } while (state->split_start > 0);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002000 break;
Johannes Berg55682962007-09-20 13:09:35 -04002001 }
Johannes Berg5fe231e2013-05-08 21:45:15 +02002002 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002003
Johannes Berg86e8cf92013-06-19 10:57:22 +02002004 state->start = idx;
Johannes Berg55682962007-09-20 13:09:35 -04002005
2006 return skb->len;
2007}
2008
Johannes Berg86e8cf92013-06-19 10:57:22 +02002009static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
2010{
2011 kfree((void *)cb->args[0]);
2012 return 0;
2013}
2014
Johannes Berg55682962007-09-20 13:09:35 -04002015static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
2016{
2017 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002018 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg86e8cf92013-06-19 10:57:22 +02002019 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -04002020
Johannes Berg645e77d2013-03-01 14:03:49 +01002021 msg = nlmsg_new(4096, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002022 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002023 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002024
Johannes Berg3bb20552014-05-26 13:52:25 +02002025 if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
2026 info->snd_portid, info->snd_seq, 0,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002027 &state) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002028 nlmsg_free(msg);
2029 return -ENOBUFS;
2030 }
Johannes Berg55682962007-09-20 13:09:35 -04002031
Johannes Berg134e6372009-07-10 09:51:34 +00002032 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002033}
2034
Jouni Malinen31888482008-10-30 16:59:24 +02002035static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
2036 [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 },
2037 [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 },
2038 [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 },
2039 [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 },
2040 [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 },
2041};
2042
2043static int parse_txq_params(struct nlattr *tb[],
2044 struct ieee80211_txq_params *txq_params)
2045{
Johannes Berga3304b02012-03-28 11:04:24 +02002046 if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
Jouni Malinen31888482008-10-30 16:59:24 +02002047 !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
2048 !tb[NL80211_TXQ_ATTR_AIFS])
2049 return -EINVAL;
2050
Johannes Berga3304b02012-03-28 11:04:24 +02002051 txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
Jouni Malinen31888482008-10-30 16:59:24 +02002052 txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
2053 txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
2054 txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
2055 txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
2056
Johannes Berga3304b02012-03-28 11:04:24 +02002057 if (txq_params->ac >= NL80211_NUM_ACS)
2058 return -EINVAL;
2059
Jouni Malinen31888482008-10-30 16:59:24 +02002060 return 0;
2061}
2062
Johannes Bergf444de02010-05-05 15:25:02 +02002063static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
2064{
2065 /*
Johannes Bergcc1d2802012-05-16 23:50:20 +02002066 * You can only set the channel explicitly for WDS interfaces,
2067 * all others have their channel managed via their respective
2068 * "establish a connection" command (connect, join, ...)
2069 *
2070 * For AP/GO and mesh mode, the channel can be set with the
2071 * channel userspace API, but is only stored and passed to the
2072 * low-level driver when the AP starts or the mesh is joined.
2073 * This is for backward compatibility, userspace can also give
2074 * the channel in the start-ap or join-mesh commands instead.
Johannes Bergf444de02010-05-05 15:25:02 +02002075 *
2076 * Monitors are special as they are normally slaved to
Johannes Berge8c9bd52012-06-06 08:18:22 +02002077 * whatever else is going on, so they have their own special
2078 * operation to set the monitor channel if possible.
Johannes Bergf444de02010-05-05 15:25:02 +02002079 */
2080 return !wdev ||
2081 wdev->iftype == NL80211_IFTYPE_AP ||
Johannes Bergf444de02010-05-05 15:25:02 +02002082 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
Johannes Berg074ac8d2010-09-16 14:58:22 +02002083 wdev->iftype == NL80211_IFTYPE_MONITOR ||
2084 wdev->iftype == NL80211_IFTYPE_P2P_GO;
Johannes Bergf444de02010-05-05 15:25:02 +02002085}
2086
Johannes Berg683b6d32012-11-08 21:25:48 +01002087static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
2088 struct genl_info *info,
2089 struct cfg80211_chan_def *chandef)
2090{
Mahesh Paliveladbeca2e2012-11-29 14:11:07 +05302091 u32 control_freq;
Johannes Berg683b6d32012-11-08 21:25:48 +01002092
2093 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
2094 return -EINVAL;
2095
2096 control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
2097
2098 chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002099 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
2100 chandef->center_freq1 = control_freq;
2101 chandef->center_freq2 = 0;
Johannes Berg683b6d32012-11-08 21:25:48 +01002102
2103 /* Primary channel not allowed */
2104 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
2105 return -EINVAL;
2106
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002107 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
2108 enum nl80211_channel_type chantype;
Johannes Berg683b6d32012-11-08 21:25:48 +01002109
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002110 chantype = nla_get_u32(
2111 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
2112
2113 switch (chantype) {
2114 case NL80211_CHAN_NO_HT:
2115 case NL80211_CHAN_HT20:
2116 case NL80211_CHAN_HT40PLUS:
2117 case NL80211_CHAN_HT40MINUS:
2118 cfg80211_chandef_create(chandef, chandef->chan,
2119 chantype);
2120 break;
2121 default:
Johannes Berg683b6d32012-11-08 21:25:48 +01002122 return -EINVAL;
Johannes Berg683b6d32012-11-08 21:25:48 +01002123 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002124 } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
2125 chandef->width =
2126 nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
2127 if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
2128 chandef->center_freq1 =
2129 nla_get_u32(
2130 info->attrs[NL80211_ATTR_CENTER_FREQ1]);
2131 if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
2132 chandef->center_freq2 =
2133 nla_get_u32(
2134 info->attrs[NL80211_ATTR_CENTER_FREQ2]);
2135 }
2136
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002137 if (!cfg80211_chandef_valid(chandef))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002138 return -EINVAL;
2139
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002140 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
2141 IEEE80211_CHAN_DISABLED))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002142 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002143
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002144 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
2145 chandef->width == NL80211_CHAN_WIDTH_10) &&
2146 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
2147 return -EINVAL;
2148
Johannes Berg683b6d32012-11-08 21:25:48 +01002149 return 0;
2150}
2151
Johannes Bergf444de02010-05-05 15:25:02 +02002152static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
Jouni Malinene16821b2014-04-28 11:22:08 +03002153 struct net_device *dev,
Johannes Bergf444de02010-05-05 15:25:02 +02002154 struct genl_info *info)
2155{
Johannes Berg683b6d32012-11-08 21:25:48 +01002156 struct cfg80211_chan_def chandef;
Johannes Bergf444de02010-05-05 15:25:02 +02002157 int result;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002158 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
Jouni Malinene16821b2014-04-28 11:22:08 +03002159 struct wireless_dev *wdev = NULL;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002160
Jouni Malinene16821b2014-04-28 11:22:08 +03002161 if (dev)
2162 wdev = dev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002163 if (!nl80211_can_set_dev_channel(wdev))
2164 return -EOPNOTSUPP;
Jouni Malinene16821b2014-04-28 11:22:08 +03002165 if (wdev)
2166 iftype = wdev->iftype;
Johannes Bergf444de02010-05-05 15:25:02 +02002167
Johannes Berg683b6d32012-11-08 21:25:48 +01002168 result = nl80211_parse_chandef(rdev, info, &chandef);
2169 if (result)
2170 return result;
Johannes Bergf444de02010-05-05 15:25:02 +02002171
Johannes Berge8c9bd52012-06-06 08:18:22 +02002172 switch (iftype) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002173 case NL80211_IFTYPE_AP:
2174 case NL80211_IFTYPE_P2P_GO:
Arik Nemtsov923b3522015-07-08 15:41:44 +03002175 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
2176 iftype)) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002177 result = -EINVAL;
2178 break;
2179 }
Jouni Malinene16821b2014-04-28 11:22:08 +03002180 if (wdev->beacon_interval) {
2181 if (!dev || !rdev->ops->set_ap_chanwidth ||
2182 !(rdev->wiphy.features &
2183 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
2184 result = -EBUSY;
2185 break;
2186 }
2187
2188 /* Only allow dynamic channel width changes */
2189 if (chandef.chan != wdev->preset_chandef.chan) {
2190 result = -EBUSY;
2191 break;
2192 }
2193 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
2194 if (result)
2195 break;
2196 }
Johannes Berg683b6d32012-11-08 21:25:48 +01002197 wdev->preset_chandef = chandef;
Johannes Bergaa430da2012-05-16 23:50:18 +02002198 result = 0;
2199 break;
Johannes Bergcc1d2802012-05-16 23:50:20 +02002200 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg683b6d32012-11-08 21:25:48 +01002201 result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
Johannes Bergcc1d2802012-05-16 23:50:20 +02002202 break;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002203 case NL80211_IFTYPE_MONITOR:
Johannes Berg683b6d32012-11-08 21:25:48 +01002204 result = cfg80211_set_monitor_channel(rdev, &chandef);
Johannes Berge8c9bd52012-06-06 08:18:22 +02002205 break;
Johannes Bergaa430da2012-05-16 23:50:18 +02002206 default:
Johannes Berge8c9bd52012-06-06 08:18:22 +02002207 result = -EINVAL;
Johannes Bergf444de02010-05-05 15:25:02 +02002208 }
Johannes Bergf444de02010-05-05 15:25:02 +02002209
2210 return result;
2211}
2212
2213static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
2214{
Johannes Berg4c476992010-10-04 21:36:35 +02002215 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2216 struct net_device *netdev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02002217
Jouni Malinene16821b2014-04-28 11:22:08 +03002218 return __nl80211_set_channel(rdev, netdev, info);
Johannes Bergf444de02010-05-05 15:25:02 +02002219}
2220
Bill Jordane8347eb2010-10-01 13:54:28 -04002221static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
2222{
Johannes Berg43b19952010-10-07 13:10:30 +02002223 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2224 struct net_device *dev = info->user_ptr[1];
2225 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg388ac772010-10-07 13:11:09 +02002226 const u8 *bssid;
Bill Jordane8347eb2010-10-01 13:54:28 -04002227
2228 if (!info->attrs[NL80211_ATTR_MAC])
2229 return -EINVAL;
2230
Johannes Berg43b19952010-10-07 13:10:30 +02002231 if (netif_running(dev))
2232 return -EBUSY;
Bill Jordane8347eb2010-10-01 13:54:28 -04002233
Johannes Berg43b19952010-10-07 13:10:30 +02002234 if (!rdev->ops->set_wds_peer)
2235 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002236
Johannes Berg43b19952010-10-07 13:10:30 +02002237 if (wdev->iftype != NL80211_IFTYPE_WDS)
2238 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002239
2240 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Hila Gonene35e4d22012-06-27 17:19:42 +03002241 return rdev_set_wds_peer(rdev, dev, bssid);
Bill Jordane8347eb2010-10-01 13:54:28 -04002242}
2243
Johannes Berg55682962007-09-20 13:09:35 -04002244static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
2245{
2246 struct cfg80211_registered_device *rdev;
Johannes Bergf444de02010-05-05 15:25:02 +02002247 struct net_device *netdev = NULL;
2248 struct wireless_dev *wdev;
Bill Jordana1e567c2010-09-10 11:22:32 -04002249 int result = 0, rem_txq_params = 0;
Jouni Malinen31888482008-10-30 16:59:24 +02002250 struct nlattr *nl_txq_params;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002251 u32 changed;
2252 u8 retry_short = 0, retry_long = 0;
2253 u32 frag_threshold = 0, rts_threshold = 0;
Lukáš Turek81077e82009-12-21 22:50:47 +01002254 u8 coverage_class = 0;
Johannes Berg55682962007-09-20 13:09:35 -04002255
Johannes Berg5fe231e2013-05-08 21:45:15 +02002256 ASSERT_RTNL();
2257
Johannes Bergf444de02010-05-05 15:25:02 +02002258 /*
2259 * Try to find the wiphy and netdev. Normally this
2260 * function shouldn't need the netdev, but this is
2261 * done for backward compatibility -- previously
2262 * setting the channel was done per wiphy, but now
2263 * it is per netdev. Previous userland like hostapd
2264 * also passed a netdev to set_wiphy, so that it is
2265 * possible to let that go to the right netdev!
2266 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002267
Johannes Bergf444de02010-05-05 15:25:02 +02002268 if (info->attrs[NL80211_ATTR_IFINDEX]) {
2269 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
2270
Ying Xue7f2b8562014-01-15 10:23:45 +08002271 netdev = __dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002272 if (netdev && netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002273 rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002274 else
Johannes Bergf444de02010-05-05 15:25:02 +02002275 netdev = NULL;
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002276 }
2277
Johannes Bergf444de02010-05-05 15:25:02 +02002278 if (!netdev) {
Johannes Berg878d9ec2012-06-15 14:18:32 +02002279 rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
2280 info->attrs);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002281 if (IS_ERR(rdev))
Johannes Berg4c476992010-10-04 21:36:35 +02002282 return PTR_ERR(rdev);
Johannes Bergf444de02010-05-05 15:25:02 +02002283 wdev = NULL;
2284 netdev = NULL;
2285 result = 0;
Johannes Berg71fe96b2012-10-24 10:04:58 +02002286 } else
Johannes Bergf444de02010-05-05 15:25:02 +02002287 wdev = netdev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002288
2289 /*
2290 * end workaround code, by now the rdev is available
2291 * and locked, and wdev may or may not be NULL.
2292 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002293
2294 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
Jouni Malinen31888482008-10-30 16:59:24 +02002295 result = cfg80211_dev_rename(
2296 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002297
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002298 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002299 return result;
Johannes Berg55682962007-09-20 13:09:35 -04002300
Jouni Malinen31888482008-10-30 16:59:24 +02002301 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
2302 struct ieee80211_txq_params txq_params;
2303 struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
2304
Ying Xue7f2b8562014-01-15 10:23:45 +08002305 if (!rdev->ops->set_txq_params)
2306 return -EOPNOTSUPP;
Jouni Malinen31888482008-10-30 16:59:24 +02002307
Ying Xue7f2b8562014-01-15 10:23:45 +08002308 if (!netdev)
2309 return -EINVAL;
Eliad Pellerf70f01c2011-09-25 20:06:53 +03002310
Johannes Berg133a3ff2011-11-03 14:50:13 +01002311 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002312 netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2313 return -EINVAL;
Johannes Berg133a3ff2011-11-03 14:50:13 +01002314
Ying Xue7f2b8562014-01-15 10:23:45 +08002315 if (!netif_running(netdev))
2316 return -ENETDOWN;
Johannes Berg2b5f8b02012-04-02 10:51:55 +02002317
Jouni Malinen31888482008-10-30 16:59:24 +02002318 nla_for_each_nested(nl_txq_params,
2319 info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
2320 rem_txq_params) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02002321 result = nla_parse_nested(tb, NL80211_TXQ_ATTR_MAX,
2322 nl_txq_params,
2323 txq_params_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01002324 if (result)
2325 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002326 result = parse_txq_params(tb, &txq_params);
2327 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002328 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002329
Hila Gonene35e4d22012-06-27 17:19:42 +03002330 result = rdev_set_txq_params(rdev, netdev,
2331 &txq_params);
Jouni Malinen31888482008-10-30 16:59:24 +02002332 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002333 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002334 }
2335 }
2336
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002337 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinene16821b2014-04-28 11:22:08 +03002338 result = __nl80211_set_channel(
2339 rdev,
2340 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
2341 info);
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002342 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002343 return result;
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002344 }
2345
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002346 if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
Johannes Bergc8442112012-10-24 10:17:18 +02002347 struct wireless_dev *txp_wdev = wdev;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002348 enum nl80211_tx_power_setting type;
2349 int idx, mbm = 0;
2350
Johannes Bergc8442112012-10-24 10:17:18 +02002351 if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
2352 txp_wdev = NULL;
2353
Ying Xue7f2b8562014-01-15 10:23:45 +08002354 if (!rdev->ops->set_tx_power)
2355 return -EOPNOTSUPP;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002356
2357 idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
2358 type = nla_get_u32(info->attrs[idx]);
2359
2360 if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002361 (type != NL80211_TX_POWER_AUTOMATIC))
2362 return -EINVAL;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002363
2364 if (type != NL80211_TX_POWER_AUTOMATIC) {
2365 idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
2366 mbm = nla_get_u32(info->attrs[idx]);
2367 }
2368
Johannes Bergc8442112012-10-24 10:17:18 +02002369 result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002370 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002371 return result;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002372 }
2373
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002374 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
2375 info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
2376 u32 tx_ant, rx_ant;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07002377
Bruno Randolf7f531e02010-12-16 11:30:22 +09002378 if ((!rdev->wiphy.available_antennas_tx &&
2379 !rdev->wiphy.available_antennas_rx) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002380 !rdev->ops->set_antenna)
2381 return -EOPNOTSUPP;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002382
2383 tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
2384 rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
2385
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002386 /* reject antenna configurations which don't match the
Bruno Randolf7f531e02010-12-16 11:30:22 +09002387 * available antenna masks, except for the "all" mask */
2388 if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002389 (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
2390 return -EINVAL;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002391
Bruno Randolf7f531e02010-12-16 11:30:22 +09002392 tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
2393 rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002394
Hila Gonene35e4d22012-06-27 17:19:42 +03002395 result = rdev_set_antenna(rdev, tx_ant, rx_ant);
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002396 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002397 return result;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002398 }
2399
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002400 changed = 0;
2401
2402 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
2403 retry_short = nla_get_u8(
2404 info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002405 if (retry_short == 0)
2406 return -EINVAL;
2407
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002408 changed |= WIPHY_PARAM_RETRY_SHORT;
2409 }
2410
2411 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
2412 retry_long = nla_get_u8(
2413 info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002414 if (retry_long == 0)
2415 return -EINVAL;
2416
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002417 changed |= WIPHY_PARAM_RETRY_LONG;
2418 }
2419
2420 if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
2421 frag_threshold = nla_get_u32(
2422 info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002423 if (frag_threshold < 256)
2424 return -EINVAL;
2425
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002426 if (frag_threshold != (u32) -1) {
2427 /*
2428 * Fragments (apart from the last one) are required to
2429 * have even length. Make the fragmentation code
2430 * simpler by stripping LSB should someone try to use
2431 * odd threshold value.
2432 */
2433 frag_threshold &= ~0x1;
2434 }
2435 changed |= WIPHY_PARAM_FRAG_THRESHOLD;
2436 }
2437
2438 if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
2439 rts_threshold = nla_get_u32(
2440 info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
2441 changed |= WIPHY_PARAM_RTS_THRESHOLD;
2442 }
2443
Lukáš Turek81077e82009-12-21 22:50:47 +01002444 if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002445 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
2446 return -EINVAL;
2447
Lukáš Turek81077e82009-12-21 22:50:47 +01002448 coverage_class = nla_get_u8(
2449 info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
2450 changed |= WIPHY_PARAM_COVERAGE_CLASS;
2451 }
2452
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002453 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
2454 if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
2455 return -EOPNOTSUPP;
2456
2457 changed |= WIPHY_PARAM_DYN_ACK;
2458 }
2459
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002460 if (changed) {
2461 u8 old_retry_short, old_retry_long;
2462 u32 old_frag_threshold, old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002463 u8 old_coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002464
Ying Xue7f2b8562014-01-15 10:23:45 +08002465 if (!rdev->ops->set_wiphy_params)
2466 return -EOPNOTSUPP;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002467
2468 old_retry_short = rdev->wiphy.retry_short;
2469 old_retry_long = rdev->wiphy.retry_long;
2470 old_frag_threshold = rdev->wiphy.frag_threshold;
2471 old_rts_threshold = rdev->wiphy.rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002472 old_coverage_class = rdev->wiphy.coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002473
2474 if (changed & WIPHY_PARAM_RETRY_SHORT)
2475 rdev->wiphy.retry_short = retry_short;
2476 if (changed & WIPHY_PARAM_RETRY_LONG)
2477 rdev->wiphy.retry_long = retry_long;
2478 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
2479 rdev->wiphy.frag_threshold = frag_threshold;
2480 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
2481 rdev->wiphy.rts_threshold = rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002482 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
2483 rdev->wiphy.coverage_class = coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002484
Hila Gonene35e4d22012-06-27 17:19:42 +03002485 result = rdev_set_wiphy_params(rdev, changed);
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002486 if (result) {
2487 rdev->wiphy.retry_short = old_retry_short;
2488 rdev->wiphy.retry_long = old_retry_long;
2489 rdev->wiphy.frag_threshold = old_frag_threshold;
2490 rdev->wiphy.rts_threshold = old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002491 rdev->wiphy.coverage_class = old_coverage_class;
Michal Kazior9189ee32015-08-03 10:55:24 +02002492 return result;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002493 }
2494 }
Ying Xue7f2b8562014-01-15 10:23:45 +08002495 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002496}
2497
Johannes Berg71bbc992012-06-15 15:30:18 +02002498static inline u64 wdev_id(struct wireless_dev *wdev)
2499{
2500 return (u64)wdev->identifier |
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002501 ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
Johannes Berg71bbc992012-06-15 15:30:18 +02002502}
Johannes Berg55682962007-09-20 13:09:35 -04002503
Johannes Berg683b6d32012-11-08 21:25:48 +01002504static int nl80211_send_chandef(struct sk_buff *msg,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01002505 const struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01002506{
Johannes Berg601555c2014-11-27 17:26:56 +01002507 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
2508 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002509
Johannes Berg683b6d32012-11-08 21:25:48 +01002510 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
2511 chandef->chan->center_freq))
2512 return -ENOBUFS;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002513 switch (chandef->width) {
2514 case NL80211_CHAN_WIDTH_20_NOHT:
2515 case NL80211_CHAN_WIDTH_20:
2516 case NL80211_CHAN_WIDTH_40:
2517 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
2518 cfg80211_get_chandef_type(chandef)))
2519 return -ENOBUFS;
2520 break;
2521 default:
2522 break;
2523 }
2524 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
2525 return -ENOBUFS;
2526 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
2527 return -ENOBUFS;
2528 if (chandef->center_freq2 &&
2529 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
Johannes Berg683b6d32012-11-08 21:25:48 +01002530 return -ENOBUFS;
2531 return 0;
2532}
2533
Eric W. Biederman15e47302012-09-07 20:12:54 +00002534static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
Johannes Bergd7264052009-04-19 16:23:20 +02002535 struct cfg80211_registered_device *rdev,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002536 struct wireless_dev *wdev, bool removal)
Johannes Berg55682962007-09-20 13:09:35 -04002537{
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002538 struct net_device *dev = wdev->netdev;
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002539 u8 cmd = NL80211_CMD_NEW_INTERFACE;
Johannes Berg55682962007-09-20 13:09:35 -04002540 void *hdr;
2541
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002542 if (removal)
2543 cmd = NL80211_CMD_DEL_INTERFACE;
2544
2545 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04002546 if (!hdr)
2547 return -1;
2548
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002549 if (dev &&
2550 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002551 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002552 goto nla_put_failure;
2553
2554 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
2555 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02002556 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
2557 NL80211_ATTR_PAD) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002558 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04002559 nla_put_u32(msg, NL80211_ATTR_GENERATION,
2560 rdev->devlist_generation ^
2561 (cfg80211_rdev_list_generation << 2)))
2562 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002563
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002564 if (rdev->ops->get_channel) {
Johannes Berg683b6d32012-11-08 21:25:48 +01002565 int ret;
2566 struct cfg80211_chan_def chandef;
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002567
Johannes Berg683b6d32012-11-08 21:25:48 +01002568 ret = rdev_get_channel(rdev, wdev, &chandef);
2569 if (ret == 0) {
2570 if (nl80211_send_chandef(msg, &chandef))
2571 goto nla_put_failure;
2572 }
Pontus Fuchsd91df0e2012-04-03 16:39:58 +02002573 }
2574
Rafał Miłeckid55d0d52015-08-31 22:59:38 +02002575 if (rdev->ops->get_tx_power) {
2576 int dbm, ret;
2577
2578 ret = rdev_get_tx_power(rdev, wdev, &dbm);
2579 if (ret == 0 &&
2580 nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
2581 DBM_TO_MBM(dbm)))
2582 goto nla_put_failure;
2583 }
2584
Antonio Quartullib84e7a02012-11-07 12:52:20 +01002585 if (wdev->ssid_len) {
2586 if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
2587 goto nla_put_failure;
2588 }
2589
Johannes Berg053c0952015-01-16 22:09:00 +01002590 genlmsg_end(msg, hdr);
2591 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002592
2593 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002594 genlmsg_cancel(msg, hdr);
2595 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04002596}
2597
2598static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
2599{
2600 int wp_idx = 0;
2601 int if_idx = 0;
2602 int wp_start = cb->args[0];
2603 int if_start = cb->args[1];
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002604 int filter_wiphy = -1;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002605 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -04002606 struct wireless_dev *wdev;
2607
Johannes Berg5fe231e2013-05-08 21:45:15 +02002608 rtnl_lock();
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002609 if (!cb->args[2]) {
2610 struct nl80211_dump_wiphy_state state = {
2611 .filter_wiphy = -1,
2612 };
2613 int ret;
2614
2615 ret = nl80211_dump_wiphy_parse(skb, cb, &state);
2616 if (ret)
2617 return ret;
2618
2619 filter_wiphy = state.filter_wiphy;
2620
2621 /*
2622 * if filtering, set cb->args[2] to +1 since 0 is the default
2623 * value needed to determine that parsing is necessary.
2624 */
2625 if (filter_wiphy >= 0)
2626 cb->args[2] = filter_wiphy + 1;
2627 else
2628 cb->args[2] = -1;
2629 } else if (cb->args[2] > 0) {
2630 filter_wiphy = cb->args[2] - 1;
2631 }
2632
Johannes Bergf5ea9122009-08-07 16:17:38 +02002633 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2634 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002635 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002636 if (wp_idx < wp_start) {
2637 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002638 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002639 }
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002640
2641 if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
2642 continue;
2643
Johannes Berg55682962007-09-20 13:09:35 -04002644 if_idx = 0;
2645
Johannes Berg53873f12016-05-03 16:52:04 +03002646 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002647 if (if_idx < if_start) {
2648 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002649 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002650 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002651 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
Johannes Berg55682962007-09-20 13:09:35 -04002652 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002653 rdev, wdev, false) < 0) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002654 goto out;
2655 }
2656 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002657 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002658
2659 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002660 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002661 out:
Johannes Berg5fe231e2013-05-08 21:45:15 +02002662 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002663
2664 cb->args[0] = wp_idx;
2665 cb->args[1] = if_idx;
2666
2667 return skb->len;
2668}
2669
2670static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
2671{
2672 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002673 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002674 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002675
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07002676 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002677 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002678 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002679
Eric W. Biederman15e47302012-09-07 20:12:54 +00002680 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002681 rdev, wdev, false) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002682 nlmsg_free(msg);
2683 return -ENOBUFS;
2684 }
Johannes Berg55682962007-09-20 13:09:35 -04002685
Johannes Berg134e6372009-07-10 09:51:34 +00002686 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002687}
2688
Michael Wu66f7ac52008-01-31 19:48:22 +01002689static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
2690 [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
2691 [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
2692 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
2693 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
2694 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002695 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
Michael Wu66f7ac52008-01-31 19:48:22 +01002696};
2697
2698static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
2699{
2700 struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
2701 int flag;
2702
2703 *mntrflags = 0;
2704
2705 if (!nla)
2706 return -EINVAL;
2707
2708 if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
2709 nla, mntr_flags_policy))
2710 return -EINVAL;
2711
2712 for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
2713 if (flags[flag])
2714 *mntrflags |= (1<<flag);
2715
2716 return 0;
2717}
2718
Johannes Berg9bc383d2009-11-19 11:55:19 +01002719static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002720 struct net_device *netdev, u8 use_4addr,
2721 enum nl80211_iftype iftype)
Johannes Berg9bc383d2009-11-19 11:55:19 +01002722{
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002723 if (!use_4addr) {
Jiri Pirkof350a0a82010-06-15 06:50:45 +00002724 if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002725 return -EBUSY;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002726 return 0;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002727 }
Johannes Berg9bc383d2009-11-19 11:55:19 +01002728
2729 switch (iftype) {
2730 case NL80211_IFTYPE_AP_VLAN:
2731 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
2732 return 0;
2733 break;
2734 case NL80211_IFTYPE_STATION:
2735 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
2736 return 0;
2737 break;
2738 default:
2739 break;
2740 }
2741
2742 return -EOPNOTSUPP;
2743}
2744
Johannes Berg55682962007-09-20 13:09:35 -04002745static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
2746{
Johannes Berg4c476992010-10-04 21:36:35 +02002747 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002748 struct vif_params params;
Johannes Berge36d56b2009-06-09 21:04:43 +02002749 int err;
Johannes Berg04a773a2009-04-19 21:24:32 +02002750 enum nl80211_iftype otype, ntype;
Johannes Berg4c476992010-10-04 21:36:35 +02002751 struct net_device *dev = info->user_ptr[1];
Johannes Berg92ffe052008-09-16 20:39:36 +02002752 u32 _flags, *flags = NULL;
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002753 bool change = false;
Johannes Berg55682962007-09-20 13:09:35 -04002754
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002755 memset(&params, 0, sizeof(params));
2756
Johannes Berg04a773a2009-04-19 21:24:32 +02002757 otype = ntype = dev->ieee80211_ptr->iftype;
Johannes Berg55682962007-09-20 13:09:35 -04002758
Johannes Berg723b0382008-09-16 20:22:09 +02002759 if (info->attrs[NL80211_ATTR_IFTYPE]) {
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002760 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg04a773a2009-04-19 21:24:32 +02002761 if (otype != ntype)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002762 change = true;
Johannes Berg4c476992010-10-04 21:36:35 +02002763 if (ntype > NL80211_IFTYPE_MAX)
2764 return -EINVAL;
Johannes Berg723b0382008-09-16 20:22:09 +02002765 }
2766
Johannes Berg92ffe052008-09-16 20:39:36 +02002767 if (info->attrs[NL80211_ATTR_MESH_ID]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01002768 struct wireless_dev *wdev = dev->ieee80211_ptr;
2769
Johannes Berg4c476992010-10-04 21:36:35 +02002770 if (ntype != NL80211_IFTYPE_MESH_POINT)
2771 return -EINVAL;
Johannes Berg29cbe682010-12-03 09:20:44 +01002772 if (netif_running(dev))
2773 return -EBUSY;
2774
2775 wdev_lock(wdev);
2776 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2777 IEEE80211_MAX_MESH_ID_LEN);
2778 wdev->mesh_id_up_len =
2779 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2780 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2781 wdev->mesh_id_up_len);
2782 wdev_unlock(wdev);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002783 }
2784
Felix Fietkau8b787642009-11-10 18:53:10 +01002785 if (info->attrs[NL80211_ATTR_4ADDR]) {
2786 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
2787 change = true;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002788 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002789 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002790 return err;
Felix Fietkau8b787642009-11-10 18:53:10 +01002791 } else {
2792 params.use_4addr = -1;
2793 }
2794
Johannes Berg92ffe052008-09-16 20:39:36 +02002795 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
Johannes Berg4c476992010-10-04 21:36:35 +02002796 if (ntype != NL80211_IFTYPE_MONITOR)
2797 return -EINVAL;
Johannes Berg92ffe052008-09-16 20:39:36 +02002798 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
2799 &_flags);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002800 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002801 return err;
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002802
2803 flags = &_flags;
2804 change = true;
Johannes Berg92ffe052008-09-16 20:39:36 +02002805 }
Johannes Berg3b858752009-03-12 09:55:09 +01002806
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +03002807 if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
2808 const u8 *mumimo_groups;
2809 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2810
2811 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2812 return -EOPNOTSUPP;
2813
2814 mumimo_groups =
2815 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
2816
2817 /* bits 0 and 63 are reserved and must be zero */
2818 if ((mumimo_groups[0] & BIT(7)) ||
2819 (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
2820 return -EINVAL;
2821
2822 memcpy(params.vht_mumimo_groups, mumimo_groups,
2823 VHT_MUMIMO_GROUPS_DATA_LEN);
2824 change = true;
2825 }
2826
2827 if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
2828 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2829
2830 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2831 return -EOPNOTSUPP;
2832
2833 nla_memcpy(params.macaddr,
2834 info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR],
2835 ETH_ALEN);
2836 change = true;
2837 }
2838
Luciano Coelho18003292013-08-29 13:26:57 +03002839 if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002840 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2841 return -EOPNOTSUPP;
2842
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002843 if (change)
Johannes Berg3d54d252009-08-21 14:51:05 +02002844 err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002845 else
2846 err = 0;
Johannes Berg60719ff2008-09-16 14:55:09 +02002847
Johannes Berg9bc383d2009-11-19 11:55:19 +01002848 if (!err && params.use_4addr != -1)
2849 dev->ieee80211_ptr->use_4addr = params.use_4addr;
2850
Johannes Berg55682962007-09-20 13:09:35 -04002851 return err;
2852}
2853
2854static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2855{
Johannes Berg4c476992010-10-04 21:36:35 +02002856 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002857 struct vif_params params;
Johannes Berg84efbb82012-06-16 00:00:26 +02002858 struct wireless_dev *wdev;
Denis Kenzior896ff062016-08-03 16:58:33 -05002859 struct sk_buff *msg;
Johannes Berg55682962007-09-20 13:09:35 -04002860 int err;
2861 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
Michael Wu66f7ac52008-01-31 19:48:22 +01002862 u32 flags;
Johannes Berg55682962007-09-20 13:09:35 -04002863
Johannes Berg78f22b62014-03-24 17:57:27 +01002864 /* to avoid failing a new interface creation due to pending removal */
2865 cfg80211_destroy_ifaces(rdev);
2866
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002867 memset(&params, 0, sizeof(params));
2868
Johannes Berg55682962007-09-20 13:09:35 -04002869 if (!info->attrs[NL80211_ATTR_IFNAME])
2870 return -EINVAL;
2871
2872 if (info->attrs[NL80211_ATTR_IFTYPE]) {
2873 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
2874 if (type > NL80211_IFTYPE_MAX)
2875 return -EINVAL;
2876 }
2877
Johannes Berg79c97e92009-07-07 03:56:12 +02002878 if (!rdev->ops->add_virtual_intf ||
Johannes Berg4c476992010-10-04 21:36:35 +02002879 !(rdev->wiphy.interface_modes & (1 << type)))
2880 return -EOPNOTSUPP;
Johannes Berg55682962007-09-20 13:09:35 -04002881
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002882 if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
Ben Greeare8f479b2014-10-22 12:23:05 -07002883 rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
2884 info->attrs[NL80211_ATTR_MAC]) {
Arend van Spriel1c18f142013-01-08 10:17:27 +01002885 nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
2886 ETH_ALEN);
2887 if (!is_valid_ether_addr(params.macaddr))
2888 return -EADDRNOTAVAIL;
2889 }
2890
Johannes Berg9bc383d2009-11-19 11:55:19 +01002891 if (info->attrs[NL80211_ATTR_4ADDR]) {
Felix Fietkau8b787642009-11-10 18:53:10 +01002892 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002893 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002894 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002895 return err;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002896 }
Felix Fietkau8b787642009-11-10 18:53:10 +01002897
Michael Wu66f7ac52008-01-31 19:48:22 +01002898 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
2899 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
2900 &flags);
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002901
Luciano Coelho18003292013-08-29 13:26:57 +03002902 if (!err && (flags & MONITOR_FLAG_ACTIVE) &&
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002903 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2904 return -EOPNOTSUPP;
2905
Johannes Berga18c7192015-02-24 10:56:42 +01002906 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2907 if (!msg)
2908 return -ENOMEM;
2909
Hila Gonene35e4d22012-06-27 17:19:42 +03002910 wdev = rdev_add_virtual_intf(rdev,
2911 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
Tom Gundersen6bab2e192015-03-18 11:13:39 +01002912 NET_NAME_USER, type, err ? NULL : &flags,
2913 &params);
Rafał Miłeckid687cbb2014-11-14 18:43:28 +01002914 if (WARN_ON(!wdev)) {
2915 nlmsg_free(msg);
2916 return -EPROTO;
2917 } else if (IS_ERR(wdev)) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002918 nlmsg_free(msg);
Johannes Berg84efbb82012-06-16 00:00:26 +02002919 return PTR_ERR(wdev);
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002920 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002921
Jukka Rissanen18e5ca62014-11-13 17:25:14 +02002922 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
Johannes Berg78f22b62014-03-24 17:57:27 +01002923 wdev->owner_nlportid = info->snd_portid;
2924
Johannes Berg98104fde2012-06-16 00:19:54 +02002925 switch (type) {
2926 case NL80211_IFTYPE_MESH_POINT:
2927 if (!info->attrs[NL80211_ATTR_MESH_ID])
2928 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002929 wdev_lock(wdev);
2930 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2931 IEEE80211_MAX_MESH_ID_LEN);
2932 wdev->mesh_id_up_len =
2933 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2934 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2935 wdev->mesh_id_up_len);
2936 wdev_unlock(wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02002937 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002938 case NL80211_IFTYPE_NAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02002939 case NL80211_IFTYPE_P2P_DEVICE:
2940 /*
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002941 * P2P Device and NAN do not have a netdev, so don't go
Johannes Berg98104fde2012-06-16 00:19:54 +02002942 * through the netdev notifier and must be added here
2943 */
2944 mutex_init(&wdev->mtx);
2945 INIT_LIST_HEAD(&wdev->event_list);
2946 spin_lock_init(&wdev->event_lock);
2947 INIT_LIST_HEAD(&wdev->mgmt_registrations);
2948 spin_lock_init(&wdev->mgmt_registrations_lock);
2949
Johannes Berg98104fde2012-06-16 00:19:54 +02002950 wdev->identifier = ++rdev->wdev_id;
Johannes Berg53873f12016-05-03 16:52:04 +03002951 list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
Johannes Berg98104fde2012-06-16 00:19:54 +02002952 rdev->devlist_generation++;
Johannes Berg98104fde2012-06-16 00:19:54 +02002953 break;
2954 default:
2955 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002956 }
2957
Eric W. Biederman15e47302012-09-07 20:12:54 +00002958 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002959 rdev, wdev, false) < 0) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002960 nlmsg_free(msg);
2961 return -ENOBUFS;
2962 }
2963
Denis Kenzior896ff062016-08-03 16:58:33 -05002964 /*
2965 * For wdevs which have no associated netdev object (e.g. of type
2966 * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
2967 * For all other types, the event will be generated from the
2968 * netdev notifier
2969 */
2970 if (!wdev->netdev)
2971 nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002972
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002973 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002974}
2975
2976static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
2977{
Johannes Berg4c476992010-10-04 21:36:35 +02002978 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg84efbb82012-06-16 00:00:26 +02002979 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002980
Johannes Berg4c476992010-10-04 21:36:35 +02002981 if (!rdev->ops->del_virtual_intf)
2982 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01002983
Johannes Berg84efbb82012-06-16 00:00:26 +02002984 /*
2985 * If we remove a wireless device without a netdev then clear
2986 * user_ptr[1] so that nl80211_post_doit won't dereference it
2987 * to check if it needs to do dev_put(). Otherwise it crashes
2988 * since the wdev has been freed, unlike with a netdev where
2989 * we need the dev_put() for the netdev to really be freed.
2990 */
2991 if (!wdev->netdev)
2992 info->user_ptr[1] = NULL;
2993
Denis Kenzior7f8ed012016-08-03 16:58:35 -05002994 return rdev_del_virtual_intf(rdev, wdev);
Johannes Berg55682962007-09-20 13:09:35 -04002995}
2996
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01002997static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
2998{
2999 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3000 struct net_device *dev = info->user_ptr[1];
3001 u16 noack_map;
3002
3003 if (!info->attrs[NL80211_ATTR_NOACK_MAP])
3004 return -EINVAL;
3005
3006 if (!rdev->ops->set_noack_map)
3007 return -EOPNOTSUPP;
3008
3009 noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
3010
Hila Gonene35e4d22012-06-27 17:19:42 +03003011 return rdev_set_noack_map(rdev, dev, noack_map);
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003012}
3013
Johannes Berg41ade002007-12-19 02:03:29 +01003014struct get_key_cookie {
3015 struct sk_buff *msg;
3016 int error;
Johannes Bergb9454e82009-07-08 13:29:08 +02003017 int idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003018};
3019
3020static void get_key_callback(void *c, struct key_params *params)
3021{
Johannes Bergb9454e82009-07-08 13:29:08 +02003022 struct nlattr *key;
Johannes Berg41ade002007-12-19 02:03:29 +01003023 struct get_key_cookie *cookie = c;
3024
David S. Miller9360ffd2012-03-29 04:41:26 -04003025 if ((params->key &&
3026 nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
3027 params->key_len, params->key)) ||
3028 (params->seq &&
3029 nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
3030 params->seq_len, params->seq)) ||
3031 (params->cipher &&
3032 nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
3033 params->cipher)))
3034 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003035
Johannes Bergb9454e82009-07-08 13:29:08 +02003036 key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
3037 if (!key)
3038 goto nla_put_failure;
3039
David S. Miller9360ffd2012-03-29 04:41:26 -04003040 if ((params->key &&
3041 nla_put(cookie->msg, NL80211_KEY_DATA,
3042 params->key_len, params->key)) ||
3043 (params->seq &&
3044 nla_put(cookie->msg, NL80211_KEY_SEQ,
3045 params->seq_len, params->seq)) ||
3046 (params->cipher &&
3047 nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
3048 params->cipher)))
3049 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003050
David S. Miller9360ffd2012-03-29 04:41:26 -04003051 if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx))
3052 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003053
3054 nla_nest_end(cookie->msg, key);
3055
Johannes Berg41ade002007-12-19 02:03:29 +01003056 return;
3057 nla_put_failure:
3058 cookie->error = 1;
3059}
3060
3061static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
3062{
Johannes Berg4c476992010-10-04 21:36:35 +02003063 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003064 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003065 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003066 u8 key_idx = 0;
Johannes Berge31b8212010-10-05 19:39:30 +02003067 const u8 *mac_addr = NULL;
3068 bool pairwise;
Johannes Berg41ade002007-12-19 02:03:29 +01003069 struct get_key_cookie cookie = {
3070 .error = 0,
3071 };
3072 void *hdr;
3073 struct sk_buff *msg;
3074
3075 if (info->attrs[NL80211_ATTR_KEY_IDX])
3076 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
3077
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +02003078 if (key_idx > 5)
Johannes Berg41ade002007-12-19 02:03:29 +01003079 return -EINVAL;
3080
3081 if (info->attrs[NL80211_ATTR_MAC])
3082 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3083
Johannes Berge31b8212010-10-05 19:39:30 +02003084 pairwise = !!mac_addr;
3085 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
3086 u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003087
Johannes Berge31b8212010-10-05 19:39:30 +02003088 if (kt >= NUM_NL80211_KEYTYPES)
3089 return -EINVAL;
3090 if (kt != NL80211_KEYTYPE_GROUP &&
3091 kt != NL80211_KEYTYPE_PAIRWISE)
3092 return -EINVAL;
3093 pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
3094 }
3095
Johannes Berg4c476992010-10-04 21:36:35 +02003096 if (!rdev->ops->get_key)
3097 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003098
Johannes Berg0fa7b392015-01-23 11:10:12 +01003099 if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3100 return -ENOENT;
3101
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003102 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02003103 if (!msg)
3104 return -ENOMEM;
Johannes Berg41ade002007-12-19 02:03:29 +01003105
Eric W. Biederman15e47302012-09-07 20:12:54 +00003106 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg41ade002007-12-19 02:03:29 +01003107 NL80211_CMD_NEW_KEY);
Dan Carpentercb35fba2013-08-14 14:50:01 +03003108 if (!hdr)
Johannes Berg9fe271a2013-10-25 11:15:12 +02003109 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003110
3111 cookie.msg = msg;
Johannes Bergb9454e82009-07-08 13:29:08 +02003112 cookie.idx = key_idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003113
David S. Miller9360ffd2012-03-29 04:41:26 -04003114 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3115 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
3116 goto nla_put_failure;
3117 if (mac_addr &&
3118 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
3119 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003120
Hila Gonene35e4d22012-06-27 17:19:42 +03003121 err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
3122 get_key_callback);
Johannes Berg41ade002007-12-19 02:03:29 +01003123
3124 if (err)
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003125 goto free_msg;
Johannes Berg41ade002007-12-19 02:03:29 +01003126
3127 if (cookie.error)
3128 goto nla_put_failure;
3129
3130 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02003131 return genlmsg_reply(msg, info);
Johannes Berg41ade002007-12-19 02:03:29 +01003132
3133 nla_put_failure:
3134 err = -ENOBUFS;
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003135 free_msg:
Johannes Berg41ade002007-12-19 02:03:29 +01003136 nlmsg_free(msg);
Johannes Berg41ade002007-12-19 02:03:29 +01003137 return err;
3138}
3139
3140static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
3141{
Johannes Berg4c476992010-10-04 21:36:35 +02003142 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergb9454e82009-07-08 13:29:08 +02003143 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003144 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003145 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003146
Johannes Bergb9454e82009-07-08 13:29:08 +02003147 err = nl80211_parse_key(info, &key);
3148 if (err)
3149 return err;
3150
3151 if (key.idx < 0)
Johannes Berg41ade002007-12-19 02:03:29 +01003152 return -EINVAL;
3153
Johannes Bergb9454e82009-07-08 13:29:08 +02003154 /* only support setting default key */
3155 if (!key.def && !key.defmgmt)
Johannes Berg41ade002007-12-19 02:03:29 +01003156 return -EINVAL;
3157
Johannes Bergfffd0932009-07-08 14:22:54 +02003158 wdev_lock(dev->ieee80211_ptr);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003159
3160 if (key.def) {
3161 if (!rdev->ops->set_default_key) {
3162 err = -EOPNOTSUPP;
3163 goto out;
3164 }
3165
3166 err = nl80211_key_allowed(dev->ieee80211_ptr);
3167 if (err)
3168 goto out;
3169
Hila Gonene35e4d22012-06-27 17:19:42 +03003170 err = rdev_set_default_key(rdev, dev, key.idx,
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003171 key.def_uni, key.def_multi);
3172
3173 if (err)
3174 goto out;
Johannes Bergfffd0932009-07-08 14:22:54 +02003175
Johannes Berg3d23e342009-09-29 23:27:28 +02003176#ifdef CONFIG_CFG80211_WEXT
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003177 dev->ieee80211_ptr->wext.default_key = key.idx;
Johannes Berg08645122009-05-11 13:54:58 +02003178#endif
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003179 } else {
3180 if (key.def_uni || !key.def_multi) {
3181 err = -EINVAL;
3182 goto out;
3183 }
3184
3185 if (!rdev->ops->set_default_mgmt_key) {
3186 err = -EOPNOTSUPP;
3187 goto out;
3188 }
3189
3190 err = nl80211_key_allowed(dev->ieee80211_ptr);
3191 if (err)
3192 goto out;
3193
Hila Gonene35e4d22012-06-27 17:19:42 +03003194 err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003195 if (err)
3196 goto out;
3197
3198#ifdef CONFIG_CFG80211_WEXT
3199 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
3200#endif
3201 }
3202
3203 out:
Johannes Bergfffd0932009-07-08 14:22:54 +02003204 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003205
Johannes Berg41ade002007-12-19 02:03:29 +01003206 return err;
3207}
3208
3209static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
3210{
Johannes Berg4c476992010-10-04 21:36:35 +02003211 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfffd0932009-07-08 14:22:54 +02003212 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003213 struct net_device *dev = info->user_ptr[1];
Johannes Bergb9454e82009-07-08 13:29:08 +02003214 struct key_parse key;
Johannes Berge31b8212010-10-05 19:39:30 +02003215 const u8 *mac_addr = NULL;
Johannes Berg41ade002007-12-19 02:03:29 +01003216
Johannes Bergb9454e82009-07-08 13:29:08 +02003217 err = nl80211_parse_key(info, &key);
3218 if (err)
3219 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003220
Johannes Bergb9454e82009-07-08 13:29:08 +02003221 if (!key.p.key)
Johannes Berg41ade002007-12-19 02:03:29 +01003222 return -EINVAL;
3223
Johannes Berg41ade002007-12-19 02:03:29 +01003224 if (info->attrs[NL80211_ATTR_MAC])
3225 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3226
Johannes Berge31b8212010-10-05 19:39:30 +02003227 if (key.type == -1) {
3228 if (mac_addr)
3229 key.type = NL80211_KEYTYPE_PAIRWISE;
3230 else
3231 key.type = NL80211_KEYTYPE_GROUP;
3232 }
3233
3234 /* for now */
3235 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3236 key.type != NL80211_KEYTYPE_GROUP)
3237 return -EINVAL;
3238
Johannes Berg4c476992010-10-04 21:36:35 +02003239 if (!rdev->ops->add_key)
3240 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003241
Johannes Berge31b8212010-10-05 19:39:30 +02003242 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
3243 key.type == NL80211_KEYTYPE_PAIRWISE,
3244 mac_addr))
Johannes Berg4c476992010-10-04 21:36:35 +02003245 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02003246
3247 wdev_lock(dev->ieee80211_ptr);
3248 err = nl80211_key_allowed(dev->ieee80211_ptr);
3249 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003250 err = rdev_add_key(rdev, dev, key.idx,
3251 key.type == NL80211_KEYTYPE_PAIRWISE,
3252 mac_addr, &key.p);
Johannes Bergfffd0932009-07-08 14:22:54 +02003253 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003254
Johannes Berg41ade002007-12-19 02:03:29 +01003255 return err;
3256}
3257
3258static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
3259{
Johannes Berg4c476992010-10-04 21:36:35 +02003260 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003261 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003262 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003263 u8 *mac_addr = NULL;
Johannes Bergb9454e82009-07-08 13:29:08 +02003264 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003265
Johannes Bergb9454e82009-07-08 13:29:08 +02003266 err = nl80211_parse_key(info, &key);
3267 if (err)
3268 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003269
3270 if (info->attrs[NL80211_ATTR_MAC])
3271 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3272
Johannes Berge31b8212010-10-05 19:39:30 +02003273 if (key.type == -1) {
3274 if (mac_addr)
3275 key.type = NL80211_KEYTYPE_PAIRWISE;
3276 else
3277 key.type = NL80211_KEYTYPE_GROUP;
3278 }
3279
3280 /* for now */
3281 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3282 key.type != NL80211_KEYTYPE_GROUP)
3283 return -EINVAL;
3284
Johannes Berg4c476992010-10-04 21:36:35 +02003285 if (!rdev->ops->del_key)
3286 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003287
Johannes Bergfffd0932009-07-08 14:22:54 +02003288 wdev_lock(dev->ieee80211_ptr);
3289 err = nl80211_key_allowed(dev->ieee80211_ptr);
Johannes Berge31b8212010-10-05 19:39:30 +02003290
Johannes Berg0fa7b392015-01-23 11:10:12 +01003291 if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
Johannes Berge31b8212010-10-05 19:39:30 +02003292 !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3293 err = -ENOENT;
3294
Johannes Bergfffd0932009-07-08 14:22:54 +02003295 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003296 err = rdev_del_key(rdev, dev, key.idx,
3297 key.type == NL80211_KEYTYPE_PAIRWISE,
3298 mac_addr);
Johannes Berg41ade002007-12-19 02:03:29 +01003299
Johannes Berg3d23e342009-09-29 23:27:28 +02003300#ifdef CONFIG_CFG80211_WEXT
Johannes Berg08645122009-05-11 13:54:58 +02003301 if (!err) {
Johannes Bergb9454e82009-07-08 13:29:08 +02003302 if (key.idx == dev->ieee80211_ptr->wext.default_key)
Johannes Berg08645122009-05-11 13:54:58 +02003303 dev->ieee80211_ptr->wext.default_key = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02003304 else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
Johannes Berg08645122009-05-11 13:54:58 +02003305 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
3306 }
3307#endif
Johannes Bergfffd0932009-07-08 14:22:54 +02003308 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg08645122009-05-11 13:54:58 +02003309
Johannes Berg41ade002007-12-19 02:03:29 +01003310 return err;
3311}
3312
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05303313/* This function returns an error or the number of nested attributes */
3314static int validate_acl_mac_addrs(struct nlattr *nl_attr)
3315{
3316 struct nlattr *attr;
3317 int n_entries = 0, tmp;
3318
3319 nla_for_each_nested(attr, nl_attr, tmp) {
3320 if (nla_len(attr) != ETH_ALEN)
3321 return -EINVAL;
3322
3323 n_entries++;
3324 }
3325
3326 return n_entries;
3327}
3328
3329/*
3330 * This function parses ACL information and allocates memory for ACL data.
3331 * On successful return, the calling function is responsible to free the
3332 * ACL buffer returned by this function.
3333 */
3334static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
3335 struct genl_info *info)
3336{
3337 enum nl80211_acl_policy acl_policy;
3338 struct nlattr *attr;
3339 struct cfg80211_acl_data *acl;
3340 int i = 0, n_entries, tmp;
3341
3342 if (!wiphy->max_acl_mac_addrs)
3343 return ERR_PTR(-EOPNOTSUPP);
3344
3345 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
3346 return ERR_PTR(-EINVAL);
3347
3348 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
3349 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
3350 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
3351 return ERR_PTR(-EINVAL);
3352
3353 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
3354 return ERR_PTR(-EINVAL);
3355
3356 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
3357 if (n_entries < 0)
3358 return ERR_PTR(n_entries);
3359
3360 if (n_entries > wiphy->max_acl_mac_addrs)
3361 return ERR_PTR(-ENOTSUPP);
3362
3363 acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
3364 GFP_KERNEL);
3365 if (!acl)
3366 return ERR_PTR(-ENOMEM);
3367
3368 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
3369 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
3370 i++;
3371 }
3372
3373 acl->n_acl_entries = n_entries;
3374 acl->acl_policy = acl_policy;
3375
3376 return acl;
3377}
3378
3379static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
3380{
3381 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3382 struct net_device *dev = info->user_ptr[1];
3383 struct cfg80211_acl_data *acl;
3384 int err;
3385
3386 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3387 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3388 return -EOPNOTSUPP;
3389
3390 if (!dev->ieee80211_ptr->beacon_interval)
3391 return -EINVAL;
3392
3393 acl = parse_acl_data(&rdev->wiphy, info);
3394 if (IS_ERR(acl))
3395 return PTR_ERR(acl);
3396
3397 err = rdev_set_mac_acl(rdev, dev, acl);
3398
3399 kfree(acl);
3400
3401 return err;
3402}
3403
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303404static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
3405 u8 *rates, u8 rates_len)
3406{
3407 u8 i;
3408 u32 mask = 0;
3409
3410 for (i = 0; i < rates_len; i++) {
3411 int rate = (rates[i] & 0x7f) * 5;
3412 int ridx;
3413
3414 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
3415 struct ieee80211_rate *srate =
3416 &sband->bitrates[ridx];
3417 if (rate == srate->bitrate) {
3418 mask |= 1 << ridx;
3419 break;
3420 }
3421 }
3422 if (ridx == sband->n_bitrates)
3423 return 0; /* rate not found */
3424 }
3425
3426 return mask;
3427}
3428
3429static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
3430 u8 *rates, u8 rates_len,
3431 u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
3432{
3433 u8 i;
3434
3435 memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
3436
3437 for (i = 0; i < rates_len; i++) {
3438 int ridx, rbit;
3439
3440 ridx = rates[i] / 8;
3441 rbit = BIT(rates[i] % 8);
3442
3443 /* check validity */
3444 if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
3445 return false;
3446
3447 /* check availability */
3448 if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
3449 mcs[ridx] |= rbit;
3450 else
3451 return false;
3452 }
3453
3454 return true;
3455}
3456
3457static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
3458{
3459 u16 mcs_mask = 0;
3460
3461 switch (vht_mcs_map) {
3462 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
3463 break;
3464 case IEEE80211_VHT_MCS_SUPPORT_0_7:
3465 mcs_mask = 0x00FF;
3466 break;
3467 case IEEE80211_VHT_MCS_SUPPORT_0_8:
3468 mcs_mask = 0x01FF;
3469 break;
3470 case IEEE80211_VHT_MCS_SUPPORT_0_9:
3471 mcs_mask = 0x03FF;
3472 break;
3473 default:
3474 break;
3475 }
3476
3477 return mcs_mask;
3478}
3479
3480static void vht_build_mcs_mask(u16 vht_mcs_map,
3481 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
3482{
3483 u8 nss;
3484
3485 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
3486 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
3487 vht_mcs_map >>= 2;
3488 }
3489}
3490
3491static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
3492 struct nl80211_txrate_vht *txrate,
3493 u16 mcs[NL80211_VHT_NSS_MAX])
3494{
3495 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3496 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
3497 u8 i;
3498
3499 if (!sband->vht_cap.vht_supported)
3500 return false;
3501
3502 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
3503
3504 /* Build vht_mcs_mask from VHT capabilities */
3505 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
3506
3507 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
3508 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
3509 mcs[i] = txrate->mcs[i];
3510 else
3511 return false;
3512 }
3513
3514 return true;
3515}
3516
3517static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
3518 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
3519 .len = NL80211_MAX_SUPP_RATES },
3520 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
3521 .len = NL80211_MAX_SUPP_HT_RATES },
3522 [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
3523 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
3524};
3525
3526static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
3527 struct cfg80211_bitrate_mask *mask)
3528{
3529 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
3530 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3531 int rem, i;
3532 struct nlattr *tx_rates;
3533 struct ieee80211_supported_band *sband;
3534 u16 vht_tx_mcs_map;
3535
3536 memset(mask, 0, sizeof(*mask));
3537 /* Default to all rates enabled */
3538 for (i = 0; i < NUM_NL80211_BANDS; i++) {
3539 sband = rdev->wiphy.bands[i];
3540
3541 if (!sband)
3542 continue;
3543
3544 mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
3545 memcpy(mask->control[i].ht_mcs,
3546 sband->ht_cap.mcs.rx_mask,
3547 sizeof(mask->control[i].ht_mcs));
3548
3549 if (!sband->vht_cap.vht_supported)
3550 continue;
3551
3552 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3553 vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
3554 }
3555
3556 /* if no rates are given set it back to the defaults */
3557 if (!info->attrs[NL80211_ATTR_TX_RATES])
3558 goto out;
3559
3560 /* The nested attribute uses enum nl80211_band as the index. This maps
3561 * directly to the enum nl80211_band values used in cfg80211.
3562 */
3563 BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
3564 nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
3565 enum nl80211_band band = nla_type(tx_rates);
3566 int err;
3567
3568 if (band < 0 || band >= NUM_NL80211_BANDS)
3569 return -EINVAL;
3570 sband = rdev->wiphy.bands[band];
3571 if (sband == NULL)
3572 return -EINVAL;
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02003573 err = nla_parse_nested(tb, NL80211_TXRATE_MAX, tx_rates,
3574 nl80211_txattr_policy);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303575 if (err)
3576 return err;
3577 if (tb[NL80211_TXRATE_LEGACY]) {
3578 mask->control[band].legacy = rateset_to_mask(
3579 sband,
3580 nla_data(tb[NL80211_TXRATE_LEGACY]),
3581 nla_len(tb[NL80211_TXRATE_LEGACY]));
3582 if ((mask->control[band].legacy == 0) &&
3583 nla_len(tb[NL80211_TXRATE_LEGACY]))
3584 return -EINVAL;
3585 }
3586 if (tb[NL80211_TXRATE_HT]) {
3587 if (!ht_rateset_to_mask(
3588 sband,
3589 nla_data(tb[NL80211_TXRATE_HT]),
3590 nla_len(tb[NL80211_TXRATE_HT]),
3591 mask->control[band].ht_mcs))
3592 return -EINVAL;
3593 }
3594 if (tb[NL80211_TXRATE_VHT]) {
3595 if (!vht_set_mcs_mask(
3596 sband,
3597 nla_data(tb[NL80211_TXRATE_VHT]),
3598 mask->control[band].vht_mcs))
3599 return -EINVAL;
3600 }
3601 if (tb[NL80211_TXRATE_GI]) {
3602 mask->control[band].gi =
3603 nla_get_u8(tb[NL80211_TXRATE_GI]);
3604 if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
3605 return -EINVAL;
3606 }
3607
3608 if (mask->control[band].legacy == 0) {
3609 /* don't allow empty legacy rates if HT or VHT
3610 * are not even supported.
3611 */
3612 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
3613 rdev->wiphy.bands[band]->vht_cap.vht_supported))
3614 return -EINVAL;
3615
3616 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
3617 if (mask->control[band].ht_mcs[i])
3618 goto out;
3619
3620 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
3621 if (mask->control[band].vht_mcs[i])
3622 goto out;
3623
3624 /* legacy and mcs rates may not be both empty */
3625 return -EINVAL;
3626 }
3627 }
3628
3629out:
3630 return 0;
3631}
3632
Johannes Berg8564e382016-09-19 09:44:44 +02003633static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
3634 enum nl80211_band band,
3635 struct cfg80211_bitrate_mask *beacon_rate)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303636{
Johannes Berg8564e382016-09-19 09:44:44 +02003637 u32 count_ht, count_vht, i;
3638 u32 rate = beacon_rate->control[band].legacy;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303639
3640 /* Allow only one rate */
3641 if (hweight32(rate) > 1)
3642 return -EINVAL;
3643
3644 count_ht = 0;
3645 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003646 if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303647 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003648 } else if (beacon_rate->control[band].ht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303649 count_ht++;
3650 if (count_ht > 1)
3651 return -EINVAL;
3652 }
3653 if (count_ht && rate)
3654 return -EINVAL;
3655 }
3656
3657 count_vht = 0;
3658 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003659 if (hweight16(beacon_rate->control[band].vht_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].vht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303662 count_vht++;
3663 if (count_vht > 1)
3664 return -EINVAL;
3665 }
3666 if (count_vht && rate)
3667 return -EINVAL;
3668 }
3669
3670 if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
3671 return -EINVAL;
3672
Johannes Berg8564e382016-09-19 09:44:44 +02003673 if (rate &&
3674 !wiphy_ext_feature_isset(&rdev->wiphy,
3675 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
3676 return -EINVAL;
3677 if (count_ht &&
3678 !wiphy_ext_feature_isset(&rdev->wiphy,
3679 NL80211_EXT_FEATURE_BEACON_RATE_HT))
3680 return -EINVAL;
3681 if (count_vht &&
3682 !wiphy_ext_feature_isset(&rdev->wiphy,
3683 NL80211_EXT_FEATURE_BEACON_RATE_VHT))
3684 return -EINVAL;
3685
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303686 return 0;
3687}
3688
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003689static int nl80211_parse_beacon(struct nlattr *attrs[],
Johannes Berg88600202012-02-13 15:17:18 +01003690 struct cfg80211_beacon_data *bcn)
Johannes Berged1b6cc2007-12-19 02:03:32 +01003691{
Johannes Berg88600202012-02-13 15:17:18 +01003692 bool haveinfo = false;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003693
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003694 if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
3695 !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
3696 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
3697 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
Johannes Bergf4a11bb2009-03-27 12:40:28 +01003698 return -EINVAL;
3699
Johannes Berg88600202012-02-13 15:17:18 +01003700 memset(bcn, 0, sizeof(*bcn));
Johannes Berged1b6cc2007-12-19 02:03:32 +01003701
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003702 if (attrs[NL80211_ATTR_BEACON_HEAD]) {
3703 bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
3704 bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
Johannes Berg88600202012-02-13 15:17:18 +01003705 if (!bcn->head_len)
3706 return -EINVAL;
3707 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003708 }
3709
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003710 if (attrs[NL80211_ATTR_BEACON_TAIL]) {
3711 bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
3712 bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
Johannes Berg88600202012-02-13 15:17:18 +01003713 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003714 }
3715
Johannes Berg4c476992010-10-04 21:36:35 +02003716 if (!haveinfo)
3717 return -EINVAL;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003718
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003719 if (attrs[NL80211_ATTR_IE]) {
3720 bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
3721 bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003722 }
3723
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003724 if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003725 bcn->proberesp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003726 nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003727 bcn->proberesp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003728 nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003729 }
3730
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003731 if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003732 bcn->assocresp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003733 nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003734 bcn->assocresp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003735 nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003736 }
3737
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003738 if (attrs[NL80211_ATTR_PROBE_RESP]) {
3739 bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
3740 bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
Arik Nemtsov00f740e2011-11-10 11:28:56 +02003741 }
3742
Johannes Berg88600202012-02-13 15:17:18 +01003743 return 0;
3744}
3745
Johannes Berg66cd7942017-02-07 22:40:44 +02003746static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
3747 const u8 *rates)
3748{
3749 int i;
3750
3751 if (!rates)
3752 return;
3753
3754 for (i = 0; i < rates[1]; i++) {
3755 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
3756 params->ht_required = true;
3757 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
3758 params->vht_required = true;
3759 }
3760}
3761
3762/*
3763 * Since the nl80211 API didn't include, from the beginning, attributes about
3764 * HT/VHT requirements/capabilities, we parse them out of the IEs for the
3765 * benefit of drivers that rebuild IEs in the firmware.
3766 */
3767static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
3768{
3769 const struct cfg80211_beacon_data *bcn = &params->beacon;
3770 size_t ies_len = bcn->beacon_ies_len;
3771 const u8 *ies = bcn->beacon_ies;
3772 const u8 *rates;
3773 const u8 *cap;
3774
3775 rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
3776 nl80211_check_ap_rate_selectors(params, rates);
3777
3778 rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
3779 nl80211_check_ap_rate_selectors(params, rates);
3780
3781 cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
3782 if (cap && cap[1] >= sizeof(*params->ht_cap))
3783 params->ht_cap = (void *)(cap + 2);
3784 cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
3785 if (cap && cap[1] >= sizeof(*params->vht_cap))
3786 params->vht_cap = (void *)(cap + 2);
3787}
3788
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003789static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
3790 struct cfg80211_ap_settings *params)
3791{
3792 struct wireless_dev *wdev;
3793 bool ret = false;
3794
Johannes Berg53873f12016-05-03 16:52:04 +03003795 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003796 if (wdev->iftype != NL80211_IFTYPE_AP &&
3797 wdev->iftype != NL80211_IFTYPE_P2P_GO)
3798 continue;
3799
Johannes Berg683b6d32012-11-08 21:25:48 +01003800 if (!wdev->preset_chandef.chan)
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003801 continue;
3802
Johannes Berg683b6d32012-11-08 21:25:48 +01003803 params->chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003804 ret = true;
3805 break;
3806 }
3807
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003808 return ret;
3809}
3810
Jouni Malinene39e5b52012-09-30 19:29:39 +03003811static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
3812 enum nl80211_auth_type auth_type,
3813 enum nl80211_commands cmd)
3814{
3815 if (auth_type > NL80211_AUTHTYPE_MAX)
3816 return false;
3817
3818 switch (cmd) {
3819 case NL80211_CMD_AUTHENTICATE:
3820 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
3821 auth_type == NL80211_AUTHTYPE_SAE)
3822 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003823 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3824 NL80211_EXT_FEATURE_FILS_STA) &&
3825 (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3826 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3827 auth_type == NL80211_AUTHTYPE_FILS_PK))
3828 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003829 return true;
3830 case NL80211_CMD_CONNECT:
3831 case NL80211_CMD_START_AP:
3832 /* SAE not supported yet */
3833 if (auth_type == NL80211_AUTHTYPE_SAE)
3834 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003835 /* FILS not supported yet */
3836 if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3837 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3838 auth_type == NL80211_AUTHTYPE_FILS_PK)
3839 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003840 return true;
3841 default:
3842 return false;
3843 }
3844}
3845
Johannes Berg88600202012-02-13 15:17:18 +01003846static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
3847{
3848 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3849 struct net_device *dev = info->user_ptr[1];
3850 struct wireless_dev *wdev = dev->ieee80211_ptr;
3851 struct cfg80211_ap_settings params;
3852 int err;
3853
3854 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3855 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3856 return -EOPNOTSUPP;
3857
3858 if (!rdev->ops->start_ap)
3859 return -EOPNOTSUPP;
3860
3861 if (wdev->beacon_interval)
3862 return -EALREADY;
3863
3864 memset(&params, 0, sizeof(params));
3865
3866 /* these are required for START_AP */
3867 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
3868 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
3869 !info->attrs[NL80211_ATTR_BEACON_HEAD])
3870 return -EINVAL;
3871
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003872 err = nl80211_parse_beacon(info->attrs, &params.beacon);
Johannes Berg88600202012-02-13 15:17:18 +01003873 if (err)
3874 return err;
3875
3876 params.beacon_interval =
3877 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
3878 params.dtim_period =
3879 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
3880
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05303881 err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
3882 params.beacon_interval);
Johannes Berg88600202012-02-13 15:17:18 +01003883 if (err)
3884 return err;
3885
3886 /*
3887 * In theory, some of these attributes should be required here
3888 * but since they were not used when the command was originally
3889 * added, keep them optional for old user space programs to let
3890 * them continue to work with drivers that do not need the
3891 * additional information -- drivers must check!
3892 */
3893 if (info->attrs[NL80211_ATTR_SSID]) {
3894 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3895 params.ssid_len =
3896 nla_len(info->attrs[NL80211_ATTR_SSID]);
3897 if (params.ssid_len == 0 ||
3898 params.ssid_len > IEEE80211_MAX_SSID_LEN)
3899 return -EINVAL;
3900 }
3901
3902 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
3903 params.hidden_ssid = nla_get_u32(
3904 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
3905 if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
3906 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
3907 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
3908 return -EINVAL;
3909 }
3910
3911 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
3912
3913 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
3914 params.auth_type = nla_get_u32(
3915 info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03003916 if (!nl80211_valid_auth_type(rdev, params.auth_type,
3917 NL80211_CMD_START_AP))
Johannes Berg88600202012-02-13 15:17:18 +01003918 return -EINVAL;
3919 } else
3920 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
3921
3922 err = nl80211_crypto_settings(rdev, info, &params.crypto,
3923 NL80211_MAX_NR_CIPHER_SUITES);
3924 if (err)
3925 return err;
3926
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05303927 if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
3928 if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
3929 return -EOPNOTSUPP;
3930 params.inactivity_timeout = nla_get_u16(
3931 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
3932 }
3933
Johannes Berg53cabad2012-11-14 15:17:28 +01003934 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
3935 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3936 return -EINVAL;
3937 params.p2p_ctwindow =
3938 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
3939 if (params.p2p_ctwindow > 127)
3940 return -EINVAL;
3941 if (params.p2p_ctwindow != 0 &&
3942 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
3943 return -EINVAL;
3944 }
3945
3946 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
3947 u8 tmp;
3948
3949 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3950 return -EINVAL;
3951 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
3952 if (tmp > 1)
3953 return -EINVAL;
3954 params.p2p_opp_ps = tmp;
3955 if (params.p2p_opp_ps != 0 &&
3956 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
3957 return -EINVAL;
3958 }
3959
Johannes Bergaa430da2012-05-16 23:50:18 +02003960 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01003961 err = nl80211_parse_chandef(rdev, info, &params.chandef);
3962 if (err)
3963 return err;
3964 } else if (wdev->preset_chandef.chan) {
3965 params.chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003966 } else if (!nl80211_get_ap_channel(rdev, &params))
Johannes Bergaa430da2012-05-16 23:50:18 +02003967 return -EINVAL;
3968
Arik Nemtsov923b3522015-07-08 15:41:44 +03003969 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
3970 wdev->iftype))
Johannes Bergaa430da2012-05-16 23:50:18 +02003971 return -EINVAL;
3972
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303973 if (info->attrs[NL80211_ATTR_TX_RATES]) {
3974 err = nl80211_parse_tx_bitrate_mask(info, &params.beacon_rate);
3975 if (err)
3976 return err;
3977
Johannes Berg8564e382016-09-19 09:44:44 +02003978 err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
3979 &params.beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303980 if (err)
3981 return err;
3982 }
3983
Eliad Peller18998c32014-09-10 14:07:34 +03003984 if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
3985 params.smps_mode =
3986 nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
3987 switch (params.smps_mode) {
3988 case NL80211_SMPS_OFF:
3989 break;
3990 case NL80211_SMPS_STATIC:
3991 if (!(rdev->wiphy.features &
3992 NL80211_FEATURE_STATIC_SMPS))
3993 return -EINVAL;
3994 break;
3995 case NL80211_SMPS_DYNAMIC:
3996 if (!(rdev->wiphy.features &
3997 NL80211_FEATURE_DYNAMIC_SMPS))
3998 return -EINVAL;
3999 break;
4000 default:
4001 return -EINVAL;
4002 }
4003 } else {
4004 params.smps_mode = NL80211_SMPS_OFF;
4005 }
4006
Purushottam Kushwaha6e8ef842016-07-05 13:44:51 +05304007 params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
4008 if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
4009 return -EOPNOTSUPP;
4010
Ola Olsson4baf6be2015-10-29 07:04:58 +01004011 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
4012 params.acl = parse_acl_data(&rdev->wiphy, info);
4013 if (IS_ERR(params.acl))
4014 return PTR_ERR(params.acl);
4015 }
4016
Johannes Berg66cd7942017-02-07 22:40:44 +02004017 nl80211_calculate_ap_params(&params);
4018
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004019 wdev_lock(wdev);
Hila Gonene35e4d22012-06-27 17:19:42 +03004020 err = rdev_start_ap(rdev, dev, &params);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004021 if (!err) {
Johannes Berg683b6d32012-11-08 21:25:48 +01004022 wdev->preset_chandef = params.chandef;
Johannes Berg88600202012-02-13 15:17:18 +01004023 wdev->beacon_interval = params.beacon_interval;
Michal Kazior9e0e2962014-01-29 14:22:27 +01004024 wdev->chandef = params.chandef;
Antonio Quartulli06e191e2012-11-07 12:52:19 +01004025 wdev->ssid_len = params.ssid_len;
4026 memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004027 }
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004028 wdev_unlock(wdev);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304029
4030 kfree(params.acl);
4031
Johannes Berg56d18932011-05-09 18:41:15 +02004032 return err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004033}
4034
Johannes Berg88600202012-02-13 15:17:18 +01004035static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
4036{
4037 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4038 struct net_device *dev = info->user_ptr[1];
4039 struct wireless_dev *wdev = dev->ieee80211_ptr;
4040 struct cfg80211_beacon_data params;
4041 int err;
4042
4043 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4044 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4045 return -EOPNOTSUPP;
4046
4047 if (!rdev->ops->change_beacon)
4048 return -EOPNOTSUPP;
4049
4050 if (!wdev->beacon_interval)
4051 return -EINVAL;
4052
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004053 err = nl80211_parse_beacon(info->attrs, &params);
Johannes Berg88600202012-02-13 15:17:18 +01004054 if (err)
4055 return err;
4056
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004057 wdev_lock(wdev);
4058 err = rdev_change_beacon(rdev, dev, &params);
4059 wdev_unlock(wdev);
4060
4061 return err;
Johannes Berg88600202012-02-13 15:17:18 +01004062}
4063
4064static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
Johannes Berged1b6cc2007-12-19 02:03:32 +01004065{
Johannes Berg4c476992010-10-04 21:36:35 +02004066 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4067 struct net_device *dev = info->user_ptr[1];
Johannes Berged1b6cc2007-12-19 02:03:32 +01004068
Ilan Peer7c8d5e02014-02-25 15:33:38 +02004069 return cfg80211_stop_ap(rdev, dev, false);
Johannes Berged1b6cc2007-12-19 02:03:32 +01004070}
4071
Johannes Berg5727ef12007-12-19 02:03:34 +01004072static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
4073 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
4074 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
4075 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
Jouni Malinen0e467242009-05-11 21:57:55 +03004076 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
Javier Cardonab39c48f2011-04-07 15:08:30 -07004077 [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
Johannes Bergd83023d2011-12-14 09:29:15 +01004078 [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
Johannes Berg5727ef12007-12-19 02:03:34 +01004079};
4080
Johannes Bergeccb8e82009-05-11 21:57:56 +03004081static int parse_station_flags(struct genl_info *info,
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004082 enum nl80211_iftype iftype,
Johannes Bergeccb8e82009-05-11 21:57:56 +03004083 struct station_parameters *params)
Johannes Berg5727ef12007-12-19 02:03:34 +01004084{
4085 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
Johannes Bergeccb8e82009-05-11 21:57:56 +03004086 struct nlattr *nla;
Johannes Berg5727ef12007-12-19 02:03:34 +01004087 int flag;
4088
Johannes Bergeccb8e82009-05-11 21:57:56 +03004089 /*
4090 * Try parsing the new attribute first so userspace
4091 * can specify both for older kernels.
4092 */
4093 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
4094 if (nla) {
4095 struct nl80211_sta_flag_update *sta_flags;
Johannes Berg5727ef12007-12-19 02:03:34 +01004096
Johannes Bergeccb8e82009-05-11 21:57:56 +03004097 sta_flags = nla_data(nla);
4098 params->sta_flags_mask = sta_flags->mask;
4099 params->sta_flags_set = sta_flags->set;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004100 params->sta_flags_set &= params->sta_flags_mask;
Johannes Bergeccb8e82009-05-11 21:57:56 +03004101 if ((params->sta_flags_mask |
4102 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
4103 return -EINVAL;
4104 return 0;
4105 }
4106
4107 /* if present, parse the old attribute */
4108
4109 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
Johannes Berg5727ef12007-12-19 02:03:34 +01004110 if (!nla)
4111 return 0;
4112
4113 if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
4114 nla, sta_flags_policy))
4115 return -EINVAL;
4116
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004117 /*
4118 * Only allow certain flags for interface types so that
4119 * other attributes are silently ignored. Remember that
4120 * this is backward compatibility code with old userspace
4121 * and shouldn't be hit in other cases anyway.
4122 */
4123 switch (iftype) {
4124 case NL80211_IFTYPE_AP:
4125 case NL80211_IFTYPE_AP_VLAN:
4126 case NL80211_IFTYPE_P2P_GO:
4127 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4128 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4129 BIT(NL80211_STA_FLAG_WME) |
4130 BIT(NL80211_STA_FLAG_MFP);
4131 break;
4132 case NL80211_IFTYPE_P2P_CLIENT:
4133 case NL80211_IFTYPE_STATION:
4134 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4135 BIT(NL80211_STA_FLAG_TDLS_PEER);
4136 break;
4137 case NL80211_IFTYPE_MESH_POINT:
4138 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4139 BIT(NL80211_STA_FLAG_MFP) |
4140 BIT(NL80211_STA_FLAG_AUTHORIZED);
4141 default:
4142 return -EINVAL;
4143 }
Johannes Berg5727ef12007-12-19 02:03:34 +01004144
Johannes Berg3383b5a2012-05-10 20:14:43 +02004145 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
4146 if (flags[flag]) {
Johannes Bergeccb8e82009-05-11 21:57:56 +03004147 params->sta_flags_set |= (1<<flag);
Johannes Berg5727ef12007-12-19 02:03:34 +01004148
Johannes Berg3383b5a2012-05-10 20:14:43 +02004149 /* no longer support new API additions in old API */
4150 if (flag > NL80211_STA_FLAG_MAX_OLD_API)
4151 return -EINVAL;
4152 }
4153 }
4154
Johannes Berg5727ef12007-12-19 02:03:34 +01004155 return 0;
4156}
4157
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004158static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
4159 int attr)
4160{
4161 struct nlattr *rate;
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004162 u32 bitrate;
4163 u16 bitrate_compat;
Johannes Bergb51f3be2015-01-15 16:14:02 +01004164 enum nl80211_attrs rate_flg;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004165
4166 rate = nla_nest_start(msg, attr);
4167 if (!rate)
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004168 return false;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004169
4170 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
4171 bitrate = cfg80211_calculate_bitrate(info);
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004172 /* report 16-bit bitrate only if we can */
4173 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004174 if (bitrate > 0 &&
4175 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
4176 return false;
4177 if (bitrate_compat > 0 &&
4178 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
4179 return false;
4180
Johannes Bergb51f3be2015-01-15 16:14:02 +01004181 switch (info->bw) {
4182 case RATE_INFO_BW_5:
4183 rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
4184 break;
4185 case RATE_INFO_BW_10:
4186 rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
4187 break;
4188 default:
4189 WARN_ON(1);
4190 /* fall through */
4191 case RATE_INFO_BW_20:
4192 rate_flg = 0;
4193 break;
4194 case RATE_INFO_BW_40:
4195 rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
4196 break;
4197 case RATE_INFO_BW_80:
4198 rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
4199 break;
4200 case RATE_INFO_BW_160:
4201 rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
4202 break;
4203 }
4204
4205 if (rate_flg && nla_put_flag(msg, rate_flg))
4206 return false;
4207
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004208 if (info->flags & RATE_INFO_FLAGS_MCS) {
4209 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
4210 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004211 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4212 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4213 return false;
4214 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
4215 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
4216 return false;
4217 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
4218 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004219 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4220 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4221 return false;
4222 }
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004223
4224 nla_nest_end(msg, rate);
4225 return true;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004226}
4227
Felix Fietkau119363c2013-04-22 16:29:30 +02004228static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
4229 int id)
4230{
4231 void *attr;
4232 int i = 0;
4233
4234 if (!mask)
4235 return true;
4236
4237 attr = nla_nest_start(msg, id);
4238 if (!attr)
4239 return false;
4240
4241 for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
4242 if (!(mask & BIT(i)))
4243 continue;
4244
4245 if (nla_put_u8(msg, i, signal[i]))
4246 return false;
4247 }
4248
4249 nla_nest_end(msg, attr);
4250
4251 return true;
4252}
4253
Johannes Bergcf5ead82014-11-14 17:14:00 +01004254static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
4255 u32 seq, int flags,
John W. Linville66266b32012-03-15 13:25:41 -04004256 struct cfg80211_registered_device *rdev,
4257 struct net_device *dev,
Johannes Berg98b62182009-12-23 13:15:44 +01004258 const u8 *mac_addr, struct station_info *sinfo)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004259{
4260 void *hdr;
Paul Stewartf4263c92011-03-31 09:25:41 -07004261 struct nlattr *sinfoattr, *bss_param;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004262
Johannes Bergcf5ead82014-11-14 17:14:00 +01004263 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004264 if (!hdr)
4265 return -1;
4266
David S. Miller9360ffd2012-03-29 04:41:26 -04004267 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
4268 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
4269 nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
4270 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02004271
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004272 sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
4273 if (!sinfoattr)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004274 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004275
4276#define PUT_SINFO(attr, memb, type) do { \
Johannes Bergd686b922016-04-26 09:54:11 +02004277 BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
Mohammed Shafi Shajakhan739960f2016-04-07 19:59:34 +05304278 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
Johannes Berg319090b2014-11-17 14:08:11 +01004279 nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
4280 sinfo->memb)) \
4281 goto nla_put_failure; \
4282 } while (0)
Johannes Bergd686b922016-04-26 09:54:11 +02004283#define PUT_SINFO_U64(attr, memb) do { \
4284 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
4285 nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
4286 sinfo->memb, NL80211_STA_INFO_PAD)) \
4287 goto nla_put_failure; \
4288 } while (0)
Johannes Berg319090b2014-11-17 14:08:11 +01004289
4290 PUT_SINFO(CONNECTED_TIME, connected_time, u32);
4291 PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
4292
4293 if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
4294 BIT(NL80211_STA_INFO_RX_BYTES64)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004295 nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004296 (u32)sinfo->rx_bytes))
4297 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004298
4299 if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
4300 BIT(NL80211_STA_INFO_TX_BYTES64)) &&
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004301 nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
4302 (u32)sinfo->tx_bytes))
4303 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004304
Johannes Bergd686b922016-04-26 09:54:11 +02004305 PUT_SINFO_U64(RX_BYTES64, rx_bytes);
4306 PUT_SINFO_U64(TX_BYTES64, tx_bytes);
Johannes Berg319090b2014-11-17 14:08:11 +01004307 PUT_SINFO(LLID, llid, u16);
4308 PUT_SINFO(PLID, plid, u16);
4309 PUT_SINFO(PLINK_STATE, plink_state, u8);
Johannes Bergd686b922016-04-26 09:54:11 +02004310 PUT_SINFO_U64(RX_DURATION, rx_duration);
Johannes Berg319090b2014-11-17 14:08:11 +01004311
John W. Linville66266b32012-03-15 13:25:41 -04004312 switch (rdev->wiphy.signal_type) {
4313 case CFG80211_SIGNAL_TYPE_MBM:
Johannes Berg319090b2014-11-17 14:08:11 +01004314 PUT_SINFO(SIGNAL, signal, u8);
4315 PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
John W. Linville66266b32012-03-15 13:25:41 -04004316 break;
4317 default:
4318 break;
4319 }
Johannes Berg319090b2014-11-17 14:08:11 +01004320 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004321 if (!nl80211_put_signal(msg, sinfo->chains,
4322 sinfo->chain_signal,
4323 NL80211_STA_INFO_CHAIN_SIGNAL))
4324 goto nla_put_failure;
4325 }
Johannes Berg319090b2014-11-17 14:08:11 +01004326 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004327 if (!nl80211_put_signal(msg, sinfo->chains,
4328 sinfo->chain_signal_avg,
4329 NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
4330 goto nla_put_failure;
4331 }
Johannes Berg319090b2014-11-17 14:08:11 +01004332 if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004333 if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
4334 NL80211_STA_INFO_TX_BITRATE))
Henning Rogge420e7fa2008-12-11 22:04:19 +01004335 goto nla_put_failure;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004336 }
Johannes Berg319090b2014-11-17 14:08:11 +01004337 if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004338 if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
4339 NL80211_STA_INFO_RX_BITRATE))
4340 goto nla_put_failure;
Henning Rogge420e7fa2008-12-11 22:04:19 +01004341 }
Johannes Berg319090b2014-11-17 14:08:11 +01004342
4343 PUT_SINFO(RX_PACKETS, rx_packets, u32);
4344 PUT_SINFO(TX_PACKETS, tx_packets, u32);
4345 PUT_SINFO(TX_RETRIES, tx_retries, u32);
4346 PUT_SINFO(TX_FAILED, tx_failed, u32);
4347 PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
4348 PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
4349 PUT_SINFO(LOCAL_PM, local_pm, u32);
4350 PUT_SINFO(PEER_PM, peer_pm, u32);
4351 PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
4352
4353 if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
Paul Stewartf4263c92011-03-31 09:25:41 -07004354 bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
4355 if (!bss_param)
4356 goto nla_put_failure;
4357
David S. Miller9360ffd2012-03-29 04:41:26 -04004358 if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
4359 nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
4360 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
4361 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
4362 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
4363 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
4364 nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
4365 sinfo->bss_param.dtim_period) ||
4366 nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
4367 sinfo->bss_param.beacon_interval))
4368 goto nla_put_failure;
Paul Stewartf4263c92011-03-31 09:25:41 -07004369
4370 nla_nest_end(msg, bss_param);
4371 }
Johannes Berg319090b2014-11-17 14:08:11 +01004372 if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004373 nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
4374 sizeof(struct nl80211_sta_flag_update),
4375 &sinfo->sta_flags))
4376 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004377
Johannes Bergd686b922016-04-26 09:54:11 +02004378 PUT_SINFO_U64(T_OFFSET, t_offset);
4379 PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
4380 PUT_SINFO_U64(BEACON_RX, rx_beacon);
Johannes Berga76b1942014-11-17 14:12:22 +01004381 PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
Johannes Berg319090b2014-11-17 14:08:11 +01004382
4383#undef PUT_SINFO
Johannes Bergd686b922016-04-26 09:54:11 +02004384#undef PUT_SINFO_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004385
4386 if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
4387 struct nlattr *tidsattr;
4388 int tid;
4389
4390 tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS);
4391 if (!tidsattr)
4392 goto nla_put_failure;
4393
4394 for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
4395 struct cfg80211_tid_stats *tidstats;
4396 struct nlattr *tidattr;
4397
4398 tidstats = &sinfo->pertid[tid];
4399
4400 if (!tidstats->filled)
4401 continue;
4402
4403 tidattr = nla_nest_start(msg, tid + 1);
4404 if (!tidattr)
4405 goto nla_put_failure;
4406
Johannes Bergd686b922016-04-26 09:54:11 +02004407#define PUT_TIDVAL_U64(attr, memb) do { \
Johannes Berg6de39802014-12-19 12:34:00 +01004408 if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02004409 nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
4410 tidstats->memb, NL80211_TID_STATS_PAD)) \
Johannes Berg6de39802014-12-19 12:34:00 +01004411 goto nla_put_failure; \
4412 } while (0)
4413
Johannes Bergd686b922016-04-26 09:54:11 +02004414 PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
4415 PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
4416 PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
4417 PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
Johannes Berg6de39802014-12-19 12:34:00 +01004418
Johannes Bergd686b922016-04-26 09:54:11 +02004419#undef PUT_TIDVAL_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004420 nla_nest_end(msg, tidattr);
4421 }
4422
4423 nla_nest_end(msg, tidsattr);
4424 }
4425
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004426 nla_nest_end(msg, sinfoattr);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004427
Johannes Berg319090b2014-11-17 14:08:11 +01004428 if (sinfo->assoc_req_ies_len &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004429 nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
4430 sinfo->assoc_req_ies))
4431 goto nla_put_failure;
Jouni Malinen50d3dfb2011-08-08 12:11:52 +03004432
Johannes Berg053c0952015-01-16 22:09:00 +01004433 genlmsg_end(msg, hdr);
4434 return 0;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004435
4436 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07004437 genlmsg_cancel(msg, hdr);
4438 return -EMSGSIZE;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004439}
4440
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004441static int nl80211_dump_station(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004442 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004443{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004444 struct station_info sinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004445 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02004446 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004447 u8 mac_addr[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02004448 int sta_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004449 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004450
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004451 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02004452 if (err)
4453 return err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004454
Johannes Berg97990a02013-04-19 01:02:55 +02004455 if (!wdev->netdev) {
4456 err = -EINVAL;
4457 goto out_err;
4458 }
4459
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004460 if (!rdev->ops->dump_station) {
Jouni Malineneec60b02009-03-20 21:21:19 +02004461 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004462 goto out_err;
4463 }
4464
Johannes Bergbba95fe2008-07-29 13:22:51 +02004465 while (1) {
Jouni Malinenf612ced2011-08-11 11:46:22 +03004466 memset(&sinfo, 0, sizeof(sinfo));
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004467 err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
Hila Gonene35e4d22012-06-27 17:19:42 +03004468 mac_addr, &sinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004469 if (err == -ENOENT)
4470 break;
4471 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01004472 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004473
Johannes Bergcf5ead82014-11-14 17:14:00 +01004474 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004475 NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004476 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004477 rdev, wdev->netdev, mac_addr,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004478 &sinfo) < 0)
4479 goto out;
4480
4481 sta_idx++;
4482 }
4483
Johannes Bergbba95fe2008-07-29 13:22:51 +02004484 out:
Johannes Berg97990a02013-04-19 01:02:55 +02004485 cb->args[2] = sta_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004486 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004487 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004488 nl80211_finish_wdev_dump(rdev);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004489
4490 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004491}
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004492
Johannes Berg5727ef12007-12-19 02:03:34 +01004493static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
4494{
Johannes Berg4c476992010-10-04 21:36:35 +02004495 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4496 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004497 struct station_info sinfo;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004498 struct sk_buff *msg;
4499 u8 *mac_addr = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02004500 int err;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004501
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004502 memset(&sinfo, 0, sizeof(sinfo));
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004503
4504 if (!info->attrs[NL80211_ATTR_MAC])
4505 return -EINVAL;
4506
4507 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4508
Johannes Berg4c476992010-10-04 21:36:35 +02004509 if (!rdev->ops->get_station)
4510 return -EOPNOTSUPP;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004511
Hila Gonene35e4d22012-06-27 17:19:42 +03004512 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004513 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02004514 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004515
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07004516 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004517 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02004518 return -ENOMEM;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004519
Johannes Bergcf5ead82014-11-14 17:14:00 +01004520 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
4521 info->snd_portid, info->snd_seq, 0,
John W. Linville66266b32012-03-15 13:25:41 -04004522 rdev, dev, mac_addr, &sinfo) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02004523 nlmsg_free(msg);
4524 return -ENOBUFS;
4525 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004526
Johannes Berg4c476992010-10-04 21:36:35 +02004527 return genlmsg_reply(msg, info);
Johannes Berg5727ef12007-12-19 02:03:34 +01004528}
4529
Johannes Berg77ee7c82013-02-15 00:48:33 +01004530int cfg80211_check_station_change(struct wiphy *wiphy,
4531 struct station_parameters *params,
4532 enum cfg80211_station_type statype)
4533{
Ayala Bekere4208422015-10-23 11:20:06 +03004534 if (params->listen_interval != -1 &&
4535 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004536 return -EINVAL;
Ayala Bekere4208422015-10-23 11:20:06 +03004537
Ayala Beker17b94242016-03-17 15:41:38 +02004538 if (params->support_p2p_ps != -1 &&
4539 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
4540 return -EINVAL;
4541
Arik Nemtsovc72e1142014-07-17 17:14:29 +03004542 if (params->aid &&
Ayala Bekere4208422015-10-23 11:20:06 +03004543 !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
4544 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004545 return -EINVAL;
4546
4547 /* When you run into this, adjust the code below for the new flag */
4548 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
4549
4550 switch (statype) {
Thomas Pederseneef941e2013-03-04 13:06:11 -08004551 case CFG80211_STA_MESH_PEER_KERNEL:
4552 case CFG80211_STA_MESH_PEER_USER:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004553 /*
4554 * No ignoring the TDLS flag here -- the userspace mesh
4555 * code doesn't have the bug of including TDLS in the
4556 * mask everywhere.
4557 */
4558 if (params->sta_flags_mask &
4559 ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4560 BIT(NL80211_STA_FLAG_MFP) |
4561 BIT(NL80211_STA_FLAG_AUTHORIZED)))
4562 return -EINVAL;
4563 break;
4564 case CFG80211_STA_TDLS_PEER_SETUP:
4565 case CFG80211_STA_TDLS_PEER_ACTIVE:
4566 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
4567 return -EINVAL;
4568 /* ignore since it can't change */
4569 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4570 break;
4571 default:
4572 /* disallow mesh-specific things */
4573 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
4574 return -EINVAL;
4575 if (params->local_pm)
4576 return -EINVAL;
4577 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4578 return -EINVAL;
4579 }
4580
4581 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4582 statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
4583 /* TDLS can't be set, ... */
4584 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
4585 return -EINVAL;
4586 /*
4587 * ... but don't bother the driver with it. This works around
4588 * a hostapd/wpa_supplicant issue -- it always includes the
4589 * TLDS_PEER flag in the mask even for AP mode.
4590 */
4591 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4592 }
4593
Ayala Beker47edb112015-09-21 15:49:53 +03004594 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4595 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004596 /* reject other things that can't change */
4597 if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
4598 return -EINVAL;
4599 if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
4600 return -EINVAL;
4601 if (params->supported_rates)
4602 return -EINVAL;
4603 if (params->ext_capab || params->ht_capa || params->vht_capa)
4604 return -EINVAL;
4605 }
4606
Ayala Beker47edb112015-09-21 15:49:53 +03004607 if (statype != CFG80211_STA_AP_CLIENT &&
4608 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004609 if (params->vlan)
4610 return -EINVAL;
4611 }
4612
4613 switch (statype) {
4614 case CFG80211_STA_AP_MLME_CLIENT:
4615 /* Use this only for authorizing/unauthorizing a station */
4616 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4617 return -EOPNOTSUPP;
4618 break;
4619 case CFG80211_STA_AP_CLIENT:
Ayala Beker47edb112015-09-21 15:49:53 +03004620 case CFG80211_STA_AP_CLIENT_UNASSOC:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004621 /* accept only the listed bits */
4622 if (params->sta_flags_mask &
4623 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4624 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4625 BIT(NL80211_STA_FLAG_ASSOCIATED) |
4626 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4627 BIT(NL80211_STA_FLAG_WME) |
4628 BIT(NL80211_STA_FLAG_MFP)))
4629 return -EINVAL;
4630
4631 /* but authenticated/associated only if driver handles it */
4632 if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
4633 params->sta_flags_mask &
4634 (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4635 BIT(NL80211_STA_FLAG_ASSOCIATED)))
4636 return -EINVAL;
4637 break;
4638 case CFG80211_STA_IBSS:
4639 case CFG80211_STA_AP_STA:
4640 /* reject any changes other than AUTHORIZED */
4641 if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
4642 return -EINVAL;
4643 break;
4644 case CFG80211_STA_TDLS_PEER_SETUP:
4645 /* reject any changes other than AUTHORIZED or WME */
4646 if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4647 BIT(NL80211_STA_FLAG_WME)))
4648 return -EINVAL;
4649 /* force (at least) rates when authorizing */
4650 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
4651 !params->supported_rates)
4652 return -EINVAL;
4653 break;
4654 case CFG80211_STA_TDLS_PEER_ACTIVE:
4655 /* reject any changes */
4656 return -EINVAL;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004657 case CFG80211_STA_MESH_PEER_KERNEL:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004658 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4659 return -EINVAL;
4660 break;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004661 case CFG80211_STA_MESH_PEER_USER:
Chun-Yeow Yeoh42925042015-04-18 01:30:02 +08004662 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
4663 params->plink_action != NL80211_PLINK_ACTION_BLOCK)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004664 return -EINVAL;
4665 break;
4666 }
4667
Beni Lev06f7c882016-07-19 19:28:56 +03004668 /*
4669 * Older kernel versions ignored this attribute entirely, so don't
4670 * reject attempts to update it but mark it as unused instead so the
4671 * driver won't look at the data.
4672 */
4673 if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
4674 statype != CFG80211_STA_TDLS_PEER_SETUP)
4675 params->opmode_notif_used = false;
4676
Johannes Berg77ee7c82013-02-15 00:48:33 +01004677 return 0;
4678}
4679EXPORT_SYMBOL(cfg80211_check_station_change);
4680
Johannes Berg5727ef12007-12-19 02:03:34 +01004681/*
Felix Fietkauc258d2d2009-11-11 17:23:31 +01004682 * Get vlan interface making sure it is running and on the right wiphy.
Johannes Berg5727ef12007-12-19 02:03:34 +01004683 */
Johannes Berg80b99892011-11-18 16:23:01 +01004684static struct net_device *get_vlan(struct genl_info *info,
4685 struct cfg80211_registered_device *rdev)
Johannes Berg5727ef12007-12-19 02:03:34 +01004686{
Johannes Berg463d0182009-07-14 00:33:35 +02004687 struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
Johannes Berg80b99892011-11-18 16:23:01 +01004688 struct net_device *v;
4689 int ret;
Johannes Berg5727ef12007-12-19 02:03:34 +01004690
Johannes Berg80b99892011-11-18 16:23:01 +01004691 if (!vlanattr)
4692 return NULL;
4693
4694 v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
4695 if (!v)
4696 return ERR_PTR(-ENODEV);
4697
4698 if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
4699 ret = -EINVAL;
4700 goto error;
Johannes Berg5727ef12007-12-19 02:03:34 +01004701 }
Johannes Berg80b99892011-11-18 16:23:01 +01004702
Johannes Berg77ee7c82013-02-15 00:48:33 +01004703 if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
4704 v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4705 v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
4706 ret = -EINVAL;
4707 goto error;
4708 }
4709
Johannes Berg80b99892011-11-18 16:23:01 +01004710 if (!netif_running(v)) {
4711 ret = -ENETDOWN;
4712 goto error;
4713 }
4714
4715 return v;
4716 error:
4717 dev_put(v);
4718 return ERR_PTR(ret);
Johannes Berg5727ef12007-12-19 02:03:34 +01004719}
4720
Johannes Berg94e860f2014-01-20 23:58:15 +01004721static const struct nla_policy
4722nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
Jouni Malinendf881292013-02-14 21:10:54 +02004723 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
4724 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
4725};
4726
Johannes Bergff276692013-02-15 00:09:01 +01004727static int nl80211_parse_sta_wme(struct genl_info *info,
4728 struct station_parameters *params)
Jouni Malinendf881292013-02-14 21:10:54 +02004729{
Jouni Malinendf881292013-02-14 21:10:54 +02004730 struct nlattr *tb[NL80211_STA_WME_MAX + 1];
4731 struct nlattr *nla;
4732 int err;
4733
Jouni Malinendf881292013-02-14 21:10:54 +02004734 /* parse WME attributes if present */
4735 if (!info->attrs[NL80211_ATTR_STA_WME])
4736 return 0;
4737
4738 nla = info->attrs[NL80211_ATTR_STA_WME];
4739 err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
4740 nl80211_sta_wme_policy);
4741 if (err)
4742 return err;
4743
4744 if (tb[NL80211_STA_WME_UAPSD_QUEUES])
4745 params->uapsd_queues = nla_get_u8(
4746 tb[NL80211_STA_WME_UAPSD_QUEUES]);
4747 if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
4748 return -EINVAL;
4749
4750 if (tb[NL80211_STA_WME_MAX_SP])
4751 params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
4752
4753 if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
4754 return -EINVAL;
4755
4756 params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
4757
4758 return 0;
4759}
4760
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304761static int nl80211_parse_sta_channel_info(struct genl_info *info,
4762 struct station_parameters *params)
4763{
4764 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
4765 params->supported_channels =
4766 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4767 params->supported_channels_len =
4768 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4769 /*
4770 * Need to include at least one (first channel, number of
4771 * channels) tuple for each subband, and must have proper
4772 * tuples for the rest of the data as well.
4773 */
4774 if (params->supported_channels_len < 2)
4775 return -EINVAL;
4776 if (params->supported_channels_len % 2)
4777 return -EINVAL;
4778 }
4779
4780 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
4781 params->supported_oper_classes =
4782 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4783 params->supported_oper_classes_len =
4784 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4785 /*
4786 * The value of the Length field of the Supported Operating
4787 * Classes element is between 2 and 253.
4788 */
4789 if (params->supported_oper_classes_len < 2 ||
4790 params->supported_oper_classes_len > 253)
4791 return -EINVAL;
4792 }
4793 return 0;
4794}
4795
Johannes Bergff276692013-02-15 00:09:01 +01004796static int nl80211_set_station_tdls(struct genl_info *info,
4797 struct station_parameters *params)
4798{
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304799 int err;
Johannes Bergff276692013-02-15 00:09:01 +01004800 /* Dummy STA entry gets updated once the peer capabilities are known */
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004801 if (info->attrs[NL80211_ATTR_PEER_AID])
4802 params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Johannes Bergff276692013-02-15 00:09:01 +01004803 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
4804 params->ht_capa =
4805 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
4806 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
4807 params->vht_capa =
4808 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
4809
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304810 err = nl80211_parse_sta_channel_info(info, params);
4811 if (err)
4812 return err;
4813
Johannes Bergff276692013-02-15 00:09:01 +01004814 return nl80211_parse_sta_wme(info, params);
4815}
4816
Johannes Berg5727ef12007-12-19 02:03:34 +01004817static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
4818{
Johannes Berg4c476992010-10-04 21:36:35 +02004819 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02004820 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004821 struct station_parameters params;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004822 u8 *mac_addr;
4823 int err;
Johannes Berg5727ef12007-12-19 02:03:34 +01004824
4825 memset(&params, 0, sizeof(params));
4826
Johannes Berg77ee7c82013-02-15 00:48:33 +01004827 if (!rdev->ops->change_station)
4828 return -EOPNOTSUPP;
4829
Ayala Bekere4208422015-10-23 11:20:06 +03004830 /*
4831 * AID and listen_interval properties can be set only for unassociated
4832 * station. Include these parameters here and will check them in
4833 * cfg80211_check_station_change().
4834 */
Ayala Bekera9bc31e2015-11-26 16:26:12 +01004835 if (info->attrs[NL80211_ATTR_STA_AID])
4836 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Ayala Bekere4208422015-10-23 11:20:06 +03004837
4838 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4839 params.listen_interval =
4840 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
4841 else
4842 params.listen_interval = -1;
Johannes Berg5727ef12007-12-19 02:03:34 +01004843
Ayala Beker17b94242016-03-17 15:41:38 +02004844 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
4845 u8 tmp;
4846
4847 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
4848 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
4849 return -EINVAL;
4850
4851 params.support_p2p_ps = tmp;
4852 } else {
4853 params.support_p2p_ps = -1;
4854 }
4855
Johannes Berg5727ef12007-12-19 02:03:34 +01004856 if (!info->attrs[NL80211_ATTR_MAC])
4857 return -EINVAL;
4858
4859 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4860
4861 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
4862 params.supported_rates =
4863 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4864 params.supported_rates_len =
4865 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4866 }
4867
Jouni Malinen9d62a982013-02-14 21:10:13 +02004868 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
4869 params.capability =
4870 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
4871 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
4872 }
4873
4874 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
4875 params.ext_capab =
4876 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4877 params.ext_capab_len =
4878 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4879 }
4880
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004881 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01004882 return -EINVAL;
4883
Johannes Bergf8bacc22013-02-14 23:27:01 +01004884 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004885 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004886 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
4887 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
4888 return -EINVAL;
4889 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004890
Johannes Bergf8bacc22013-02-14 23:27:01 +01004891 if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
Javier Cardona9c3990a2011-05-03 16:57:11 -07004892 params.plink_state =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004893 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
4894 if (params.plink_state >= NUM_NL80211_PLINK_STATES)
4895 return -EINVAL;
Masashi Honma7d27a0b2016-07-01 10:19:34 +09004896 if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) {
4897 params.peer_aid = nla_get_u16(
4898 info->attrs[NL80211_ATTR_MESH_PEER_AID]);
4899 if (params.peer_aid > IEEE80211_MAX_AID)
4900 return -EINVAL;
4901 }
Johannes Bergf8bacc22013-02-14 23:27:01 +01004902 params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
4903 }
Javier Cardona9c3990a2011-05-03 16:57:11 -07004904
Marco Porsch3b1c5a52013-01-07 16:04:52 +01004905 if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
4906 enum nl80211_mesh_power_mode pm = nla_get_u32(
4907 info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
4908
4909 if (pm <= NL80211_MESH_POWER_UNKNOWN ||
4910 pm > NL80211_MESH_POWER_MAX)
4911 return -EINVAL;
4912
4913 params.local_pm = pm;
4914 }
4915
Beni Lev06f7c882016-07-19 19:28:56 +03004916 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
4917 params.opmode_notif_used = true;
4918 params.opmode_notif =
4919 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
4920 }
4921
Johannes Berg77ee7c82013-02-15 00:48:33 +01004922 /* Include parameters for TDLS peer (will check later) */
4923 err = nl80211_set_station_tdls(info, &params);
4924 if (err)
4925 return err;
4926
4927 params.vlan = get_vlan(info, rdev);
4928 if (IS_ERR(params.vlan))
4929 return PTR_ERR(params.vlan);
4930
Johannes Berga97f4422009-06-18 17:23:43 +02004931 switch (dev->ieee80211_ptr->iftype) {
4932 case NL80211_IFTYPE_AP:
4933 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02004934 case NL80211_IFTYPE_P2P_GO:
Johannes Berg074ac8d2010-09-16 14:58:22 +02004935 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berga97f4422009-06-18 17:23:43 +02004936 case NL80211_IFTYPE_STATION:
Antonio Quartulli267335d2012-01-31 20:25:47 +01004937 case NL80211_IFTYPE_ADHOC:
Johannes Berga97f4422009-06-18 17:23:43 +02004938 case NL80211_IFTYPE_MESH_POINT:
Johannes Berga97f4422009-06-18 17:23:43 +02004939 break;
4940 default:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004941 err = -EOPNOTSUPP;
4942 goto out_put_vlan;
Johannes Berg034d6552009-05-27 10:35:29 +02004943 }
4944
Johannes Berg77ee7c82013-02-15 00:48:33 +01004945 /* driver will call cfg80211_check_station_change() */
Hila Gonene35e4d22012-06-27 17:19:42 +03004946 err = rdev_change_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01004947
Johannes Berg77ee7c82013-02-15 00:48:33 +01004948 out_put_vlan:
Johannes Berg5727ef12007-12-19 02:03:34 +01004949 if (params.vlan)
4950 dev_put(params.vlan);
Johannes Berg3b858752009-03-12 09:55:09 +01004951
Johannes Berg5727ef12007-12-19 02:03:34 +01004952 return err;
4953}
4954
4955static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
4956{
Johannes Berg4c476992010-10-04 21:36:35 +02004957 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg5727ef12007-12-19 02:03:34 +01004958 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004959 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004960 struct station_parameters params;
4961 u8 *mac_addr = NULL;
Johannes Bergbda95eb2015-11-26 16:26:13 +01004962 u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4963 BIT(NL80211_STA_FLAG_ASSOCIATED);
Johannes Berg5727ef12007-12-19 02:03:34 +01004964
4965 memset(&params, 0, sizeof(params));
4966
Johannes Berg984c3112013-02-14 23:43:25 +01004967 if (!rdev->ops->add_station)
4968 return -EOPNOTSUPP;
4969
Johannes Berg5727ef12007-12-19 02:03:34 +01004970 if (!info->attrs[NL80211_ATTR_MAC])
4971 return -EINVAL;
4972
Johannes Berg5727ef12007-12-19 02:03:34 +01004973 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4974 return -EINVAL;
4975
4976 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
4977 return -EINVAL;
4978
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004979 if (!info->attrs[NL80211_ATTR_STA_AID] &&
4980 !info->attrs[NL80211_ATTR_PEER_AID])
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02004981 return -EINVAL;
4982
Johannes Berg5727ef12007-12-19 02:03:34 +01004983 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4984 params.supported_rates =
4985 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4986 params.supported_rates_len =
4987 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4988 params.listen_interval =
4989 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02004990
Ayala Beker17b94242016-03-17 15:41:38 +02004991 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
4992 u8 tmp;
4993
4994 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
4995 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
4996 return -EINVAL;
4997
4998 params.support_p2p_ps = tmp;
4999 } else {
5000 /*
5001 * if not specified, assume it's supported for P2P GO interface,
5002 * and is NOT supported for AP interface
5003 */
5004 params.support_p2p_ps =
5005 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
5006 }
5007
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005008 if (info->attrs[NL80211_ATTR_PEER_AID])
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005009 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005010 else
5011 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02005012 if (!params.aid || params.aid > IEEE80211_MAX_AID)
5013 return -EINVAL;
Johannes Berg51b50fb2009-05-24 16:42:30 +02005014
Jouni Malinen9d62a982013-02-14 21:10:13 +02005015 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5016 params.capability =
5017 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5018 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5019 }
5020
5021 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5022 params.ext_capab =
5023 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5024 params.ext_capab_len =
5025 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5026 }
5027
Jouni Malinen36aedc92008-08-25 11:58:58 +03005028 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
5029 params.ht_capa =
5030 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005031
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +00005032 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
5033 params.vht_capa =
5034 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
5035
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +01005036 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
5037 params.opmode_notif_used = true;
5038 params.opmode_notif =
5039 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
5040 }
5041
Johannes Bergf8bacc22013-02-14 23:27:01 +01005042 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Javier Cardona96b78df2011-04-07 15:08:33 -07005043 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005044 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5045 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
5046 return -EINVAL;
5047 }
Javier Cardona96b78df2011-04-07 15:08:33 -07005048
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305049 err = nl80211_parse_sta_channel_info(info, &params);
5050 if (err)
5051 return err;
5052
Johannes Bergff276692013-02-15 00:09:01 +01005053 err = nl80211_parse_sta_wme(info, &params);
5054 if (err)
5055 return err;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005056
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005057 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01005058 return -EINVAL;
5059
Johannes Berg496fcc22015-03-12 08:53:27 +02005060 /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
5061 * as userspace might just pass through the capabilities from the IEs
5062 * directly, rather than enforcing this restriction and returning an
5063 * error in this case.
5064 */
5065 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
5066 params.ht_capa = NULL;
5067 params.vht_capa = NULL;
5068 }
5069
Johannes Berg77ee7c82013-02-15 00:48:33 +01005070 /* When you run into this, adjust the code below for the new flag */
5071 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5072
Johannes Bergbdd90d52011-12-14 12:20:27 +01005073 switch (dev->ieee80211_ptr->iftype) {
5074 case NL80211_IFTYPE_AP:
5075 case NL80211_IFTYPE_AP_VLAN:
5076 case NL80211_IFTYPE_P2P_GO:
Johannes Berg984c3112013-02-14 23:43:25 +01005077 /* ignore WME attributes if iface/sta is not capable */
5078 if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
5079 !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
5080 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005081
Johannes Bergbdd90d52011-12-14 12:20:27 +01005082 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005083 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5084 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005085 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005086 /* but don't bother the driver with it */
5087 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
Eliad Pellerc75786c2011-08-23 14:37:46 +03005088
Johannes Bergd582cff2012-10-26 17:53:44 +02005089 /* allow authenticated/associated only if driver handles it */
5090 if (!(rdev->wiphy.features &
5091 NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
Johannes Bergbda95eb2015-11-26 16:26:13 +01005092 params.sta_flags_mask & auth_assoc)
Johannes Bergd582cff2012-10-26 17:53:44 +02005093 return -EINVAL;
5094
Johannes Bergbda95eb2015-11-26 16:26:13 +01005095 /* Older userspace, or userspace wanting to be compatible with
5096 * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
5097 * and assoc flags in the mask, but assumes the station will be
5098 * added as associated anyway since this was the required driver
5099 * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
5100 * introduced.
5101 * In order to not bother drivers with this quirk in the API
5102 * set the flags in both the mask and set for new stations in
5103 * this case.
5104 */
5105 if (!(params.sta_flags_mask & auth_assoc)) {
5106 params.sta_flags_mask |= auth_assoc;
5107 params.sta_flags_set |= auth_assoc;
5108 }
5109
Johannes Bergbdd90d52011-12-14 12:20:27 +01005110 /* must be last in here for error handling */
5111 params.vlan = get_vlan(info, rdev);
5112 if (IS_ERR(params.vlan))
5113 return PTR_ERR(params.vlan);
5114 break;
5115 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg984c3112013-02-14 23:43:25 +01005116 /* ignore uAPSD data */
5117 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5118
Johannes Bergd582cff2012-10-26 17:53:44 +02005119 /* associated is disallowed */
5120 if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
5121 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005122 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005123 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5124 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005125 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005126 break;
5127 case NL80211_IFTYPE_STATION:
Johannes Berg93d08f02013-03-04 09:29:46 +01005128 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg984c3112013-02-14 23:43:25 +01005129 /* ignore uAPSD data */
5130 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5131
Johannes Berg77ee7c82013-02-15 00:48:33 +01005132 /* these are disallowed */
5133 if (params.sta_flags_mask &
5134 (BIT(NL80211_STA_FLAG_ASSOCIATED) |
5135 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
Johannes Bergd582cff2012-10-26 17:53:44 +02005136 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005137 /* Only TDLS peers can be added */
5138 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
5139 return -EINVAL;
5140 /* Can only add if TDLS ... */
5141 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
5142 return -EOPNOTSUPP;
5143 /* ... with external setup is supported */
5144 if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
5145 return -EOPNOTSUPP;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005146 /*
5147 * Older wpa_supplicant versions always mark the TDLS peer
5148 * as authorized, but it shouldn't yet be.
5149 */
5150 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
Johannes Bergbdd90d52011-12-14 12:20:27 +01005151 break;
5152 default:
5153 return -EOPNOTSUPP;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005154 }
5155
Johannes Bergbdd90d52011-12-14 12:20:27 +01005156 /* be aware of params.vlan when changing code here */
Johannes Berg5727ef12007-12-19 02:03:34 +01005157
Hila Gonene35e4d22012-06-27 17:19:42 +03005158 err = rdev_add_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005159
Johannes Berg5727ef12007-12-19 02:03:34 +01005160 if (params.vlan)
5161 dev_put(params.vlan);
Johannes Berg5727ef12007-12-19 02:03:34 +01005162 return err;
5163}
5164
5165static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
5166{
Johannes Berg4c476992010-10-04 21:36:35 +02005167 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5168 struct net_device *dev = info->user_ptr[1];
Jouni Malinen89c771e2014-10-10 20:52:40 +03005169 struct station_del_parameters params;
5170
5171 memset(&params, 0, sizeof(params));
Johannes Berg5727ef12007-12-19 02:03:34 +01005172
5173 if (info->attrs[NL80211_ATTR_MAC])
Jouni Malinen89c771e2014-10-10 20:52:40 +03005174 params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005175
Johannes Berge80cf852009-05-11 14:43:13 +02005176 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Marco Porschd5d9de02010-03-30 10:00:16 +02005177 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
Johannes Berg074ac8d2010-09-16 14:58:22 +02005178 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
Johannes Berg4c476992010-10-04 21:36:35 +02005179 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5180 return -EINVAL;
Johannes Berge80cf852009-05-11 14:43:13 +02005181
Johannes Berg4c476992010-10-04 21:36:35 +02005182 if (!rdev->ops->del_station)
5183 return -EOPNOTSUPP;
Johannes Berg5727ef12007-12-19 02:03:34 +01005184
Jouni Malinen98856862014-10-20 13:20:45 +03005185 if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
5186 params.subtype =
5187 nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
5188 if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
5189 params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
5190 return -EINVAL;
5191 } else {
5192 /* Default to Deauthentication frame */
5193 params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
5194 }
5195
5196 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
5197 params.reason_code =
5198 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
5199 if (params.reason_code == 0)
5200 return -EINVAL; /* 0 is reserved */
5201 } else {
5202 /* Default to reason code 2 */
5203 params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
5204 }
5205
Jouni Malinen89c771e2014-10-10 20:52:40 +03005206 return rdev_del_station(rdev, dev, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005207}
5208
Eric W. Biederman15e47302012-09-07 20:12:54 +00005209static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005210 int flags, struct net_device *dev,
5211 u8 *dst, u8 *next_hop,
5212 struct mpath_info *pinfo)
5213{
5214 void *hdr;
5215 struct nlattr *pinfoattr;
5216
Henning Rogge1ef4c852014-11-04 16:14:58 +01005217 hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005218 if (!hdr)
5219 return -1;
5220
David S. Miller9360ffd2012-03-29 04:41:26 -04005221 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5222 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
5223 nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
5224 nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
5225 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02005226
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005227 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
5228 if (!pinfoattr)
5229 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005230 if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
5231 nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
5232 pinfo->frame_qlen))
5233 goto nla_put_failure;
5234 if (((pinfo->filled & MPATH_INFO_SN) &&
5235 nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
5236 ((pinfo->filled & MPATH_INFO_METRIC) &&
5237 nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
5238 pinfo->metric)) ||
5239 ((pinfo->filled & MPATH_INFO_EXPTIME) &&
5240 nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
5241 pinfo->exptime)) ||
5242 ((pinfo->filled & MPATH_INFO_FLAGS) &&
5243 nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
5244 pinfo->flags)) ||
5245 ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
5246 nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
5247 pinfo->discovery_timeout)) ||
5248 ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
5249 nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
5250 pinfo->discovery_retries)))
5251 goto nla_put_failure;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005252
5253 nla_nest_end(msg, pinfoattr);
5254
Johannes Berg053c0952015-01-16 22:09:00 +01005255 genlmsg_end(msg, hdr);
5256 return 0;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005257
5258 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07005259 genlmsg_cancel(msg, hdr);
5260 return -EMSGSIZE;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005261}
5262
5263static int nl80211_dump_mpath(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005264 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005265{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005266 struct mpath_info pinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005267 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02005268 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005269 u8 dst[ETH_ALEN];
5270 u8 next_hop[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02005271 int path_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005272 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005273
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005274 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02005275 if (err)
5276 return err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005277
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005278 if (!rdev->ops->dump_mpath) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005279 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005280 goto out_err;
5281 }
5282
Johannes Berg97990a02013-04-19 01:02:55 +02005283 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005284 err = -EOPNOTSUPP;
Roel Kluin0448b5f2009-08-22 21:15:49 +02005285 goto out_err;
Jouni Malineneec60b02009-03-20 21:21:19 +02005286 }
5287
Johannes Bergbba95fe2008-07-29 13:22:51 +02005288 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005289 err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
Johannes Berg97990a02013-04-19 01:02:55 +02005290 next_hop, &pinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005291 if (err == -ENOENT)
5292 break;
5293 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01005294 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005295
Eric W. Biederman15e47302012-09-07 20:12:54 +00005296 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005297 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg97990a02013-04-19 01:02:55 +02005298 wdev->netdev, dst, next_hop,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005299 &pinfo) < 0)
5300 goto out;
5301
5302 path_idx++;
5303 }
5304
Johannes Bergbba95fe2008-07-29 13:22:51 +02005305 out:
Johannes Berg97990a02013-04-19 01:02:55 +02005306 cb->args[2] = path_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005307 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005308 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005309 nl80211_finish_wdev_dump(rdev);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005310 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005311}
5312
5313static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
5314{
Johannes Berg4c476992010-10-04 21:36:35 +02005315 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005316 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02005317 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005318 struct mpath_info pinfo;
5319 struct sk_buff *msg;
5320 u8 *dst = NULL;
5321 u8 next_hop[ETH_ALEN];
5322
5323 memset(&pinfo, 0, sizeof(pinfo));
5324
5325 if (!info->attrs[NL80211_ATTR_MAC])
5326 return -EINVAL;
5327
5328 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5329
Johannes Berg4c476992010-10-04 21:36:35 +02005330 if (!rdev->ops->get_mpath)
5331 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005332
Johannes Berg4c476992010-10-04 21:36:35 +02005333 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5334 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005335
Hila Gonene35e4d22012-06-27 17:19:42 +03005336 err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005337 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005338 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005339
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005340 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005341 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02005342 return -ENOMEM;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005343
Eric W. Biederman15e47302012-09-07 20:12:54 +00005344 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg4c476992010-10-04 21:36:35 +02005345 dev, dst, next_hop, &pinfo) < 0) {
5346 nlmsg_free(msg);
5347 return -ENOBUFS;
5348 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005349
Johannes Berg4c476992010-10-04 21:36:35 +02005350 return genlmsg_reply(msg, info);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005351}
5352
5353static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
5354{
Johannes Berg4c476992010-10-04 21:36:35 +02005355 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5356 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005357 u8 *dst = NULL;
5358 u8 *next_hop = NULL;
5359
5360 if (!info->attrs[NL80211_ATTR_MAC])
5361 return -EINVAL;
5362
5363 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5364 return -EINVAL;
5365
5366 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5367 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5368
Johannes Berg4c476992010-10-04 21:36:35 +02005369 if (!rdev->ops->change_mpath)
5370 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005371
Johannes Berg4c476992010-10-04 21:36:35 +02005372 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5373 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005374
Hila Gonene35e4d22012-06-27 17:19:42 +03005375 return rdev_change_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005376}
Johannes Berg4c476992010-10-04 21:36:35 +02005377
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005378static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
5379{
Johannes Berg4c476992010-10-04 21:36:35 +02005380 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5381 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005382 u8 *dst = NULL;
5383 u8 *next_hop = NULL;
5384
5385 if (!info->attrs[NL80211_ATTR_MAC])
5386 return -EINVAL;
5387
5388 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5389 return -EINVAL;
5390
5391 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5392 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5393
Johannes Berg4c476992010-10-04 21:36:35 +02005394 if (!rdev->ops->add_mpath)
5395 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005396
Johannes Berg4c476992010-10-04 21:36:35 +02005397 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5398 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005399
Hila Gonene35e4d22012-06-27 17:19:42 +03005400 return rdev_add_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005401}
5402
5403static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
5404{
Johannes Berg4c476992010-10-04 21:36:35 +02005405 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5406 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005407 u8 *dst = NULL;
5408
5409 if (info->attrs[NL80211_ATTR_MAC])
5410 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5411
Johannes Berg4c476992010-10-04 21:36:35 +02005412 if (!rdev->ops->del_mpath)
5413 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005414
Hila Gonene35e4d22012-06-27 17:19:42 +03005415 return rdev_del_mpath(rdev, dev, dst);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005416}
5417
Henning Rogge66be7d22014-09-12 08:58:49 +02005418static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
5419{
5420 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5421 int err;
5422 struct net_device *dev = info->user_ptr[1];
5423 struct mpath_info pinfo;
5424 struct sk_buff *msg;
5425 u8 *dst = NULL;
5426 u8 mpp[ETH_ALEN];
5427
5428 memset(&pinfo, 0, sizeof(pinfo));
5429
5430 if (!info->attrs[NL80211_ATTR_MAC])
5431 return -EINVAL;
5432
5433 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5434
5435 if (!rdev->ops->get_mpp)
5436 return -EOPNOTSUPP;
5437
5438 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5439 return -EOPNOTSUPP;
5440
5441 err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
5442 if (err)
5443 return err;
5444
5445 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5446 if (!msg)
5447 return -ENOMEM;
5448
5449 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
5450 dev, dst, mpp, &pinfo) < 0) {
5451 nlmsg_free(msg);
5452 return -ENOBUFS;
5453 }
5454
5455 return genlmsg_reply(msg, info);
5456}
5457
5458static int nl80211_dump_mpp(struct sk_buff *skb,
5459 struct netlink_callback *cb)
5460{
5461 struct mpath_info pinfo;
5462 struct cfg80211_registered_device *rdev;
5463 struct wireless_dev *wdev;
5464 u8 dst[ETH_ALEN];
5465 u8 mpp[ETH_ALEN];
5466 int path_idx = cb->args[2];
5467 int err;
5468
5469 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
5470 if (err)
5471 return err;
5472
5473 if (!rdev->ops->dump_mpp) {
5474 err = -EOPNOTSUPP;
5475 goto out_err;
5476 }
5477
5478 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
5479 err = -EOPNOTSUPP;
5480 goto out_err;
5481 }
5482
5483 while (1) {
5484 err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
5485 mpp, &pinfo);
5486 if (err == -ENOENT)
5487 break;
5488 if (err)
5489 goto out_err;
5490
5491 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
5492 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5493 wdev->netdev, dst, mpp,
5494 &pinfo) < 0)
5495 goto out;
5496
5497 path_idx++;
5498 }
5499
5500 out:
5501 cb->args[2] = path_idx;
5502 err = skb->len;
5503 out_err:
5504 nl80211_finish_wdev_dump(rdev);
5505 return err;
5506}
5507
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005508static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
5509{
Johannes Berg4c476992010-10-04 21:36:35 +02005510 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5511 struct net_device *dev = info->user_ptr[1];
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005512 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005513 struct bss_parameters params;
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005514 int err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005515
5516 memset(&params, 0, sizeof(params));
5517 /* default to not changing parameters */
5518 params.use_cts_prot = -1;
5519 params.use_short_preamble = -1;
5520 params.use_short_slot_time = -1;
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005521 params.ap_isolate = -1;
Helmut Schaa50b12f52010-11-19 12:40:25 +01005522 params.ht_opmode = -1;
Johannes Berg53cabad2012-11-14 15:17:28 +01005523 params.p2p_ctwindow = -1;
5524 params.p2p_opp_ps = -1;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005525
5526 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
5527 params.use_cts_prot =
5528 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
5529 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
5530 params.use_short_preamble =
5531 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
5532 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
5533 params.use_short_slot_time =
5534 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
Jouni Malinen90c97a02008-10-30 16:59:22 +02005535 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
5536 params.basic_rates =
5537 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5538 params.basic_rates_len =
5539 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5540 }
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005541 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
5542 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
Helmut Schaa50b12f52010-11-19 12:40:25 +01005543 if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
5544 params.ht_opmode =
5545 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005546
Johannes Berg53cabad2012-11-14 15:17:28 +01005547 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
5548 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5549 return -EINVAL;
5550 params.p2p_ctwindow =
5551 nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
5552 if (params.p2p_ctwindow < 0)
5553 return -EINVAL;
5554 if (params.p2p_ctwindow != 0 &&
5555 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
5556 return -EINVAL;
5557 }
5558
5559 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
5560 u8 tmp;
5561
5562 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5563 return -EINVAL;
5564 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
5565 if (tmp > 1)
5566 return -EINVAL;
5567 params.p2p_opp_ps = tmp;
5568 if (params.p2p_opp_ps &&
5569 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
5570 return -EINVAL;
5571 }
5572
Johannes Berg4c476992010-10-04 21:36:35 +02005573 if (!rdev->ops->change_bss)
5574 return -EOPNOTSUPP;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005575
Johannes Berg074ac8d2010-09-16 14:58:22 +02005576 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berg4c476992010-10-04 21:36:35 +02005577 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5578 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005579
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005580 wdev_lock(wdev);
5581 err = rdev_change_bss(rdev, dev, &params);
5582 wdev_unlock(wdev);
5583
5584 return err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005585}
5586
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005587static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
5588{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005589 char *data = NULL;
Ilan peer05050752015-03-04 00:32:06 -05005590 bool is_indoor;
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005591 enum nl80211_user_reg_hint_type user_reg_hint_type;
Ilan peer05050752015-03-04 00:32:06 -05005592 u32 owner_nlportid;
5593
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005594 /*
5595 * You should only get this when cfg80211 hasn't yet initialized
5596 * completely when built-in to the kernel right between the time
5597 * window between nl80211_init() and regulatory_init(), if that is
5598 * even possible.
5599 */
Johannes Berg458f4f92012-12-06 15:47:38 +01005600 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
Luis R. Rodriguezfe33eb32009-02-21 00:04:30 -05005601 return -EINPROGRESS;
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005602
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005603 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
5604 user_reg_hint_type =
5605 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
5606 else
5607 user_reg_hint_type = NL80211_USER_REG_HINT_USER;
5608
5609 switch (user_reg_hint_type) {
5610 case NL80211_USER_REG_HINT_USER:
5611 case NL80211_USER_REG_HINT_CELL_BASE:
Ilan Peer52616f22014-02-25 16:26:00 +02005612 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
5613 return -EINVAL;
5614
5615 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
5616 return regulatory_hint_user(data, user_reg_hint_type);
5617 case NL80211_USER_REG_HINT_INDOOR:
Ilan peer05050752015-03-04 00:32:06 -05005618 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
5619 owner_nlportid = info->snd_portid;
5620 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
5621 } else {
5622 owner_nlportid = 0;
5623 is_indoor = true;
5624 }
5625
5626 return regulatory_hint_indoor(is_indoor, owner_nlportid);
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005627 default:
5628 return -EINVAL;
5629 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005630}
5631
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005632static int nl80211_get_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01005633 struct genl_info *info)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005634{
Johannes Berg4c476992010-10-04 21:36:35 +02005635 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02005636 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01005637 struct wireless_dev *wdev = dev->ieee80211_ptr;
5638 struct mesh_config cur_params;
5639 int err = 0;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005640 void *hdr;
5641 struct nlattr *pinfoattr;
5642 struct sk_buff *msg;
5643
Johannes Berg29cbe682010-12-03 09:20:44 +01005644 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
5645 return -EOPNOTSUPP;
5646
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005647 if (!rdev->ops->get_mesh_config)
Johannes Berg4c476992010-10-04 21:36:35 +02005648 return -EOPNOTSUPP;
Jouni Malinenf3f92582009-03-20 17:57:36 +02005649
Johannes Berg29cbe682010-12-03 09:20:44 +01005650 wdev_lock(wdev);
5651 /* If not connected, get default parameters */
5652 if (!wdev->mesh_id_len)
5653 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
5654 else
Hila Gonene35e4d22012-06-27 17:19:42 +03005655 err = rdev_get_mesh_config(rdev, dev, &cur_params);
Johannes Berg29cbe682010-12-03 09:20:44 +01005656 wdev_unlock(wdev);
5657
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005658 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005659 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005660
5661 /* Draw up a netlink message to send back */
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005662 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02005663 if (!msg)
5664 return -ENOMEM;
Eric W. Biederman15e47302012-09-07 20:12:54 +00005665 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005666 NL80211_CMD_GET_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005667 if (!hdr)
Julia Lawallefe1cf02011-01-28 15:17:11 +01005668 goto out;
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005669 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005670 if (!pinfoattr)
5671 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005672 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5673 nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
5674 cur_params.dot11MeshRetryTimeout) ||
5675 nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
5676 cur_params.dot11MeshConfirmTimeout) ||
5677 nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
5678 cur_params.dot11MeshHoldingTimeout) ||
5679 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
5680 cur_params.dot11MeshMaxPeerLinks) ||
5681 nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
5682 cur_params.dot11MeshMaxRetries) ||
5683 nla_put_u8(msg, NL80211_MESHCONF_TTL,
5684 cur_params.dot11MeshTTL) ||
5685 nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
5686 cur_params.element_ttl) ||
5687 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
5688 cur_params.auto_open_plinks) ||
John W. Linville7eab0f62012-04-12 14:25:14 -04005689 nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
5690 cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04005691 nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
5692 cur_params.dot11MeshHWMPmaxPREQretries) ||
5693 nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
5694 cur_params.path_refresh_time) ||
5695 nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
5696 cur_params.min_discovery_timeout) ||
5697 nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
5698 cur_params.dot11MeshHWMPactivePathTimeout) ||
5699 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
5700 cur_params.dot11MeshHWMPpreqMinInterval) ||
5701 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
5702 cur_params.dot11MeshHWMPperrMinInterval) ||
5703 nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
5704 cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
5705 nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
5706 cur_params.dot11MeshHWMPRootMode) ||
5707 nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
5708 cur_params.dot11MeshHWMPRannInterval) ||
5709 nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
5710 cur_params.dot11MeshGateAnnouncementProtocol) ||
5711 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
5712 cur_params.dot11MeshForwarding) ||
5713 nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
Ashok Nagarajan70c33ea2012-04-30 14:20:32 -07005714 cur_params.rssi_threshold) ||
5715 nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005716 cur_params.ht_opmode) ||
5717 nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
5718 cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
5719 nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005720 cur_params.dot11MeshHWMProotInterval) ||
5721 nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005722 cur_params.dot11MeshHWMPconfirmationInterval) ||
5723 nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
5724 cur_params.power_mode) ||
5725 nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005726 cur_params.dot11MeshAwakeWindowDuration) ||
5727 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
5728 cur_params.plink_timeout))
David S. Miller9360ffd2012-03-29 04:41:26 -04005729 goto nla_put_failure;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005730 nla_nest_end(msg, pinfoattr);
5731 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02005732 return genlmsg_reply(msg, info);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005733
Johannes Berg3b858752009-03-12 09:55:09 +01005734 nla_put_failure:
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005735 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01005736 out:
Yuri Ershovd080e272010-06-29 15:08:07 +04005737 nlmsg_free(msg);
Johannes Berg4c476992010-10-04 21:36:35 +02005738 return -ENOBUFS;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005739}
5740
Alexey Dobriyanb54452b2010-02-18 08:14:31 +00005741static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005742 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
5743 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
5744 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
5745 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
5746 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
5747 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
Javier Cardona45904f22010-12-03 09:20:40 +01005748 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005749 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
Javier Cardonad299a1f2012-03-31 11:31:33 -07005750 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005751 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
5752 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
5753 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
5754 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
5755 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
Thomas Pedersendca7e942011-11-24 17:15:24 -08005756 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005757 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
Javier Cardona699403d2011-08-09 16:45:09 -07005758 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
Javier Cardona0507e152011-08-09 16:45:10 -07005759 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
Javier Cardona16dd7262011-08-09 16:45:11 -07005760 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
Chun-Yeow Yeoh94f90652012-01-21 01:02:16 +08005761 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005762 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
5763 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005764 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
5765 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005766 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005767 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
5768 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005769 [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005770};
5771
Javier Cardonac80d5452010-12-16 17:37:49 -08005772static const struct nla_policy
5773 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
Javier Cardonad299a1f2012-03-31 11:31:33 -07005774 [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
Javier Cardonac80d5452010-12-16 17:37:49 -08005775 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
5776 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
Javier Cardona15d5dda2011-04-07 15:08:28 -07005777 [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
Colleen Twitty6e16d902013-05-08 11:45:59 -07005778 [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08005779 [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
Javier Cardona581a8b02011-04-07 15:08:27 -07005780 [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005781 .len = IEEE80211_MAX_DATA_LEN },
Javier Cardonab130e5c2011-05-03 16:57:07 -07005782 [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
Javier Cardonac80d5452010-12-16 17:37:49 -08005783};
5784
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005785static int nl80211_check_bool(const struct nlattr *nla, u8 min, u8 max, bool *out)
5786{
5787 u8 val = nla_get_u8(nla);
5788 if (val < min || val > max)
5789 return -EINVAL;
5790 *out = val;
5791 return 0;
5792}
5793
5794static int nl80211_check_u8(const struct nlattr *nla, u8 min, u8 max, u8 *out)
5795{
5796 u8 val = nla_get_u8(nla);
5797 if (val < min || val > max)
5798 return -EINVAL;
5799 *out = val;
5800 return 0;
5801}
5802
5803static int nl80211_check_u16(const struct nlattr *nla, u16 min, u16 max, u16 *out)
5804{
5805 u16 val = nla_get_u16(nla);
5806 if (val < min || val > max)
5807 return -EINVAL;
5808 *out = val;
5809 return 0;
5810}
5811
5812static int nl80211_check_u32(const struct nlattr *nla, u32 min, u32 max, u32 *out)
5813{
5814 u32 val = nla_get_u32(nla);
5815 if (val < min || val > max)
5816 return -EINVAL;
5817 *out = val;
5818 return 0;
5819}
5820
5821static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *out)
5822{
5823 s32 val = nla_get_s32(nla);
5824 if (val < min || val > max)
5825 return -EINVAL;
5826 *out = val;
5827 return 0;
5828}
5829
Johannes Bergff9a71a2016-08-11 14:59:53 +02005830static int nl80211_check_power_mode(const struct nlattr *nla,
5831 enum nl80211_mesh_power_mode min,
5832 enum nl80211_mesh_power_mode max,
5833 enum nl80211_mesh_power_mode *out)
5834{
5835 u32 val = nla_get_u32(nla);
5836 if (val < min || val > max)
5837 return -EINVAL;
5838 *out = val;
5839 return 0;
5840}
5841
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005842static int nl80211_parse_mesh_config(struct genl_info *info,
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005843 struct mesh_config *cfg,
5844 u32 *mask_out)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005845{
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005846 struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005847 u32 mask = 0;
Masashi Honma97572352016-08-03 10:07:44 +09005848 u16 ht_opmode;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005849
Marco Porschea54fba2013-01-07 16:04:48 +01005850#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
5851do { \
5852 if (tb[attr]) { \
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005853 if (fn(tb[attr], min, max, &cfg->param)) \
Marco Porschea54fba2013-01-07 16:04:48 +01005854 return -EINVAL; \
Marco Porschea54fba2013-01-07 16:04:48 +01005855 mask |= (1 << (attr - 1)); \
5856 } \
5857} while (0)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005858
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005859 if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005860 return -EINVAL;
5861 if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005862 info->attrs[NL80211_ATTR_MESH_CONFIG],
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005863 nl80211_meshconf_params_policy))
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005864 return -EINVAL;
5865
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005866 /* This makes sure that there aren't more than 32 mesh config
5867 * parameters (otherwise our bitfield scheme would not work.) */
5868 BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
5869
5870 /* Fill in the params struct */
Marco Porschea54fba2013-01-07 16:04:48 +01005871 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005872 mask, NL80211_MESHCONF_RETRY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005873 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005874 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005875 mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005876 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005877 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005878 mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005879 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005880 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005881 mask, NL80211_MESHCONF_MAX_PEER_LINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005882 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005883 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005884 mask, NL80211_MESHCONF_MAX_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005885 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005886 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005887 mask, NL80211_MESHCONF_TTL, nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005888 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005889 mask, NL80211_MESHCONF_ELEMENT_TTL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005890 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005891 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005892 mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005893 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005894 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
5895 1, 255, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005896 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005897 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005898 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005899 mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005900 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005901 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005902 mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005903 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005904 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005905 mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005906 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005907 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
5908 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005909 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005910 nl80211_check_u32);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005911 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005912 1, 65535, mask,
5913 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005914 nl80211_check_u16);
Thomas Pedersendca7e942011-11-24 17:15:24 -08005915 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005916 1, 65535, mask,
5917 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005918 nl80211_check_u16);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005919 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005920 dot11MeshHWMPnetDiameterTraversalTime,
5921 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005922 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005923 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005924 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
5925 mask, NL80211_MESHCONF_HWMP_ROOTMODE,
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, dot11MeshHWMPRannInterval, 1, 65535,
5928 mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005929 nl80211_check_u16);
Rui Paulo63c57232009-11-09 23:46:57 +00005930 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005931 dot11MeshGateAnnouncementProtocol, 0, 1,
5932 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005933 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005934 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005935 mask, NL80211_MESHCONF_FORWARDING,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005936 nl80211_check_bool);
Chun-Yeow Yeoh83374fe2013-07-11 18:24:03 +08005937 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005938 mask, NL80211_MESHCONF_RSSI_THRESHOLD,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005939 nl80211_check_s32);
Masashi Honma97572352016-08-03 10:07:44 +09005940 /*
5941 * Check HT operation mode based on
5942 * IEEE 802.11 2012 8.4.2.59 HT Operation element.
5943 */
5944 if (tb[NL80211_MESHCONF_HT_OPMODE]) {
5945 ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
5946
5947 if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
5948 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
5949 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5950 return -EINVAL;
5951
5952 if ((ht_opmode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) &&
5953 (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5954 return -EINVAL;
5955
5956 switch (ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION) {
5957 case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
5958 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
5959 if (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT)
5960 return -EINVAL;
5961 break;
5962 case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
5963 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
5964 if (!(ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5965 return -EINVAL;
5966 break;
5967 }
5968 cfg->ht_opmode = ht_opmode;
5969 }
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005970 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
Marco Porschea54fba2013-01-07 16:04:48 +01005971 1, 65535, mask,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005972 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005973 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005974 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005975 mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005976 nl80211_check_u16);
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005977 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005978 dot11MeshHWMPconfirmationInterval,
5979 1, 65535, mask,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005980 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005981 nl80211_check_u16);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005982 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
5983 NL80211_MESH_POWER_ACTIVE,
5984 NL80211_MESH_POWER_MAX,
5985 mask, NL80211_MESHCONF_POWER_MODE,
Johannes Bergff9a71a2016-08-11 14:59:53 +02005986 nl80211_check_power_mode);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005987 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
5988 0, 65535, mask,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005989 NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
Masashi Honma31f909a2015-02-24 22:42:16 +09005990 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005991 mask, NL80211_MESHCONF_PLINK_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005992 nl80211_check_u32);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005993 if (mask_out)
5994 *mask_out = mask;
Javier Cardonac80d5452010-12-16 17:37:49 -08005995
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005996 return 0;
5997
5998#undef FILL_IN_MESH_PARAM_IF_SET
5999}
6000
Javier Cardonac80d5452010-12-16 17:37:49 -08006001static int nl80211_parse_mesh_setup(struct genl_info *info,
6002 struct mesh_setup *setup)
6003{
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006004 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Javier Cardonac80d5452010-12-16 17:37:49 -08006005 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
6006
6007 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
6008 return -EINVAL;
6009 if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX,
6010 info->attrs[NL80211_ATTR_MESH_SETUP],
6011 nl80211_mesh_setup_params_policy))
6012 return -EINVAL;
6013
Javier Cardonad299a1f2012-03-31 11:31:33 -07006014 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
6015 setup->sync_method =
6016 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
6017 IEEE80211_SYNC_METHOD_VENDOR :
6018 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
6019
Javier Cardonac80d5452010-12-16 17:37:49 -08006020 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
6021 setup->path_sel_proto =
6022 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
6023 IEEE80211_PATH_PROTOCOL_VENDOR :
6024 IEEE80211_PATH_PROTOCOL_HWMP;
6025
6026 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
6027 setup->path_metric =
6028 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
6029 IEEE80211_PATH_METRIC_VENDOR :
6030 IEEE80211_PATH_METRIC_AIRTIME;
6031
Javier Cardona581a8b02011-04-07 15:08:27 -07006032 if (tb[NL80211_MESH_SETUP_IE]) {
Javier Cardonac80d5452010-12-16 17:37:49 -08006033 struct nlattr *ieattr =
Javier Cardona581a8b02011-04-07 15:08:27 -07006034 tb[NL80211_MESH_SETUP_IE];
Javier Cardonac80d5452010-12-16 17:37:49 -08006035 if (!is_valid_ie_attr(ieattr))
6036 return -EINVAL;
Javier Cardona581a8b02011-04-07 15:08:27 -07006037 setup->ie = nla_data(ieattr);
6038 setup->ie_len = nla_len(ieattr);
Javier Cardonac80d5452010-12-16 17:37:49 -08006039 }
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006040 if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
6041 !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
6042 return -EINVAL;
6043 setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
Javier Cardonab130e5c2011-05-03 16:57:07 -07006044 setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
6045 setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006046 if (setup->is_secure)
6047 setup->user_mpm = true;
Javier Cardonac80d5452010-12-16 17:37:49 -08006048
Colleen Twitty6e16d902013-05-08 11:45:59 -07006049 if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
6050 if (!setup->user_mpm)
6051 return -EINVAL;
6052 setup->auth_id =
6053 nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
6054 }
6055
Javier Cardonac80d5452010-12-16 17:37:49 -08006056 return 0;
6057}
6058
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006059static int nl80211_update_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01006060 struct genl_info *info)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006061{
6062 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6063 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01006064 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006065 struct mesh_config cfg;
6066 u32 mask;
6067 int err;
6068
Johannes Berg29cbe682010-12-03 09:20:44 +01006069 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6070 return -EOPNOTSUPP;
6071
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006072 if (!rdev->ops->update_mesh_config)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006073 return -EOPNOTSUPP;
6074
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006075 err = nl80211_parse_mesh_config(info, &cfg, &mask);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006076 if (err)
6077 return err;
6078
Johannes Berg29cbe682010-12-03 09:20:44 +01006079 wdev_lock(wdev);
6080 if (!wdev->mesh_id_len)
6081 err = -ENOLINK;
6082
6083 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03006084 err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01006085
6086 wdev_unlock(wdev);
6087
6088 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006089}
6090
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006091static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
6092 struct sk_buff *msg)
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006093{
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006094 struct nlattr *nl_reg_rules;
6095 unsigned int i;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006096
Johannes Berg458f4f92012-12-06 15:47:38 +01006097 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
6098 (regdom->dfs_region &&
6099 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006100 goto nla_put_failure;
Johannes Berg458f4f92012-12-06 15:47:38 +01006101
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006102 nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
6103 if (!nl_reg_rules)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006104 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006105
Johannes Berg458f4f92012-12-06 15:47:38 +01006106 for (i = 0; i < regdom->n_reg_rules; i++) {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006107 struct nlattr *nl_reg_rule;
6108 const struct ieee80211_reg_rule *reg_rule;
6109 const struct ieee80211_freq_range *freq_range;
6110 const struct ieee80211_power_rule *power_rule;
Janusz Dziedzic97524822014-01-30 09:52:20 +01006111 unsigned int max_bandwidth_khz;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006112
Johannes Berg458f4f92012-12-06 15:47:38 +01006113 reg_rule = &regdom->reg_rules[i];
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006114 freq_range = &reg_rule->freq_range;
6115 power_rule = &reg_rule->power_rule;
6116
6117 nl_reg_rule = nla_nest_start(msg, i);
6118 if (!nl_reg_rule)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006119 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006120
Janusz Dziedzic97524822014-01-30 09:52:20 +01006121 max_bandwidth_khz = freq_range->max_bandwidth_khz;
6122 if (!max_bandwidth_khz)
6123 max_bandwidth_khz = reg_get_max_bandwidth(regdom,
6124 reg_rule);
6125
David S. Miller9360ffd2012-03-29 04:41:26 -04006126 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
6127 reg_rule->flags) ||
6128 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
6129 freq_range->start_freq_khz) ||
6130 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
6131 freq_range->end_freq_khz) ||
6132 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
Janusz Dziedzic97524822014-01-30 09:52:20 +01006133 max_bandwidth_khz) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04006134 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
6135 power_rule->max_antenna_gain) ||
6136 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
Janusz Dziedzic089027e2014-02-21 19:46:12 +01006137 power_rule->max_eirp) ||
6138 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
6139 reg_rule->dfs_cac_ms))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006140 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006141
6142 nla_nest_end(msg, nl_reg_rule);
6143 }
6144
6145 nla_nest_end(msg, nl_reg_rules);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006146 return 0;
6147
6148nla_put_failure:
6149 return -EMSGSIZE;
6150}
6151
6152static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
6153{
6154 const struct ieee80211_regdomain *regdom = NULL;
6155 struct cfg80211_registered_device *rdev;
6156 struct wiphy *wiphy = NULL;
6157 struct sk_buff *msg;
6158 void *hdr;
6159
6160 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6161 if (!msg)
6162 return -ENOBUFS;
6163
6164 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
6165 NL80211_CMD_GET_REG);
6166 if (!hdr)
6167 goto put_failure;
6168
6169 if (info->attrs[NL80211_ATTR_WIPHY]) {
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006170 bool self_managed;
6171
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006172 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
6173 if (IS_ERR(rdev)) {
6174 nlmsg_free(msg);
6175 return PTR_ERR(rdev);
6176 }
6177
6178 wiphy = &rdev->wiphy;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006179 self_managed = wiphy->regulatory_flags &
6180 REGULATORY_WIPHY_SELF_MANAGED;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006181 regdom = get_wiphy_regdom(wiphy);
6182
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006183 /* a self-managed-reg device must have a private regdom */
6184 if (WARN_ON(!regdom && self_managed)) {
6185 nlmsg_free(msg);
6186 return -EINVAL;
6187 }
6188
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006189 if (regdom &&
6190 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6191 goto nla_put_failure;
6192 }
6193
6194 if (!wiphy && reg_last_request_cell_base() &&
6195 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6196 NL80211_USER_REG_HINT_CELL_BASE))
6197 goto nla_put_failure;
6198
6199 rcu_read_lock();
6200
6201 if (!regdom)
6202 regdom = rcu_dereference(cfg80211_regdomain);
6203
6204 if (nl80211_put_regdom(regdom, msg))
6205 goto nla_put_failure_rcu;
6206
6207 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006208
6209 genlmsg_end(msg, hdr);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006210 return genlmsg_reply(msg, info);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006211
Johannes Berg458f4f92012-12-06 15:47:38 +01006212nla_put_failure_rcu:
6213 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006214nla_put_failure:
6215 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01006216put_failure:
Yuri Ershovd080e272010-06-29 15:08:07 +04006217 nlmsg_free(msg);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006218 return -EMSGSIZE;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006219}
6220
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006221static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
6222 u32 seq, int flags, struct wiphy *wiphy,
6223 const struct ieee80211_regdomain *regdom)
6224{
6225 void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
6226 NL80211_CMD_GET_REG);
6227
6228 if (!hdr)
6229 return -1;
6230
6231 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
6232
6233 if (nl80211_put_regdom(regdom, msg))
6234 goto nla_put_failure;
6235
6236 if (!wiphy && reg_last_request_cell_base() &&
6237 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6238 NL80211_USER_REG_HINT_CELL_BASE))
6239 goto nla_put_failure;
6240
6241 if (wiphy &&
6242 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6243 goto nla_put_failure;
6244
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006245 if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
6246 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
6247 goto nla_put_failure;
6248
Johannes Berg053c0952015-01-16 22:09:00 +01006249 genlmsg_end(msg, hdr);
6250 return 0;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006251
6252nla_put_failure:
6253 genlmsg_cancel(msg, hdr);
6254 return -EMSGSIZE;
6255}
6256
6257static int nl80211_get_reg_dump(struct sk_buff *skb,
6258 struct netlink_callback *cb)
6259{
6260 const struct ieee80211_regdomain *regdom = NULL;
6261 struct cfg80211_registered_device *rdev;
6262 int err, reg_idx, start = cb->args[2];
6263
6264 rtnl_lock();
6265
6266 if (cfg80211_regdomain && start == 0) {
6267 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6268 NLM_F_MULTI, NULL,
6269 rtnl_dereference(cfg80211_regdomain));
6270 if (err < 0)
6271 goto out_err;
6272 }
6273
6274 /* the global regdom is idx 0 */
6275 reg_idx = 1;
6276 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
6277 regdom = get_wiphy_regdom(&rdev->wiphy);
6278 if (!regdom)
6279 continue;
6280
6281 if (++reg_idx <= start)
6282 continue;
6283
6284 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6285 NLM_F_MULTI, &rdev->wiphy, regdom);
6286 if (err < 0) {
6287 reg_idx--;
6288 break;
6289 }
6290 }
6291
6292 cb->args[2] = reg_idx;
6293 err = skb->len;
6294out_err:
6295 rtnl_unlock();
6296 return err;
6297}
6298
Johannes Bergb6863032015-10-15 09:25:18 +02006299#ifdef CONFIG_CFG80211_CRDA_SUPPORT
6300static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
6301 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
6302 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
6303 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
6304 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
6305 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
6306 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
6307 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
6308};
6309
6310static int parse_reg_rule(struct nlattr *tb[],
6311 struct ieee80211_reg_rule *reg_rule)
6312{
6313 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
6314 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
6315
6316 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
6317 return -EINVAL;
6318 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
6319 return -EINVAL;
6320 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
6321 return -EINVAL;
6322 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
6323 return -EINVAL;
6324 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
6325 return -EINVAL;
6326
6327 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
6328
6329 freq_range->start_freq_khz =
6330 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
6331 freq_range->end_freq_khz =
6332 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
6333 freq_range->max_bandwidth_khz =
6334 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
6335
6336 power_rule->max_eirp =
6337 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
6338
6339 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
6340 power_rule->max_antenna_gain =
6341 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
6342
6343 if (tb[NL80211_ATTR_DFS_CAC_TIME])
6344 reg_rule->dfs_cac_ms =
6345 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
6346
6347 return 0;
6348}
6349
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006350static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
6351{
6352 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
6353 struct nlattr *nl_reg_rule;
Johannes Bergea372c52014-11-28 14:54:31 +01006354 char *alpha2;
6355 int rem_reg_rules, r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006356 u32 num_rules = 0, rule_idx = 0, size_of_regd;
Luis R. Rodriguez4c7d3982013-11-13 18:54:02 +01006357 enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
Johannes Bergea372c52014-11-28 14:54:31 +01006358 struct ieee80211_regdomain *rd;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006359
6360 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
6361 return -EINVAL;
6362
6363 if (!info->attrs[NL80211_ATTR_REG_RULES])
6364 return -EINVAL;
6365
6366 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
6367
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006368 if (info->attrs[NL80211_ATTR_DFS_REGION])
6369 dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
6370
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006371 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006372 rem_reg_rules) {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006373 num_rules++;
6374 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
Luis R. Rodriguez4776c6e2009-05-13 17:04:39 -04006375 return -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006376 }
6377
Luis R. Rodrigueze4387682013-11-05 09:18:01 -08006378 if (!reg_is_valid_request(alpha2))
6379 return -EINVAL;
6380
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006381 size_of_regd = sizeof(struct ieee80211_regdomain) +
Johannes Berg1a919312012-12-03 17:21:11 +01006382 num_rules * sizeof(struct ieee80211_reg_rule);
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006383
6384 rd = kzalloc(size_of_regd, GFP_KERNEL);
Johannes Berg6913b492012-12-04 00:48:59 +01006385 if (!rd)
6386 return -ENOMEM;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006387
6388 rd->n_reg_rules = num_rules;
6389 rd->alpha2[0] = alpha2[0];
6390 rd->alpha2[1] = alpha2[1];
6391
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006392 /*
6393 * Disable DFS master mode if the DFS region was
6394 * not supported or known on this kernel.
6395 */
6396 if (reg_supported_dfs_region(dfs_region))
6397 rd->dfs_region = dfs_region;
6398
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006399 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006400 rem_reg_rules) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006401 r = nla_parse_nested(tb, NL80211_REG_RULE_ATTR_MAX,
6402 nl_reg_rule, reg_rule_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01006403 if (r)
6404 goto bad_reg;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006405 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
6406 if (r)
6407 goto bad_reg;
6408
6409 rule_idx++;
6410
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006411 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
6412 r = -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006413 goto bad_reg;
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006414 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006415 }
6416
Johannes Berg06627992016-06-09 10:40:09 +02006417 /* set_regdom takes ownership of rd */
6418 return set_regdom(rd, REGD_SOURCE_CRDA);
Johannes Bergd2372b32008-10-24 20:32:20 +02006419 bad_reg:
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006420 kfree(rd);
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006421 return r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006422}
Johannes Bergb6863032015-10-15 09:25:18 +02006423#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006424
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006425static int validate_scan_freqs(struct nlattr *freqs)
6426{
6427 struct nlattr *attr1, *attr2;
6428 int n_channels = 0, tmp1, tmp2;
6429
6430 nla_for_each_nested(attr1, freqs, tmp1) {
6431 n_channels++;
6432 /*
6433 * Some hardware has a limited channel list for
6434 * scanning, and it is pretty much nonsensical
6435 * to scan for a channel twice, so disallow that
6436 * and don't require drivers to check that the
6437 * channel list they get isn't longer than what
6438 * they can scan, as long as they can scan all
6439 * the channels they registered at once.
6440 */
6441 nla_for_each_nested(attr2, freqs, tmp2)
6442 if (attr1 != attr2 &&
6443 nla_get_u32(attr1) == nla_get_u32(attr2))
6444 return 0;
6445 }
6446
6447 return n_channels;
6448}
6449
Johannes Berg57fbcce2016-04-12 15:56:15 +02006450static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
Arend van Spriel38de03d2016-03-02 20:37:18 +01006451{
Johannes Berg57fbcce2016-04-12 15:56:15 +02006452 return b < NUM_NL80211_BANDS && wiphy->bands[b];
Arend van Spriel38de03d2016-03-02 20:37:18 +01006453}
6454
6455static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
6456 struct cfg80211_bss_selection *bss_select)
6457{
6458 struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
6459 struct nlattr *nest;
6460 int err;
6461 bool found = false;
6462 int i;
6463
6464 /* only process one nested attribute */
6465 nest = nla_data(nla);
6466 if (!nla_ok(nest, nla_len(nest)))
6467 return -EINVAL;
6468
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006469 err = nla_parse_nested(attr, NL80211_BSS_SELECT_ATTR_MAX, nest,
6470 nl80211_bss_select_policy);
Arend van Spriel38de03d2016-03-02 20:37:18 +01006471 if (err)
6472 return err;
6473
6474 /* only one attribute may be given */
6475 for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
6476 if (attr[i]) {
6477 if (found)
6478 return -EINVAL;
6479 found = true;
6480 }
6481 }
6482
6483 bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
6484
6485 if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
6486 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
6487
6488 if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
6489 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
6490 bss_select->param.band_pref =
6491 nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
6492 if (!is_band_valid(wiphy, bss_select->param.band_pref))
6493 return -EINVAL;
6494 }
6495
6496 if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
6497 struct nl80211_bss_select_rssi_adjust *adj_param;
6498
6499 adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
6500 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
6501 bss_select->param.adjust.band = adj_param->band;
6502 bss_select->param.adjust.delta = adj_param->delta;
6503 if (!is_band_valid(wiphy, bss_select->param.adjust.band))
6504 return -EINVAL;
6505 }
6506
6507 /* user-space did not provide behaviour attribute */
6508 if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
6509 return -EINVAL;
6510
6511 if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
6512 return -EINVAL;
6513
6514 return 0;
6515}
6516
Johannes Bergad2b26a2014-06-12 21:39:05 +02006517static int nl80211_parse_random_mac(struct nlattr **attrs,
6518 u8 *mac_addr, u8 *mac_addr_mask)
6519{
6520 int i;
6521
6522 if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
Joe Perchesd2beae12015-03-02 19:54:58 -08006523 eth_zero_addr(mac_addr);
6524 eth_zero_addr(mac_addr_mask);
Johannes Bergad2b26a2014-06-12 21:39:05 +02006525 mac_addr[0] = 0x2;
6526 mac_addr_mask[0] = 0x3;
6527
6528 return 0;
6529 }
6530
6531 /* need both or none */
6532 if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
6533 return -EINVAL;
6534
6535 memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
6536 memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
6537
6538 /* don't allow or configure an mcast address */
6539 if (!is_multicast_ether_addr(mac_addr_mask) ||
6540 is_multicast_ether_addr(mac_addr))
6541 return -EINVAL;
6542
6543 /*
6544 * allow users to pass a MAC address that has bits set outside
6545 * of the mask, but don't bother drivers with having to deal
6546 * with such bits
6547 */
6548 for (i = 0; i < ETH_ALEN; i++)
6549 mac_addr[i] &= mac_addr_mask[i];
6550
6551 return 0;
6552}
6553
Johannes Berg2a519312009-02-10 21:25:55 +01006554static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
6555{
Johannes Berg4c476992010-10-04 21:36:35 +02006556 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfd014282012-06-18 19:17:03 +02006557 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2a519312009-02-10 21:25:55 +01006558 struct cfg80211_scan_request *request;
Johannes Berg2a519312009-02-10 21:25:55 +01006559 struct nlattr *attr;
6560 struct wiphy *wiphy;
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006561 int err, tmp, n_ssids = 0, n_channels, i;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006562 size_t ie_len;
Johannes Berg2a519312009-02-10 21:25:55 +01006563
Johannes Bergf4a11bb2009-03-27 12:40:28 +01006564 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
6565 return -EINVAL;
6566
Johannes Berg79c97e92009-07-07 03:56:12 +02006567 wiphy = &rdev->wiphy;
Johannes Berg2a519312009-02-10 21:25:55 +01006568
Ayala Bekercb3b7d82016-09-20 17:31:13 +03006569 if (wdev->iftype == NL80211_IFTYPE_NAN)
6570 return -EOPNOTSUPP;
6571
Johannes Berg4c476992010-10-04 21:36:35 +02006572 if (!rdev->ops->scan)
6573 return -EOPNOTSUPP;
Johannes Berg2a519312009-02-10 21:25:55 +01006574
Johannes Bergf9d15d12014-01-22 11:14:19 +02006575 if (rdev->scan_req || rdev->scan_msg) {
Johannes Bergf9f47522013-03-19 15:04:07 +01006576 err = -EBUSY;
6577 goto unlock;
6578 }
Johannes Berg2a519312009-02-10 21:25:55 +01006579
6580 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006581 n_channels = validate_scan_freqs(
6582 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Johannes Bergf9f47522013-03-19 15:04:07 +01006583 if (!n_channels) {
6584 err = -EINVAL;
6585 goto unlock;
6586 }
Johannes Berg2a519312009-02-10 21:25:55 +01006587 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006588 n_channels = ieee80211_get_num_supported_channels(wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01006589 }
6590
6591 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
6592 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
6593 n_ssids++;
6594
Johannes Bergf9f47522013-03-19 15:04:07 +01006595 if (n_ssids > wiphy->max_scan_ssids) {
6596 err = -EINVAL;
6597 goto unlock;
6598 }
Johannes Berg2a519312009-02-10 21:25:55 +01006599
Jouni Malinen70692ad2009-02-16 19:39:13 +02006600 if (info->attrs[NL80211_ATTR_IE])
6601 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6602 else
6603 ie_len = 0;
6604
Johannes Bergf9f47522013-03-19 15:04:07 +01006605 if (ie_len > wiphy->max_scan_ie_len) {
6606 err = -EINVAL;
6607 goto unlock;
6608 }
Johannes Berg18a83652009-03-31 12:12:05 +02006609
Johannes Berg2a519312009-02-10 21:25:55 +01006610 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03006611 + sizeof(*request->ssids) * n_ssids
6612 + sizeof(*request->channels) * n_channels
Jouni Malinen70692ad2009-02-16 19:39:13 +02006613 + ie_len, GFP_KERNEL);
Johannes Bergf9f47522013-03-19 15:04:07 +01006614 if (!request) {
6615 err = -ENOMEM;
6616 goto unlock;
6617 }
Johannes Berg2a519312009-02-10 21:25:55 +01006618
Johannes Berg2a519312009-02-10 21:25:55 +01006619 if (n_ssids)
Johannes Berg5ba63532009-08-07 17:54:07 +02006620 request->ssids = (void *)&request->channels[n_channels];
Johannes Berg2a519312009-02-10 21:25:55 +01006621 request->n_ssids = n_ssids;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006622 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01006623 if (n_ssids)
Jouni Malinen70692ad2009-02-16 19:39:13 +02006624 request->ie = (void *)(request->ssids + n_ssids);
6625 else
6626 request->ie = (void *)(request->channels + n_channels);
6627 }
Johannes Berg2a519312009-02-10 21:25:55 +01006628
Johannes Berg584991d2009-11-02 13:32:03 +01006629 i = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01006630 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
6631 /* user specified, bail out if channel not found */
Johannes Berg2a519312009-02-10 21:25:55 +01006632 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
Johannes Berg584991d2009-11-02 13:32:03 +01006633 struct ieee80211_channel *chan;
6634
6635 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
6636
6637 if (!chan) {
Johannes Berg2a519312009-02-10 21:25:55 +01006638 err = -EINVAL;
6639 goto out_free;
6640 }
Johannes Berg584991d2009-11-02 13:32:03 +01006641
6642 /* ignore disabled channels */
6643 if (chan->flags & IEEE80211_CHAN_DISABLED)
6644 continue;
6645
6646 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006647 i++;
6648 }
6649 } else {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006650 enum nl80211_band band;
Johannes Berg34850ab2011-07-18 18:08:35 +02006651
Johannes Berg2a519312009-02-10 21:25:55 +01006652 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006653 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Johannes Berg2a519312009-02-10 21:25:55 +01006654 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07006655
Johannes Berg2a519312009-02-10 21:25:55 +01006656 if (!wiphy->bands[band])
6657 continue;
6658 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
Johannes Berg584991d2009-11-02 13:32:03 +01006659 struct ieee80211_channel *chan;
6660
6661 chan = &wiphy->bands[band]->channels[j];
6662
6663 if (chan->flags & IEEE80211_CHAN_DISABLED)
6664 continue;
6665
6666 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006667 i++;
6668 }
6669 }
6670 }
6671
Johannes Berg584991d2009-11-02 13:32:03 +01006672 if (!i) {
6673 err = -EINVAL;
6674 goto out_free;
6675 }
6676
6677 request->n_channels = i;
6678
Johannes Berg2a519312009-02-10 21:25:55 +01006679 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01006680 if (n_ssids) {
Johannes Berg2a519312009-02-10 21:25:55 +01006681 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03006682 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Johannes Berg2a519312009-02-10 21:25:55 +01006683 err = -EINVAL;
6684 goto out_free;
6685 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03006686 request->ssids[i].ssid_len = nla_len(attr);
Johannes Berg2a519312009-02-10 21:25:55 +01006687 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
Johannes Berg2a519312009-02-10 21:25:55 +01006688 i++;
6689 }
6690 }
6691
Jouni Malinen70692ad2009-02-16 19:39:13 +02006692 if (info->attrs[NL80211_ATTR_IE]) {
6693 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Johannes Bergde95a54b2009-04-01 11:58:36 +02006694 memcpy((void *)request->ie,
6695 nla_data(info->attrs[NL80211_ATTR_IE]),
Jouni Malinen70692ad2009-02-16 19:39:13 +02006696 request->ie_len);
6697 }
6698
Johannes Berg57fbcce2016-04-12 15:56:15 +02006699 for (i = 0; i < NUM_NL80211_BANDS; i++)
Johannes Berga401d2b2011-07-20 00:52:16 +02006700 if (wiphy->bands[i])
6701 request->rates[i] =
6702 (1 << wiphy->bands[i]->n_bitrates) - 1;
Johannes Berg34850ab2011-07-18 18:08:35 +02006703
6704 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
6705 nla_for_each_nested(attr,
6706 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
6707 tmp) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006708 enum nl80211_band band = nla_type(attr);
Johannes Berg34850ab2011-07-18 18:08:35 +02006709
Johannes Berg57fbcce2016-04-12 15:56:15 +02006710 if (band < 0 || band >= NUM_NL80211_BANDS) {
Johannes Berg34850ab2011-07-18 18:08:35 +02006711 err = -EINVAL;
6712 goto out_free;
6713 }
Felix Fietkau1b09cd82013-11-20 19:40:41 +01006714
6715 if (!wiphy->bands[band])
6716 continue;
6717
Johannes Berg34850ab2011-07-18 18:08:35 +02006718 err = ieee80211_get_ratemask(wiphy->bands[band],
6719 nla_data(attr),
6720 nla_len(attr),
6721 &request->rates[band]);
6722 if (err)
6723 goto out_free;
6724 }
6725 }
6726
Avraham Stern1d762502016-07-05 17:10:13 +03006727 if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
6728 if (!wiphy_ext_feature_isset(wiphy,
6729 NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
6730 err = -EOPNOTSUPP;
6731 goto out_free;
6732 }
6733
6734 request->duration =
6735 nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
6736 request->duration_mandatory =
6737 nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
6738 }
6739
Sam Leffler46856bb2012-10-11 21:03:32 -07006740 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
Sam Lefflered4737712012-10-11 21:03:31 -07006741 request->flags = nla_get_u32(
6742 info->attrs[NL80211_ATTR_SCAN_FLAGS]);
Johannes Berg00c3a6e2013-10-26 17:14:38 +02006743 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
6744 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
Sam Leffler46856bb2012-10-11 21:03:32 -07006745 err = -EOPNOTSUPP;
6746 goto out_free;
6747 }
Johannes Bergad2b26a2014-06-12 21:39:05 +02006748
6749 if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
6750 if (!(wiphy->features &
6751 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) {
6752 err = -EOPNOTSUPP;
6753 goto out_free;
6754 }
6755
6756 if (wdev->current_bss) {
6757 err = -EOPNOTSUPP;
6758 goto out_free;
6759 }
6760
6761 err = nl80211_parse_random_mac(info->attrs,
6762 request->mac_addr,
6763 request->mac_addr_mask);
6764 if (err)
6765 goto out_free;
6766 }
Sam Leffler46856bb2012-10-11 21:03:32 -07006767 }
Sam Lefflered4737712012-10-11 21:03:31 -07006768
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05306769 request->no_cck =
6770 nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
6771
Vamsi Krishna2fa436b2016-12-02 23:59:08 +02006772 /* Initial implementation used NL80211_ATTR_MAC to set the specific
6773 * BSSID to scan for. This was problematic because that same attribute
6774 * was already used for another purpose (local random MAC address). The
6775 * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
6776 * compatibility with older userspace components, also use the
6777 * NL80211_ATTR_MAC value here if it can be determined to be used for
6778 * the specific BSSID use case instead of the random MAC address
6779 * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
6780 */
6781 if (info->attrs[NL80211_ATTR_BSSID])
6782 memcpy(request->bssid,
6783 nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
6784 else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
6785 info->attrs[NL80211_ATTR_MAC])
Jouni Malinen818965d2016-02-26 22:12:47 +02006786 memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
6787 ETH_ALEN);
6788 else
6789 eth_broadcast_addr(request->bssid);
6790
Johannes Bergfd014282012-06-18 19:17:03 +02006791 request->wdev = wdev;
Johannes Berg79c97e92009-07-07 03:56:12 +02006792 request->wiphy = &rdev->wiphy;
Sam Leffler15d60302012-10-11 21:03:34 -07006793 request->scan_start = jiffies;
Johannes Berg2a519312009-02-10 21:25:55 +01006794
Johannes Berg79c97e92009-07-07 03:56:12 +02006795 rdev->scan_req = request;
Hila Gonene35e4d22012-06-27 17:19:42 +03006796 err = rdev_scan(rdev, request);
Johannes Berg2a519312009-02-10 21:25:55 +01006797
Johannes Berg463d0182009-07-14 00:33:35 +02006798 if (!err) {
Johannes Bergfd014282012-06-18 19:17:03 +02006799 nl80211_send_scan_start(rdev, wdev);
6800 if (wdev->netdev)
6801 dev_hold(wdev->netdev);
Johannes Berg4c476992010-10-04 21:36:35 +02006802 } else {
Johannes Berg2a519312009-02-10 21:25:55 +01006803 out_free:
Johannes Berg79c97e92009-07-07 03:56:12 +02006804 rdev->scan_req = NULL;
Johannes Berg2a519312009-02-10 21:25:55 +01006805 kfree(request);
6806 }
Johannes Berg3b858752009-03-12 09:55:09 +01006807
Johannes Bergf9f47522013-03-19 15:04:07 +01006808 unlock:
Johannes Berg2a519312009-02-10 21:25:55 +01006809 return err;
6810}
6811
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +05306812static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
6813{
6814 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6815 struct wireless_dev *wdev = info->user_ptr[1];
6816
6817 if (!rdev->ops->abort_scan)
6818 return -EOPNOTSUPP;
6819
6820 if (rdev->scan_msg)
6821 return 0;
6822
6823 if (!rdev->scan_req)
6824 return -ENOENT;
6825
6826 rdev_abort_scan(rdev, wdev);
6827 return 0;
6828}
6829
Avraham Stern3b06d272015-10-12 09:51:34 +03006830static int
6831nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
6832 struct cfg80211_sched_scan_request *request,
6833 struct nlattr **attrs)
6834{
6835 int tmp, err, i = 0;
6836 struct nlattr *attr;
6837
6838 if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
6839 u32 interval;
6840
6841 /*
6842 * If scan plans are not specified,
Arend Van Spriel5a88de52016-11-17 09:02:40 +00006843 * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
Avraham Stern3b06d272015-10-12 09:51:34 +03006844 * case one scan plan will be set with the specified scan
6845 * interval and infinite number of iterations.
6846 */
Avraham Stern3b06d272015-10-12 09:51:34 +03006847 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
6848 if (!interval)
6849 return -EINVAL;
6850
6851 request->scan_plans[0].interval =
6852 DIV_ROUND_UP(interval, MSEC_PER_SEC);
6853 if (!request->scan_plans[0].interval)
6854 return -EINVAL;
6855
6856 if (request->scan_plans[0].interval >
6857 wiphy->max_sched_scan_plan_interval)
6858 request->scan_plans[0].interval =
6859 wiphy->max_sched_scan_plan_interval;
6860
6861 return 0;
6862 }
6863
6864 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
6865 struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
6866
6867 if (WARN_ON(i >= n_plans))
6868 return -EINVAL;
6869
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006870 err = nla_parse_nested(plan, NL80211_SCHED_SCAN_PLAN_MAX,
6871 attr, nl80211_plan_policy);
Avraham Stern3b06d272015-10-12 09:51:34 +03006872 if (err)
6873 return err;
6874
6875 if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
6876 return -EINVAL;
6877
6878 request->scan_plans[i].interval =
6879 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
6880 if (!request->scan_plans[i].interval ||
6881 request->scan_plans[i].interval >
6882 wiphy->max_sched_scan_plan_interval)
6883 return -EINVAL;
6884
6885 if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
6886 request->scan_plans[i].iterations =
6887 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
6888 if (!request->scan_plans[i].iterations ||
6889 (request->scan_plans[i].iterations >
6890 wiphy->max_sched_scan_plan_iterations))
6891 return -EINVAL;
6892 } else if (i < n_plans - 1) {
6893 /*
6894 * All scan plans but the last one must specify
6895 * a finite number of iterations
6896 */
6897 return -EINVAL;
6898 }
6899
6900 i++;
6901 }
6902
6903 /*
6904 * The last scan plan must not specify the number of
6905 * iterations, it is supposed to run infinitely
6906 */
6907 if (request->scan_plans[n_plans - 1].iterations)
6908 return -EINVAL;
6909
6910 return 0;
6911}
6912
Luciano Coelho256da022014-11-10 16:13:46 +02006913static struct cfg80211_sched_scan_request *
Johannes Bergad2b26a2014-06-12 21:39:05 +02006914nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00006915 struct nlattr **attrs, int max_match_sets)
Luciano Coelho807f8a82011-05-11 17:09:35 +03006916{
6917 struct cfg80211_sched_scan_request *request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006918 struct nlattr *attr;
Avraham Stern3b06d272015-10-12 09:51:34 +03006919 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02006920 enum nl80211_band band;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006921 size_t ie_len;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006922 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
Johannes Bergea73cbc2014-01-24 10:53:53 +01006923 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006924
Luciano Coelho256da022014-11-10 16:13:46 +02006925 if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
6926 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006927
Luciano Coelho256da022014-11-10 16:13:46 +02006928 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03006929 n_channels = validate_scan_freqs(
Luciano Coelho256da022014-11-10 16:13:46 +02006930 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006931 if (!n_channels)
Luciano Coelho256da022014-11-10 16:13:46 +02006932 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006933 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006934 n_channels = ieee80211_get_num_supported_channels(wiphy);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006935 }
6936
Luciano Coelho256da022014-11-10 16:13:46 +02006937 if (attrs[NL80211_ATTR_SCAN_SSIDS])
6938 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03006939 tmp)
6940 n_ssids++;
6941
Luciano Coelho93b6aa62011-07-13 14:57:28 +03006942 if (n_ssids > wiphy->max_sched_scan_ssids)
Luciano Coelho256da022014-11-10 16:13:46 +02006943 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006944
Johannes Bergea73cbc2014-01-24 10:53:53 +01006945 /*
6946 * First, count the number of 'real' matchsets. Due to an issue with
6947 * the old implementation, matchsets containing only the RSSI attribute
6948 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
6949 * RSSI for all matchsets, rather than their own matchset for reporting
6950 * all APs with a strong RSSI. This is needed to be compatible with
6951 * older userspace that treated a matchset with only the RSSI as the
6952 * global RSSI for all other matchsets - if there are other matchsets.
6953 */
Luciano Coelho256da022014-11-10 16:13:46 +02006954 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006955 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02006956 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Johannes Bergea73cbc2014-01-24 10:53:53 +01006957 tmp) {
6958 struct nlattr *rssi;
6959
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006960 err = nla_parse_nested(tb,
6961 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
6962 attr, nl80211_match_policy);
Johannes Bergea73cbc2014-01-24 10:53:53 +01006963 if (err)
Luciano Coelho256da022014-11-10 16:13:46 +02006964 return ERR_PTR(err);
Johannes Bergea73cbc2014-01-24 10:53:53 +01006965 /* add other standalone attributes here */
6966 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
6967 n_match_sets++;
6968 continue;
6969 }
6970 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
6971 if (rssi)
6972 default_match_rssi = nla_get_s32(rssi);
6973 }
6974 }
6975
6976 /* However, if there's no other matchset, add the RSSI one */
6977 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
6978 n_match_sets = 1;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006979
Arend Van Sprielaad1e812017-01-27 12:27:44 +00006980 if (n_match_sets > max_match_sets)
Luciano Coelho256da022014-11-10 16:13:46 +02006981 return ERR_PTR(-EINVAL);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006982
Luciano Coelho256da022014-11-10 16:13:46 +02006983 if (attrs[NL80211_ATTR_IE])
6984 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006985 else
6986 ie_len = 0;
6987
Luciano Coelho5a865ba2011-07-13 14:57:29 +03006988 if (ie_len > wiphy->max_sched_scan_ie_len)
Luciano Coelho256da022014-11-10 16:13:46 +02006989 return ERR_PTR(-EINVAL);
Luciano Coelhoc10841c2011-06-30 08:32:41 +03006990
Avraham Stern3b06d272015-10-12 09:51:34 +03006991 if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
6992 /*
6993 * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
6994 * each scan plan already specifies its own interval
6995 */
6996 if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
6997 return ERR_PTR(-EINVAL);
6998
6999 nla_for_each_nested(attr,
7000 attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
7001 n_plans++;
7002 } else {
7003 /*
7004 * The scan interval attribute is kept for backward
7005 * compatibility. If no scan plans are specified and sched scan
7006 * interval is specified, one scan plan will be set with this
7007 * scan interval and infinite number of iterations.
7008 */
7009 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7010 return ERR_PTR(-EINVAL);
7011
7012 n_plans = 1;
7013 }
7014
7015 if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
7016 return ERR_PTR(-EINVAL);
7017
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007018 if (!wiphy_ext_feature_isset(
7019 wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
7020 (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
7021 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
7022 return ERR_PTR(-EINVAL);
7023
Luciano Coelho807f8a82011-05-11 17:09:35 +03007024 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007025 + sizeof(*request->ssids) * n_ssids
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007026 + sizeof(*request->match_sets) * n_match_sets
Avraham Stern3b06d272015-10-12 09:51:34 +03007027 + sizeof(*request->scan_plans) * n_plans
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007028 + sizeof(*request->channels) * n_channels
Luciano Coelho807f8a82011-05-11 17:09:35 +03007029 + ie_len, GFP_KERNEL);
Luciano Coelho256da022014-11-10 16:13:46 +02007030 if (!request)
7031 return ERR_PTR(-ENOMEM);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007032
7033 if (n_ssids)
7034 request->ssids = (void *)&request->channels[n_channels];
7035 request->n_ssids = n_ssids;
7036 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01007037 if (n_ssids)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007038 request->ie = (void *)(request->ssids + n_ssids);
7039 else
7040 request->ie = (void *)(request->channels + n_channels);
7041 }
7042
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007043 if (n_match_sets) {
7044 if (request->ie)
7045 request->match_sets = (void *)(request->ie + ie_len);
Johannes Berg13874e42015-01-23 11:25:20 +01007046 else if (n_ssids)
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007047 request->match_sets =
7048 (void *)(request->ssids + n_ssids);
7049 else
7050 request->match_sets =
7051 (void *)(request->channels + n_channels);
7052 }
7053 request->n_match_sets = n_match_sets;
7054
Avraham Stern3b06d272015-10-12 09:51:34 +03007055 if (n_match_sets)
7056 request->scan_plans = (void *)(request->match_sets +
7057 n_match_sets);
7058 else if (request->ie)
7059 request->scan_plans = (void *)(request->ie + ie_len);
7060 else if (n_ssids)
7061 request->scan_plans = (void *)(request->ssids + n_ssids);
7062 else
7063 request->scan_plans = (void *)(request->channels + n_channels);
7064
7065 request->n_scan_plans = n_plans;
7066
Luciano Coelho807f8a82011-05-11 17:09:35 +03007067 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007068 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007069 /* user specified, bail out if channel not found */
7070 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007071 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007072 tmp) {
7073 struct ieee80211_channel *chan;
7074
7075 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
7076
7077 if (!chan) {
7078 err = -EINVAL;
7079 goto out_free;
7080 }
7081
7082 /* ignore disabled channels */
7083 if (chan->flags & IEEE80211_CHAN_DISABLED)
7084 continue;
7085
7086 request->channels[i] = chan;
7087 i++;
7088 }
7089 } else {
7090 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007091 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007092 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007093
Luciano Coelho807f8a82011-05-11 17:09:35 +03007094 if (!wiphy->bands[band])
7095 continue;
7096 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
7097 struct ieee80211_channel *chan;
7098
7099 chan = &wiphy->bands[band]->channels[j];
7100
7101 if (chan->flags & IEEE80211_CHAN_DISABLED)
7102 continue;
7103
7104 request->channels[i] = chan;
7105 i++;
7106 }
7107 }
7108 }
7109
7110 if (!i) {
7111 err = -EINVAL;
7112 goto out_free;
7113 }
7114
7115 request->n_channels = i;
7116
7117 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01007118 if (n_ssids) {
Luciano Coelho256da022014-11-10 16:13:46 +02007119 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007120 tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03007121 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007122 err = -EINVAL;
7123 goto out_free;
7124 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03007125 request->ssids[i].ssid_len = nla_len(attr);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007126 memcpy(request->ssids[i].ssid, nla_data(attr),
7127 nla_len(attr));
Luciano Coelho807f8a82011-05-11 17:09:35 +03007128 i++;
7129 }
7130 }
7131
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007132 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007133 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007134 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007135 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007136 tmp) {
Thomas Pedersen88e920b2012-06-21 11:09:54 -07007137 struct nlattr *ssid, *rssi;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007138
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007139 err = nla_parse_nested(tb,
7140 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
7141 attr, nl80211_match_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01007142 if (err)
7143 goto out_free;
Johannes Berg4a4ab0d2012-06-13 11:17:11 +02007144 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007145 if (ssid) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01007146 if (WARN_ON(i >= n_match_sets)) {
7147 /* this indicates a programming error,
7148 * the loop above should have verified
7149 * things properly
7150 */
7151 err = -EINVAL;
7152 goto out_free;
7153 }
7154
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007155 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
7156 err = -EINVAL;
7157 goto out_free;
7158 }
7159 memcpy(request->match_sets[i].ssid.ssid,
7160 nla_data(ssid), nla_len(ssid));
7161 request->match_sets[i].ssid.ssid_len =
7162 nla_len(ssid);
Kirtika Ruchandani56ab3642016-05-29 19:54:10 -07007163 /* special attribute - old implementation w/a */
Johannes Bergea73cbc2014-01-24 10:53:53 +01007164 request->match_sets[i].rssi_thold =
7165 default_match_rssi;
7166 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7167 if (rssi)
7168 request->match_sets[i].rssi_thold =
7169 nla_get_s32(rssi);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007170 }
7171 i++;
7172 }
Johannes Bergea73cbc2014-01-24 10:53:53 +01007173
7174 /* there was no other matchset, so the RSSI one is alone */
Luciano Coelhof89f46c2014-12-01 11:32:09 +02007175 if (i == 0 && n_match_sets)
Johannes Bergea73cbc2014-01-24 10:53:53 +01007176 request->match_sets[0].rssi_thold = default_match_rssi;
7177
7178 request->min_rssi_thold = INT_MAX;
7179 for (i = 0; i < n_match_sets; i++)
7180 request->min_rssi_thold =
7181 min(request->match_sets[i].rssi_thold,
7182 request->min_rssi_thold);
7183 } else {
7184 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007185 }
7186
Johannes Berg9900e482014-02-04 21:01:25 +01007187 if (ie_len) {
7188 request->ie_len = ie_len;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007189 memcpy((void *)request->ie,
Luciano Coelho256da022014-11-10 16:13:46 +02007190 nla_data(attrs[NL80211_ATTR_IE]),
Luciano Coelho807f8a82011-05-11 17:09:35 +03007191 request->ie_len);
7192 }
7193
Luciano Coelho256da022014-11-10 16:13:46 +02007194 if (attrs[NL80211_ATTR_SCAN_FLAGS]) {
Sam Lefflered4737712012-10-11 21:03:31 -07007195 request->flags = nla_get_u32(
Luciano Coelho256da022014-11-10 16:13:46 +02007196 attrs[NL80211_ATTR_SCAN_FLAGS]);
Johannes Berg00c3a6e2013-10-26 17:14:38 +02007197 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
7198 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
Sam Leffler46856bb2012-10-11 21:03:32 -07007199 err = -EOPNOTSUPP;
7200 goto out_free;
7201 }
Johannes Bergad2b26a2014-06-12 21:39:05 +02007202
7203 if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
7204 u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7205
7206 if (!wdev) /* must be net-detect */
7207 flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7208
7209 if (!(wiphy->features & flg)) {
7210 err = -EOPNOTSUPP;
7211 goto out_free;
7212 }
7213
7214 if (wdev && wdev->current_bss) {
7215 err = -EOPNOTSUPP;
7216 goto out_free;
7217 }
7218
7219 err = nl80211_parse_random_mac(attrs, request->mac_addr,
7220 request->mac_addr_mask);
7221 if (err)
7222 goto out_free;
7223 }
Sam Leffler46856bb2012-10-11 21:03:32 -07007224 }
Sam Lefflered4737712012-10-11 21:03:31 -07007225
Luciano Coelho9c748932015-01-16 16:04:09 +02007226 if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
7227 request->delay =
7228 nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
7229
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007230 if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
7231 request->relative_rssi = nla_get_s8(
7232 attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
7233 request->relative_rssi_set = true;
7234 }
7235
7236 if (request->relative_rssi_set &&
7237 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
7238 struct nl80211_bss_select_rssi_adjust *rssi_adjust;
7239
7240 rssi_adjust = nla_data(
7241 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
7242 request->rssi_adjust.band = rssi_adjust->band;
7243 request->rssi_adjust.delta = rssi_adjust->delta;
7244 if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
7245 err = -EINVAL;
7246 goto out_free;
7247 }
7248 }
7249
Avraham Stern3b06d272015-10-12 09:51:34 +03007250 err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
7251 if (err)
7252 goto out_free;
7253
Sam Leffler15d60302012-10-11 21:03:34 -07007254 request->scan_start = jiffies;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007255
Luciano Coelho256da022014-11-10 16:13:46 +02007256 return request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007257
7258out_free:
7259 kfree(request);
Luciano Coelho256da022014-11-10 16:13:46 +02007260 return ERR_PTR(err);
7261}
7262
7263static int nl80211_start_sched_scan(struct sk_buff *skb,
7264 struct genl_info *info)
7265{
7266 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7267 struct net_device *dev = info->user_ptr[1];
Johannes Bergad2b26a2014-06-12 21:39:05 +02007268 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007269 struct cfg80211_sched_scan_request *sched_scan_req;
Luciano Coelho256da022014-11-10 16:13:46 +02007270 int err;
7271
7272 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
7273 !rdev->ops->sched_scan_start)
7274 return -EOPNOTSUPP;
7275
7276 if (rdev->sched_scan_req)
7277 return -EINPROGRESS;
7278
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007279 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007280 info->attrs,
7281 rdev->wiphy.max_match_sets);
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007282
7283 err = PTR_ERR_OR_ZERO(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007284 if (err)
7285 goto out_err;
7286
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007287 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007288 if (err)
7289 goto out_free;
7290
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007291 sched_scan_req->dev = dev;
7292 sched_scan_req->wiphy = &rdev->wiphy;
7293
Jukka Rissanen93a1e862014-12-15 13:25:39 +02007294 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
7295 sched_scan_req->owner_nlportid = info->snd_portid;
7296
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007297 rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007298
7299 nl80211_send_sched_scan(rdev, dev,
7300 NL80211_CMD_START_SCHED_SCAN);
7301 return 0;
7302
7303out_free:
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007304 kfree(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007305out_err:
Luciano Coelho807f8a82011-05-11 17:09:35 +03007306 return err;
7307}
7308
7309static int nl80211_stop_sched_scan(struct sk_buff *skb,
7310 struct genl_info *info)
7311{
7312 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7313
7314 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
7315 !rdev->ops->sched_scan_stop)
7316 return -EOPNOTSUPP;
7317
Johannes Berg5fe231e2013-05-08 21:45:15 +02007318 return __cfg80211_stop_sched_scan(rdev, false);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007319}
7320
Simon Wunderlich04f39042013-02-08 18:16:19 +01007321static int nl80211_start_radar_detection(struct sk_buff *skb,
7322 struct genl_info *info)
7323{
7324 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7325 struct net_device *dev = info->user_ptr[1];
7326 struct wireless_dev *wdev = dev->ieee80211_ptr;
7327 struct cfg80211_chan_def chandef;
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007328 enum nl80211_dfs_regions dfs_region;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007329 unsigned int cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007330 int err;
7331
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007332 dfs_region = reg_get_dfs_region(wdev->wiphy);
7333 if (dfs_region == NL80211_DFS_UNSET)
7334 return -EINVAL;
7335
Simon Wunderlich04f39042013-02-08 18:16:19 +01007336 err = nl80211_parse_chandef(rdev, info, &chandef);
7337 if (err)
7338 return err;
7339
Simon Wunderlichff311bc2013-09-03 19:43:18 +02007340 if (netif_carrier_ok(dev))
7341 return -EBUSY;
7342
Simon Wunderlich04f39042013-02-08 18:16:19 +01007343 if (wdev->cac_started)
7344 return -EBUSY;
7345
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007346 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
Luciano Coelho00ec75f2014-05-15 13:05:39 +03007347 wdev->iftype);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007348 if (err < 0)
7349 return err;
7350
7351 if (err == 0)
7352 return -EINVAL;
7353
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +01007354 if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
Simon Wunderlich04f39042013-02-08 18:16:19 +01007355 return -EINVAL;
7356
7357 if (!rdev->ops->start_radar_detection)
7358 return -EOPNOTSUPP;
7359
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007360 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
7361 if (WARN_ON(!cac_time_ms))
7362 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
7363
Ilan Peera1056b1b2015-10-22 22:27:46 +03007364 err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007365 if (!err) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01007366 wdev->chandef = chandef;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007367 wdev->cac_started = true;
7368 wdev->cac_start_time = jiffies;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007369 wdev->cac_time_ms = cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007370 }
Simon Wunderlich04f39042013-02-08 18:16:19 +01007371 return err;
7372}
7373
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007374static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
7375{
7376 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7377 struct net_device *dev = info->user_ptr[1];
7378 struct wireless_dev *wdev = dev->ieee80211_ptr;
7379 struct cfg80211_csa_settings params;
7380 /* csa_attrs is defined static to avoid waste of stack size - this
7381 * function is called under RTNL lock, so this should not be a problem.
7382 */
7383 static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007384 int err;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007385 bool need_new_beacon = false;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007386 int len, i;
Luciano Coelho252e07c2014-10-08 09:48:34 +03007387 u32 cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007388
7389 if (!rdev->ops->channel_switch ||
7390 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
7391 return -EOPNOTSUPP;
7392
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007393 switch (dev->ieee80211_ptr->iftype) {
7394 case NL80211_IFTYPE_AP:
7395 case NL80211_IFTYPE_P2P_GO:
7396 need_new_beacon = true;
7397
7398 /* useless if AP is not running */
7399 if (!wdev->beacon_interval)
Johannes Berg1ff79df2014-01-22 10:05:27 +01007400 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007401 break;
7402 case NL80211_IFTYPE_ADHOC:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007403 if (!wdev->ssid_len)
7404 return -ENOTCONN;
7405 break;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07007406 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007407 if (!wdev->mesh_id_len)
7408 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007409 break;
7410 default:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007411 return -EOPNOTSUPP;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007412 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007413
7414 memset(&params, 0, sizeof(params));
7415
7416 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
7417 !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
7418 return -EINVAL;
7419
7420 /* only important for AP, IBSS and mesh create IEs internally */
Andrei Otcheretianskid0a361a2013-10-17 10:52:17 +02007421 if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007422 return -EINVAL;
7423
Luciano Coelho252e07c2014-10-08 09:48:34 +03007424 /* Even though the attribute is u32, the specification says
7425 * u8, so let's make sure we don't overflow.
7426 */
7427 cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
7428 if (cs_count > 255)
7429 return -EINVAL;
7430
7431 params.count = cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007432
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007433 if (!need_new_beacon)
7434 goto skip_beacons;
7435
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007436 err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
7437 if (err)
7438 return err;
7439
7440 err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
7441 info->attrs[NL80211_ATTR_CSA_IES],
7442 nl80211_policy);
7443 if (err)
7444 return err;
7445
7446 err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
7447 if (err)
7448 return err;
7449
7450 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
7451 return -EINVAL;
7452
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007453 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7454 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007455 return -EINVAL;
7456
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007457 params.n_counter_offsets_beacon = len / sizeof(u16);
7458 if (rdev->wiphy.max_num_csa_counters &&
7459 (params.n_counter_offsets_beacon >
7460 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007461 return -EINVAL;
7462
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007463 params.counter_offsets_beacon =
7464 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7465
7466 /* sanity checks - counters should fit and be the same */
7467 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
7468 u16 offset = params.counter_offsets_beacon[i];
7469
7470 if (offset >= params.beacon_csa.tail_len)
7471 return -EINVAL;
7472
7473 if (params.beacon_csa.tail[offset] != params.count)
7474 return -EINVAL;
7475 }
7476
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007477 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007478 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7479 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007480 return -EINVAL;
7481
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007482 params.n_counter_offsets_presp = len / sizeof(u16);
7483 if (rdev->wiphy.max_num_csa_counters &&
Johannes Bergad5987b2016-09-13 15:53:55 +02007484 (params.n_counter_offsets_presp >
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007485 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007486 return -EINVAL;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007487
7488 params.counter_offsets_presp =
7489 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7490
7491 /* sanity checks - counters should fit and be the same */
7492 for (i = 0; i < params.n_counter_offsets_presp; i++) {
7493 u16 offset = params.counter_offsets_presp[i];
7494
7495 if (offset >= params.beacon_csa.probe_resp_len)
7496 return -EINVAL;
7497
7498 if (params.beacon_csa.probe_resp[offset] !=
7499 params.count)
7500 return -EINVAL;
7501 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007502 }
7503
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007504skip_beacons:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007505 err = nl80211_parse_chandef(rdev, info, &params.chandef);
7506 if (err)
7507 return err;
7508
Arik Nemtsov923b3522015-07-08 15:41:44 +03007509 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
7510 wdev->iftype))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007511 return -EINVAL;
7512
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007513 err = cfg80211_chandef_dfs_required(wdev->wiphy,
7514 &params.chandef,
7515 wdev->iftype);
7516 if (err < 0)
7517 return err;
7518
Fabian Frederickdcc6c2f2014-10-25 17:57:35 +02007519 if (err > 0)
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007520 params.radar_required = true;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007521
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007522 if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
7523 params.block_tx = true;
7524
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007525 wdev_lock(wdev);
7526 err = rdev_channel_switch(rdev, dev, &params);
7527 wdev_unlock(wdev);
7528
7529 return err;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007530}
7531
Johannes Berg9720bb32011-06-21 09:45:33 +02007532static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
7533 u32 seq, int flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007534 struct cfg80211_registered_device *rdev,
Johannes Berg48ab9052009-07-10 18:42:31 +02007535 struct wireless_dev *wdev,
7536 struct cfg80211_internal_bss *intbss)
Johannes Berg2a519312009-02-10 21:25:55 +01007537{
Johannes Berg48ab9052009-07-10 18:42:31 +02007538 struct cfg80211_bss *res = &intbss->pub;
Johannes Berg9caf0362012-11-29 01:25:20 +01007539 const struct cfg80211_bss_ies *ies;
Johannes Berg2a519312009-02-10 21:25:55 +01007540 void *hdr;
7541 struct nlattr *bss;
Johannes Berg48ab9052009-07-10 18:42:31 +02007542
7543 ASSERT_WDEV_LOCK(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007544
Eric W. Biederman15e47302012-09-07 20:12:54 +00007545 hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007546 NL80211_CMD_NEW_SCAN_RESULTS);
7547 if (!hdr)
7548 return -1;
7549
Johannes Berg9720bb32011-06-21 09:45:33 +02007550 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
7551
Johannes Berg97990a02013-04-19 01:02:55 +02007552 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
7553 goto nla_put_failure;
7554 if (wdev->netdev &&
David S. Miller9360ffd2012-03-29 04:41:26 -04007555 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
7556 goto nla_put_failure;
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007557 if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
7558 NL80211_ATTR_PAD))
Johannes Berg97990a02013-04-19 01:02:55 +02007559 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007560
7561 bss = nla_nest_start(msg, NL80211_ATTR_BSS);
7562 if (!bss)
7563 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04007564 if ((!is_zero_ether_addr(res->bssid) &&
Johannes Berg9caf0362012-11-29 01:25:20 +01007565 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
David S. Miller9360ffd2012-03-29 04:41:26 -04007566 goto nla_put_failure;
Johannes Berg9caf0362012-11-29 01:25:20 +01007567
7568 rcu_read_lock();
Johannes Berg0e227082014-08-12 20:34:30 +02007569 /* indicate whether we have probe response data or not */
7570 if (rcu_access_pointer(res->proberesp_ies) &&
7571 nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
7572 goto fail_unlock_rcu;
7573
7574 /* this pointer prefers to be pointed to probe response data
7575 * but is always valid
7576 */
Johannes Berg9caf0362012-11-29 01:25:20 +01007577 ies = rcu_dereference(res->ies);
Johannes Berg8cef2c92013-02-05 16:54:31 +01007578 if (ies) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007579 if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
7580 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007581 goto fail_unlock_rcu;
Johannes Berg8cef2c92013-02-05 16:54:31 +01007582 if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
7583 ies->len, ies->data))
7584 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007585 }
Johannes Berg0e227082014-08-12 20:34:30 +02007586
7587 /* and this pointer is always (unless driver didn't know) beacon data */
Johannes Berg9caf0362012-11-29 01:25:20 +01007588 ies = rcu_dereference(res->beacon_ies);
Johannes Berg0e227082014-08-12 20:34:30 +02007589 if (ies && ies->from_beacon) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007590 if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
7591 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007592 goto fail_unlock_rcu;
7593 if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
7594 ies->len, ies->data))
7595 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007596 }
7597 rcu_read_unlock();
7598
David S. Miller9360ffd2012-03-29 04:41:26 -04007599 if (res->beacon_interval &&
7600 nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
7601 goto nla_put_failure;
7602 if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
7603 nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
Simon Wunderlichdcd6eac2013-07-08 16:55:49 +02007604 nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007605 nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
7606 jiffies_to_msecs(jiffies - intbss->ts)))
7607 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007608
Avraham Stern1d762502016-07-05 17:10:13 +03007609 if (intbss->parent_tsf &&
7610 (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
7611 intbss->parent_tsf, NL80211_BSS_PAD) ||
7612 nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
7613 intbss->parent_bssid)))
7614 goto nla_put_failure;
7615
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007616 if (intbss->ts_boottime &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007617 nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
7618 intbss->ts_boottime, NL80211_BSS_PAD))
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007619 goto nla_put_failure;
7620
Johannes Berg77965c972009-02-18 18:45:06 +01007621 switch (rdev->wiphy.signal_type) {
Johannes Berg2a519312009-02-10 21:25:55 +01007622 case CFG80211_SIGNAL_TYPE_MBM:
David S. Miller9360ffd2012-03-29 04:41:26 -04007623 if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
7624 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007625 break;
7626 case CFG80211_SIGNAL_TYPE_UNSPEC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007627 if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
7628 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007629 break;
7630 default:
7631 break;
7632 }
7633
Johannes Berg48ab9052009-07-10 18:42:31 +02007634 switch (wdev->iftype) {
Johannes Berg074ac8d2010-09-16 14:58:22 +02007635 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg48ab9052009-07-10 18:42:31 +02007636 case NL80211_IFTYPE_STATION:
David S. Miller9360ffd2012-03-29 04:41:26 -04007637 if (intbss == wdev->current_bss &&
7638 nla_put_u32(msg, NL80211_BSS_STATUS,
7639 NL80211_BSS_STATUS_ASSOCIATED))
7640 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007641 break;
7642 case NL80211_IFTYPE_ADHOC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007643 if (intbss == wdev->current_bss &&
7644 nla_put_u32(msg, NL80211_BSS_STATUS,
7645 NL80211_BSS_STATUS_IBSS_JOINED))
7646 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007647 break;
7648 default:
7649 break;
7650 }
7651
Johannes Berg2a519312009-02-10 21:25:55 +01007652 nla_nest_end(msg, bss);
7653
Johannes Berg053c0952015-01-16 22:09:00 +01007654 genlmsg_end(msg, hdr);
7655 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007656
Johannes Berg8cef2c92013-02-05 16:54:31 +01007657 fail_unlock_rcu:
7658 rcu_read_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01007659 nla_put_failure:
7660 genlmsg_cancel(msg, hdr);
7661 return -EMSGSIZE;
7662}
7663
Johannes Berg97990a02013-04-19 01:02:55 +02007664static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
Johannes Berg2a519312009-02-10 21:25:55 +01007665{
Johannes Berg48ab9052009-07-10 18:42:31 +02007666 struct cfg80211_registered_device *rdev;
Johannes Berg2a519312009-02-10 21:25:55 +01007667 struct cfg80211_internal_bss *scan;
Johannes Berg48ab9052009-07-10 18:42:31 +02007668 struct wireless_dev *wdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007669 int start = cb->args[2], idx = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007670 int err;
7671
Johannes Berg97990a02013-04-19 01:02:55 +02007672 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007673 if (err)
7674 return err;
Johannes Berg2a519312009-02-10 21:25:55 +01007675
Johannes Berg48ab9052009-07-10 18:42:31 +02007676 wdev_lock(wdev);
7677 spin_lock_bh(&rdev->bss_lock);
7678 cfg80211_bss_expire(rdev);
7679
Johannes Berg9720bb32011-06-21 09:45:33 +02007680 cb->seq = rdev->bss_generation;
7681
Johannes Berg48ab9052009-07-10 18:42:31 +02007682 list_for_each_entry(scan, &rdev->bss_list, list) {
Johannes Berg2a519312009-02-10 21:25:55 +01007683 if (++idx <= start)
7684 continue;
Johannes Berg9720bb32011-06-21 09:45:33 +02007685 if (nl80211_send_bss(skb, cb,
Johannes Berg2a519312009-02-10 21:25:55 +01007686 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg48ab9052009-07-10 18:42:31 +02007687 rdev, wdev, scan) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +01007688 idx--;
Johannes Berg67748892010-10-04 21:14:06 +02007689 break;
Johannes Berg2a519312009-02-10 21:25:55 +01007690 }
7691 }
7692
Johannes Berg48ab9052009-07-10 18:42:31 +02007693 spin_unlock_bh(&rdev->bss_lock);
7694 wdev_unlock(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007695
Johannes Berg97990a02013-04-19 01:02:55 +02007696 cb->args[2] = idx;
7697 nl80211_finish_wdev_dump(rdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007698
Johannes Berg67748892010-10-04 21:14:06 +02007699 return skb->len;
Johannes Berg2a519312009-02-10 21:25:55 +01007700}
7701
Eric W. Biederman15e47302012-09-07 20:12:54 +00007702static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007703 int flags, struct net_device *dev,
7704 bool allow_radio_stats,
7705 struct survey_info *survey)
Holger Schurig61fa7132009-11-11 12:25:40 +01007706{
7707 void *hdr;
7708 struct nlattr *infoattr;
7709
Johannes Berg11f78ac2014-11-14 16:43:50 +01007710 /* skip radio stats if userspace didn't request them */
7711 if (!survey->channel && !allow_radio_stats)
7712 return 0;
7713
Eric W. Biederman15e47302012-09-07 20:12:54 +00007714 hdr = nl80211hdr_put(msg, portid, seq, flags,
Holger Schurig61fa7132009-11-11 12:25:40 +01007715 NL80211_CMD_NEW_SURVEY_RESULTS);
7716 if (!hdr)
7717 return -ENOMEM;
7718
David S. Miller9360ffd2012-03-29 04:41:26 -04007719 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
7720 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007721
7722 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
7723 if (!infoattr)
7724 goto nla_put_failure;
7725
Johannes Berg11f78ac2014-11-14 16:43:50 +01007726 if (survey->channel &&
7727 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
David S. Miller9360ffd2012-03-29 04:41:26 -04007728 survey->channel->center_freq))
7729 goto nla_put_failure;
7730
7731 if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
7732 nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
7733 goto nla_put_failure;
7734 if ((survey->filled & SURVEY_INFO_IN_USE) &&
7735 nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
7736 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007737 if ((survey->filled & SURVEY_INFO_TIME) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007738 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
7739 survey->time, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007740 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007741 if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007742 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
7743 survey->time_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007744 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007745 if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007746 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
7747 survey->time_ext_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007748 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007749 if ((survey->filled & SURVEY_INFO_TIME_RX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007750 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
7751 survey->time_rx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007752 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007753 if ((survey->filled & SURVEY_INFO_TIME_TX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007754 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
7755 survey->time_tx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007756 goto nla_put_failure;
Johannes Berg052536a2014-11-14 16:44:11 +01007757 if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007758 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
7759 survey->time_scan, NL80211_SURVEY_INFO_PAD))
Johannes Berg052536a2014-11-14 16:44:11 +01007760 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007761
7762 nla_nest_end(msg, infoattr);
7763
Johannes Berg053c0952015-01-16 22:09:00 +01007764 genlmsg_end(msg, hdr);
7765 return 0;
Holger Schurig61fa7132009-11-11 12:25:40 +01007766
7767 nla_put_failure:
7768 genlmsg_cancel(msg, hdr);
7769 return -EMSGSIZE;
7770}
7771
Johannes Berg11f78ac2014-11-14 16:43:50 +01007772static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
Holger Schurig61fa7132009-11-11 12:25:40 +01007773{
Johannes Bergc90c39d2016-10-24 14:40:01 +02007774 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Holger Schurig61fa7132009-11-11 12:25:40 +01007775 struct survey_info survey;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007776 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007777 struct wireless_dev *wdev;
7778 int survey_idx = cb->args[2];
Holger Schurig61fa7132009-11-11 12:25:40 +01007779 int res;
Johannes Berg11f78ac2014-11-14 16:43:50 +01007780 bool radio_stats;
Holger Schurig61fa7132009-11-11 12:25:40 +01007781
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007782 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007783 if (res)
7784 return res;
Holger Schurig61fa7132009-11-11 12:25:40 +01007785
Johannes Berg11f78ac2014-11-14 16:43:50 +01007786 /* prepare_wdev_dump parsed the attributes */
Johannes Bergc90c39d2016-10-24 14:40:01 +02007787 radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
Johannes Berg11f78ac2014-11-14 16:43:50 +01007788
Johannes Berg97990a02013-04-19 01:02:55 +02007789 if (!wdev->netdev) {
7790 res = -EINVAL;
7791 goto out_err;
7792 }
7793
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007794 if (!rdev->ops->dump_survey) {
Holger Schurig61fa7132009-11-11 12:25:40 +01007795 res = -EOPNOTSUPP;
7796 goto out_err;
7797 }
7798
7799 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007800 res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
Holger Schurig61fa7132009-11-11 12:25:40 +01007801 if (res == -ENOENT)
7802 break;
7803 if (res)
7804 goto out_err;
7805
Johannes Berg11f78ac2014-11-14 16:43:50 +01007806 /* don't send disabled channels, but do send non-channel data */
7807 if (survey.channel &&
7808 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
Luis R. Rodriguez180cdc72011-05-27 07:24:02 -07007809 survey_idx++;
7810 continue;
7811 }
7812
Holger Schurig61fa7132009-11-11 12:25:40 +01007813 if (nl80211_send_survey(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00007814 NETLINK_CB(cb->skb).portid,
Holger Schurig61fa7132009-11-11 12:25:40 +01007815 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007816 wdev->netdev, radio_stats, &survey) < 0)
Holger Schurig61fa7132009-11-11 12:25:40 +01007817 goto out;
7818 survey_idx++;
7819 }
7820
7821 out:
Johannes Berg97990a02013-04-19 01:02:55 +02007822 cb->args[2] = survey_idx;
Holger Schurig61fa7132009-11-11 12:25:40 +01007823 res = skb->len;
7824 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007825 nl80211_finish_wdev_dump(rdev);
Holger Schurig61fa7132009-11-11 12:25:40 +01007826 return res;
7827}
7828
Samuel Ortizb23aa672009-07-01 21:26:54 +02007829static bool nl80211_valid_wpa_versions(u32 wpa_versions)
7830{
7831 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
7832 NL80211_WPA_VERSION_2));
7833}
7834
Jouni Malinen636a5d32009-03-19 13:39:22 +02007835static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
7836{
Johannes Berg4c476992010-10-04 21:36:35 +02007837 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7838 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02007839 struct ieee80211_channel *chan;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007840 const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
7841 int err, ssid_len, ie_len = 0, auth_data_len = 0;
Johannes Berg19957bb2009-07-02 17:20:43 +02007842 enum nl80211_auth_type auth_type;
Johannes Bergfffd0932009-07-08 14:22:54 +02007843 struct key_parse key;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03007844 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007845
Johannes Bergf4a11bb2009-03-27 12:40:28 +01007846 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
7847 return -EINVAL;
7848
7849 if (!info->attrs[NL80211_ATTR_MAC])
7850 return -EINVAL;
7851
Jouni Malinen17780922009-03-27 20:52:47 +02007852 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
7853 return -EINVAL;
7854
Johannes Berg19957bb2009-07-02 17:20:43 +02007855 if (!info->attrs[NL80211_ATTR_SSID])
7856 return -EINVAL;
7857
7858 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
7859 return -EINVAL;
7860
Johannes Bergfffd0932009-07-08 14:22:54 +02007861 err = nl80211_parse_key(info, &key);
7862 if (err)
7863 return err;
7864
7865 if (key.idx >= 0) {
Johannes Berge31b8212010-10-05 19:39:30 +02007866 if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
7867 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02007868 if (!key.p.key || !key.p.key_len)
7869 return -EINVAL;
7870 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
7871 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
7872 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
7873 key.p.key_len != WLAN_KEY_LEN_WEP104))
7874 return -EINVAL;
Johannes Bergb6b55552016-09-13 16:25:58 +02007875 if (key.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +02007876 return -EINVAL;
7877 } else {
7878 key.p.key_len = 0;
7879 key.p.key = NULL;
7880 }
7881
Johannes Bergafea0b72010-08-10 09:46:42 +02007882 if (key.idx >= 0) {
7883 int i;
7884 bool ok = false;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007885
Johannes Bergafea0b72010-08-10 09:46:42 +02007886 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
7887 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
7888 ok = true;
7889 break;
7890 }
7891 }
Johannes Berg4c476992010-10-04 21:36:35 +02007892 if (!ok)
7893 return -EINVAL;
Johannes Bergafea0b72010-08-10 09:46:42 +02007894 }
7895
Johannes Berg4c476992010-10-04 21:36:35 +02007896 if (!rdev->ops->auth)
7897 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007898
Johannes Berg074ac8d2010-09-16 14:58:22 +02007899 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02007900 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
7901 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02007902
Johannes Berg19957bb2009-07-02 17:20:43 +02007903 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen664834d2014-01-15 00:01:44 +02007904 chan = nl80211_get_valid_chan(&rdev->wiphy,
7905 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
7906 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02007907 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007908
Johannes Berg19957bb2009-07-02 17:20:43 +02007909 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
7910 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
7911
7912 if (info->attrs[NL80211_ATTR_IE]) {
7913 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
7914 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
7915 }
7916
7917 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03007918 if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
Johannes Berg4c476992010-10-04 21:36:35 +02007919 return -EINVAL;
Johannes Berg19957bb2009-07-02 17:20:43 +02007920
Jouni Malinen63181062016-10-27 00:42:02 +03007921 if ((auth_type == NL80211_AUTHTYPE_SAE ||
7922 auth_type == NL80211_AUTHTYPE_FILS_SK ||
7923 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
7924 auth_type == NL80211_AUTHTYPE_FILS_PK) &&
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007925 !info->attrs[NL80211_ATTR_AUTH_DATA])
Jouni Malinene39e5b52012-09-30 19:29:39 +03007926 return -EINVAL;
7927
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007928 if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
Jouni Malinen63181062016-10-27 00:42:02 +03007929 if (auth_type != NL80211_AUTHTYPE_SAE &&
7930 auth_type != NL80211_AUTHTYPE_FILS_SK &&
7931 auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
7932 auth_type != NL80211_AUTHTYPE_FILS_PK)
Jouni Malinene39e5b52012-09-30 19:29:39 +03007933 return -EINVAL;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007934 auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
7935 auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03007936 /* need to include at least Auth Transaction and Status Code */
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007937 if (auth_data_len < 4)
Jouni Malinene39e5b52012-09-30 19:29:39 +03007938 return -EINVAL;
7939 }
7940
Jouni Malinend5cdfac2010-04-04 09:37:19 +03007941 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
7942
Johannes Berg95de8172012-01-20 13:55:25 +01007943 /*
7944 * Since we no longer track auth state, ignore
7945 * requests to only change local state.
7946 */
7947 if (local_state_change)
7948 return 0;
7949
Johannes Berg91bf9b22013-05-15 17:44:01 +02007950 wdev_lock(dev->ieee80211_ptr);
7951 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
7952 ssid, ssid_len, ie, ie_len,
7953 key.p.key, key.p.key_len, key.idx,
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007954 auth_data, auth_data_len);
Johannes Berg91bf9b22013-05-15 17:44:01 +02007955 wdev_unlock(dev->ieee80211_ptr);
7956 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007957}
7958
Johannes Bergc0692b82010-08-27 14:26:53 +03007959static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
7960 struct genl_info *info,
Johannes Berg3dc27d22009-07-02 21:36:37 +02007961 struct cfg80211_crypto_settings *settings,
7962 int cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02007963{
Johannes Bergc0b2bbd2009-07-25 16:54:36 +02007964 memset(settings, 0, sizeof(*settings));
7965
Samuel Ortizb23aa672009-07-01 21:26:54 +02007966 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
7967
Johannes Bergc0692b82010-08-27 14:26:53 +03007968 if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
7969 u16 proto;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007970
Johannes Bergc0692b82010-08-27 14:26:53 +03007971 proto = nla_get_u16(
7972 info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
7973 settings->control_port_ethertype = cpu_to_be16(proto);
7974 if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
7975 proto != ETH_P_PAE)
7976 return -EINVAL;
7977 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
7978 settings->control_port_no_encrypt = true;
7979 } else
7980 settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
7981
Samuel Ortizb23aa672009-07-01 21:26:54 +02007982 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
7983 void *data;
7984 int len, i;
7985
7986 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
7987 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
7988 settings->n_ciphers_pairwise = len / sizeof(u32);
7989
7990 if (len % sizeof(u32))
7991 return -EINVAL;
7992
Johannes Berg3dc27d22009-07-02 21:36:37 +02007993 if (settings->n_ciphers_pairwise > cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02007994 return -EINVAL;
7995
7996 memcpy(settings->ciphers_pairwise, data, len);
7997
7998 for (i = 0; i < settings->n_ciphers_pairwise; i++)
Jouni Malinen38ba3c52011-09-21 18:14:56 +03007999 if (!cfg80211_supported_cipher_suite(
8000 &rdev->wiphy,
Samuel Ortizb23aa672009-07-01 21:26:54 +02008001 settings->ciphers_pairwise[i]))
8002 return -EINVAL;
8003 }
8004
8005 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
8006 settings->cipher_group =
8007 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008008 if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
8009 settings->cipher_group))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008010 return -EINVAL;
8011 }
8012
8013 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
8014 settings->wpa_versions =
8015 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
8016 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
8017 return -EINVAL;
8018 }
8019
8020 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
8021 void *data;
Jouni Malinen6d302402011-09-21 18:11:33 +03008022 int len;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008023
8024 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
8025 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
8026 settings->n_akm_suites = len / sizeof(u32);
8027
8028 if (len % sizeof(u32))
8029 return -EINVAL;
8030
Jouni Malinen1b9ca022011-09-21 16:13:07 +03008031 if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
8032 return -EINVAL;
8033
Samuel Ortizb23aa672009-07-01 21:26:54 +02008034 memcpy(settings->akm_suites, data, len);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008035 }
8036
8037 return 0;
8038}
8039
Jouni Malinen636a5d32009-03-19 13:39:22 +02008040static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
8041{
Johannes Berg4c476992010-10-04 21:36:35 +02008042 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8043 struct net_device *dev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02008044 struct ieee80211_channel *chan;
Johannes Bergf62fab72013-02-21 20:09:09 +01008045 struct cfg80211_assoc_request req = {};
8046 const u8 *bssid, *ssid;
8047 int err, ssid_len = 0;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008048
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008049 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8050 return -EINVAL;
8051
8052 if (!info->attrs[NL80211_ATTR_MAC] ||
Johannes Berg19957bb2009-07-02 17:20:43 +02008053 !info->attrs[NL80211_ATTR_SSID] ||
8054 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008055 return -EINVAL;
8056
Johannes Berg4c476992010-10-04 21:36:35 +02008057 if (!rdev->ops->assoc)
8058 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008059
Johannes Berg074ac8d2010-09-16 14:58:22 +02008060 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008061 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8062 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008063
Johannes Berg19957bb2009-07-02 17:20:43 +02008064 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008065
Jouni Malinen664834d2014-01-15 00:01:44 +02008066 chan = nl80211_get_valid_chan(&rdev->wiphy,
8067 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8068 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02008069 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008070
Johannes Berg19957bb2009-07-02 17:20:43 +02008071 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8072 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008073
8074 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008075 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8076 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008077 }
8078
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008079 if (info->attrs[NL80211_ATTR_USE_MFP]) {
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008080 enum nl80211_mfp mfp =
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008081 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008082 if (mfp == NL80211_MFP_REQUIRED)
Johannes Bergf62fab72013-02-21 20:09:09 +01008083 req.use_mfp = true;
Johannes Berg4c476992010-10-04 21:36:35 +02008084 else if (mfp != NL80211_MFP_NO)
8085 return -EINVAL;
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008086 }
8087
Johannes Berg3e5d7642009-07-07 14:37:26 +02008088 if (info->attrs[NL80211_ATTR_PREV_BSSID])
Johannes Bergf62fab72013-02-21 20:09:09 +01008089 req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
Johannes Berg3e5d7642009-07-07 14:37:26 +02008090
Ben Greear7e7c8922011-11-18 11:31:59 -08008091 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008092 req.flags |= ASSOC_REQ_DISABLE_HT;
Ben Greear7e7c8922011-11-18 11:31:59 -08008093
8094 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008095 memcpy(&req.ht_capa_mask,
8096 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8097 sizeof(req.ht_capa_mask));
Ben Greear7e7c8922011-11-18 11:31:59 -08008098
8099 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008100 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Ben Greear7e7c8922011-11-18 11:31:59 -08008101 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008102 memcpy(&req.ht_capa,
8103 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8104 sizeof(req.ht_capa));
Ben Greear7e7c8922011-11-18 11:31:59 -08008105 }
8106
Johannes Bergee2aca32013-02-21 17:36:01 +01008107 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008108 req.flags |= ASSOC_REQ_DISABLE_VHT;
Johannes Bergee2aca32013-02-21 17:36:01 +01008109
8110 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008111 memcpy(&req.vht_capa_mask,
8112 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8113 sizeof(req.vht_capa_mask));
Johannes Bergee2aca32013-02-21 17:36:01 +01008114
8115 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008116 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergee2aca32013-02-21 17:36:01 +01008117 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008118 memcpy(&req.vht_capa,
8119 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8120 sizeof(req.vht_capa));
Johannes Bergee2aca32013-02-21 17:36:01 +01008121 }
8122
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008123 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008124 if (!((rdev->wiphy.features &
8125 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8126 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8127 !wiphy_ext_feature_isset(&rdev->wiphy,
8128 NL80211_EXT_FEATURE_RRM))
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008129 return -EINVAL;
8130 req.flags |= ASSOC_REQ_USE_RRM;
8131 }
8132
Jouni Malinen348bd452016-10-27 00:42:03 +03008133 if (info->attrs[NL80211_ATTR_FILS_KEK]) {
8134 req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
8135 req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
8136 if (!info->attrs[NL80211_ATTR_FILS_NONCES])
8137 return -EINVAL;
8138 req.fils_nonces =
8139 nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
8140 }
8141
Johannes Bergf62fab72013-02-21 20:09:09 +01008142 err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008143 if (!err) {
8144 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008145
Johannes Bergf62fab72013-02-21 20:09:09 +01008146 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
8147 ssid, ssid_len, &req);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008148
8149 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8150 dev->ieee80211_ptr->conn_owner_nlportid =
8151 info->snd_portid;
8152 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8153 bssid, ETH_ALEN);
8154 }
8155
Johannes Berg91bf9b22013-05-15 17:44:01 +02008156 wdev_unlock(dev->ieee80211_ptr);
8157 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008158
Jouni Malinen636a5d32009-03-19 13:39:22 +02008159 return err;
8160}
8161
8162static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
8163{
Johannes Berg4c476992010-10-04 21:36:35 +02008164 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8165 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008166 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008167 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008168 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008169 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008170
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008171 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8172 return -EINVAL;
8173
8174 if (!info->attrs[NL80211_ATTR_MAC])
8175 return -EINVAL;
8176
8177 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8178 return -EINVAL;
8179
Johannes Berg4c476992010-10-04 21:36:35 +02008180 if (!rdev->ops->deauth)
8181 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008182
Johannes Berg074ac8d2010-09-16 14:58:22 +02008183 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008184 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8185 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008186
Johannes Berg19957bb2009-07-02 17:20:43 +02008187 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008188
Johannes Berg19957bb2009-07-02 17:20:43 +02008189 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8190 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008191 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008192 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008193 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008194
8195 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008196 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8197 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008198 }
8199
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008200 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8201
Johannes Berg91bf9b22013-05-15 17:44:01 +02008202 wdev_lock(dev->ieee80211_ptr);
8203 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
8204 local_state_change);
8205 wdev_unlock(dev->ieee80211_ptr);
8206 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008207}
8208
8209static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
8210{
Johannes Berg4c476992010-10-04 21:36:35 +02008211 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8212 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008213 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008214 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008215 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008216 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008217
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008218 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8219 return -EINVAL;
8220
8221 if (!info->attrs[NL80211_ATTR_MAC])
8222 return -EINVAL;
8223
8224 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8225 return -EINVAL;
8226
Johannes Berg4c476992010-10-04 21:36:35 +02008227 if (!rdev->ops->disassoc)
8228 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008229
Johannes Berg074ac8d2010-09-16 14:58:22 +02008230 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008231 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8232 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008233
Johannes Berg19957bb2009-07-02 17:20:43 +02008234 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008235
Johannes Berg19957bb2009-07-02 17:20:43 +02008236 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8237 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008238 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008239 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008240 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008241
8242 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008243 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8244 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008245 }
8246
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008247 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8248
Johannes Berg91bf9b22013-05-15 17:44:01 +02008249 wdev_lock(dev->ieee80211_ptr);
8250 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
8251 local_state_change);
8252 wdev_unlock(dev->ieee80211_ptr);
8253 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008254}
8255
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008256static bool
8257nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
Johannes Berg57fbcce2016-04-12 15:56:15 +02008258 int mcast_rate[NUM_NL80211_BANDS],
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008259 int rateval)
8260{
8261 struct wiphy *wiphy = &rdev->wiphy;
8262 bool found = false;
8263 int band, i;
8264
Johannes Berg57fbcce2016-04-12 15:56:15 +02008265 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008266 struct ieee80211_supported_band *sband;
8267
8268 sband = wiphy->bands[band];
8269 if (!sband)
8270 continue;
8271
8272 for (i = 0; i < sband->n_bitrates; i++) {
8273 if (sband->bitrates[i].bitrate == rateval) {
8274 mcast_rate[band] = i + 1;
8275 found = true;
8276 break;
8277 }
8278 }
8279 }
8280
8281 return found;
8282}
8283
Johannes Berg04a773a2009-04-19 21:24:32 +02008284static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
8285{
Johannes Berg4c476992010-10-04 21:36:35 +02008286 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8287 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008288 struct cfg80211_ibss_params ibss;
8289 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008290 struct cfg80211_cached_keys *connkeys = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +02008291 int err;
8292
Johannes Berg8e30bc52009-04-22 17:45:38 +02008293 memset(&ibss, 0, sizeof(ibss));
8294
Johannes Berg04a773a2009-04-19 21:24:32 +02008295 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8296 return -EINVAL;
8297
Johannes Berg683b6d32012-11-08 21:25:48 +01008298 if (!info->attrs[NL80211_ATTR_SSID] ||
Johannes Berg04a773a2009-04-19 21:24:32 +02008299 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8300 return -EINVAL;
8301
Johannes Berg8e30bc52009-04-22 17:45:38 +02008302 ibss.beacon_interval = 100;
8303
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308304 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
Johannes Berg8e30bc52009-04-22 17:45:38 +02008305 ibss.beacon_interval =
8306 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308307
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05308308 err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
8309 ibss.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308310 if (err)
8311 return err;
Johannes Berg8e30bc52009-04-22 17:45:38 +02008312
Johannes Berg4c476992010-10-04 21:36:35 +02008313 if (!rdev->ops->join_ibss)
8314 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008315
Johannes Berg4c476992010-10-04 21:36:35 +02008316 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8317 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008318
Johannes Berg79c97e92009-07-07 03:56:12 +02008319 wiphy = &rdev->wiphy;
Johannes Berg04a773a2009-04-19 21:24:32 +02008320
Johannes Berg39193492011-09-16 13:45:25 +02008321 if (info->attrs[NL80211_ATTR_MAC]) {
Johannes Berg04a773a2009-04-19 21:24:32 +02008322 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg39193492011-09-16 13:45:25 +02008323
8324 if (!is_valid_ether_addr(ibss.bssid))
8325 return -EINVAL;
8326 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008327 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8328 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8329
8330 if (info->attrs[NL80211_ATTR_IE]) {
8331 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8332 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8333 }
8334
Johannes Berg683b6d32012-11-08 21:25:48 +01008335 err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
8336 if (err)
8337 return err;
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008338
Ilan Peer174e0cd2014-02-23 09:13:01 +02008339 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
8340 NL80211_IFTYPE_ADHOC))
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008341 return -EINVAL;
8342
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008343 switch (ibss.chandef.width) {
Simon Wunderlichbf372642013-07-08 16:55:58 +02008344 case NL80211_CHAN_WIDTH_5:
8345 case NL80211_CHAN_WIDTH_10:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008346 case NL80211_CHAN_WIDTH_20_NOHT:
8347 break;
8348 case NL80211_CHAN_WIDTH_20:
8349 case NL80211_CHAN_WIDTH_40:
Janusz.Dziedzic@tieto.comffc11992015-02-21 16:52:39 +01008350 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8351 return -EINVAL;
8352 break;
8353 case NL80211_CHAN_WIDTH_80:
8354 case NL80211_CHAN_WIDTH_80P80:
8355 case NL80211_CHAN_WIDTH_160:
8356 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8357 return -EINVAL;
8358 if (!wiphy_ext_feature_isset(&rdev->wiphy,
8359 NL80211_EXT_FEATURE_VHT_IBSS))
8360 return -EINVAL;
8361 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008362 default:
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008363 return -EINVAL;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008364 }
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008365
Johannes Berg04a773a2009-04-19 21:24:32 +02008366 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
Johannes Bergfffd0932009-07-08 14:22:54 +02008367 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg04a773a2009-04-19 21:24:32 +02008368
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008369 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
8370 u8 *rates =
8371 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8372 int n_rates =
8373 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8374 struct ieee80211_supported_band *sband =
Johannes Berg683b6d32012-11-08 21:25:48 +01008375 wiphy->bands[ibss.chandef.chan->band];
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008376
Johannes Berg34850ab2011-07-18 18:08:35 +02008377 err = ieee80211_get_ratemask(sband, rates, n_rates,
8378 &ibss.basic_rates);
8379 if (err)
8380 return err;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008381 }
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008382
Simon Wunderlich803768f2013-06-28 10:39:58 +02008383 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8384 memcpy(&ibss.ht_capa_mask,
8385 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8386 sizeof(ibss.ht_capa_mask));
8387
8388 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
8389 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8390 return -EINVAL;
8391 memcpy(&ibss.ht_capa,
8392 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8393 sizeof(ibss.ht_capa));
8394 }
8395
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008396 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
8397 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
8398 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
8399 return -EINVAL;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008400
Johannes Berg4c476992010-10-04 21:36:35 +02008401 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Sujith Manoharande7044e2012-10-18 10:19:28 +05308402 bool no_ht = false;
8403
Johannes Berg4c476992010-10-04 21:36:35 +02008404 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308405 info->attrs[NL80211_ATTR_KEYS],
8406 &no_ht);
Johannes Berg4c476992010-10-04 21:36:35 +02008407 if (IS_ERR(connkeys))
8408 return PTR_ERR(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308409
Johannes Berg3d9d1d62012-11-08 23:14:50 +01008410 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
8411 no_ht) {
Ola Olsson5e950a72016-02-11 01:00:22 +01008412 kzfree(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308413 return -EINVAL;
8414 }
Johannes Berg4c476992010-10-04 21:36:35 +02008415 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008416
Antonio Quartulli267335d2012-01-31 20:25:47 +01008417 ibss.control_port =
8418 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
8419
Simon Wunderlich5336fa82013-10-07 18:41:05 +02008420 ibss.userspace_handles_dfs =
8421 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
8422
Johannes Berg4c476992010-10-04 21:36:35 +02008423 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008424 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008425 kzfree(connkeys);
Johannes Berg04a773a2009-04-19 21:24:32 +02008426 return err;
8427}
8428
8429static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
8430{
Johannes Berg4c476992010-10-04 21:36:35 +02008431 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8432 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008433
Johannes Berg4c476992010-10-04 21:36:35 +02008434 if (!rdev->ops->leave_ibss)
8435 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008436
Johannes Berg4c476992010-10-04 21:36:35 +02008437 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8438 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008439
Johannes Berg4c476992010-10-04 21:36:35 +02008440 return cfg80211_leave_ibss(rdev, dev, false);
Johannes Berg04a773a2009-04-19 21:24:32 +02008441}
8442
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008443static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
8444{
8445 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8446 struct net_device *dev = info->user_ptr[1];
Johannes Berg57fbcce2016-04-12 15:56:15 +02008447 int mcast_rate[NUM_NL80211_BANDS];
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008448 u32 nla_rate;
8449 int err;
8450
8451 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
Bertold Van den Bergh876dc932015-08-05 16:02:21 +02008452 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
8453 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008454 return -EOPNOTSUPP;
8455
8456 if (!rdev->ops->set_mcast_rate)
8457 return -EOPNOTSUPP;
8458
8459 memset(mcast_rate, 0, sizeof(mcast_rate));
8460
8461 if (!info->attrs[NL80211_ATTR_MCAST_RATE])
8462 return -EINVAL;
8463
8464 nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
8465 if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
8466 return -EINVAL;
8467
Ilan Peera1056b1b2015-10-22 22:27:46 +03008468 err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008469
8470 return err;
8471}
8472
Johannes Bergad7e7182013-11-13 13:37:47 +01008473static struct sk_buff *
8474__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008475 struct wireless_dev *wdev, int approxlen,
8476 u32 portid, u32 seq, enum nl80211_commands cmd,
Johannes Berg567ffc32013-12-18 14:43:31 +01008477 enum nl80211_attrs attr,
8478 const struct nl80211_vendor_cmd_info *info,
8479 gfp_t gfp)
Johannes Bergad7e7182013-11-13 13:37:47 +01008480{
8481 struct sk_buff *skb;
8482 void *hdr;
8483 struct nlattr *data;
8484
8485 skb = nlmsg_new(approxlen + 100, gfp);
8486 if (!skb)
8487 return NULL;
8488
8489 hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
8490 if (!hdr) {
8491 kfree_skb(skb);
8492 return NULL;
8493 }
8494
8495 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
8496 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01008497
8498 if (info) {
8499 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
8500 info->vendor_id))
8501 goto nla_put_failure;
8502 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
8503 info->subcmd))
8504 goto nla_put_failure;
8505 }
8506
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008507 if (wdev) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008508 if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
8509 wdev_id(wdev), NL80211_ATTR_PAD))
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008510 goto nla_put_failure;
8511 if (wdev->netdev &&
8512 nla_put_u32(skb, NL80211_ATTR_IFINDEX,
8513 wdev->netdev->ifindex))
8514 goto nla_put_failure;
8515 }
8516
Johannes Bergad7e7182013-11-13 13:37:47 +01008517 data = nla_nest_start(skb, attr);
Johannes Berg76e1fb42016-09-14 09:55:57 +02008518 if (!data)
8519 goto nla_put_failure;
Johannes Bergad7e7182013-11-13 13:37:47 +01008520
8521 ((void **)skb->cb)[0] = rdev;
8522 ((void **)skb->cb)[1] = hdr;
8523 ((void **)skb->cb)[2] = data;
8524
8525 return skb;
8526
8527 nla_put_failure:
8528 kfree_skb(skb);
8529 return NULL;
8530}
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008531
Johannes Berge03ad6e2014-01-01 17:22:30 +01008532struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008533 struct wireless_dev *wdev,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008534 enum nl80211_commands cmd,
8535 enum nl80211_attrs attr,
8536 int vendor_event_idx,
8537 int approxlen, gfp_t gfp)
8538{
Zhao, Gangf26cbf42014-04-21 12:53:03 +08008539 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berge03ad6e2014-01-01 17:22:30 +01008540 const struct nl80211_vendor_cmd_info *info;
8541
8542 switch (cmd) {
8543 case NL80211_CMD_TESTMODE:
8544 if (WARN_ON(vendor_event_idx != -1))
8545 return NULL;
8546 info = NULL;
8547 break;
8548 case NL80211_CMD_VENDOR:
8549 if (WARN_ON(vendor_event_idx < 0 ||
8550 vendor_event_idx >= wiphy->n_vendor_events))
8551 return NULL;
8552 info = &wiphy->vendor_events[vendor_event_idx];
8553 break;
8554 default:
8555 WARN_ON(1);
8556 return NULL;
8557 }
8558
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008559 return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008560 cmd, attr, info, gfp);
8561}
8562EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
8563
8564void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
8565{
8566 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
8567 void *hdr = ((void **)skb->cb)[1];
8568 struct nlattr *data = ((void **)skb->cb)[2];
8569 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
8570
Johannes Bergbd8c78e2014-07-30 14:55:26 +02008571 /* clear CB data for netlink core to own from now on */
8572 memset(skb->cb, 0, sizeof(skb->cb));
8573
Johannes Berge03ad6e2014-01-01 17:22:30 +01008574 nla_nest_end(skb, data);
8575 genlmsg_end(skb, hdr);
8576
8577 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
8578 mcgrp = NL80211_MCGRP_VENDOR;
8579
8580 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
8581 mcgrp, gfp);
8582}
8583EXPORT_SYMBOL(__cfg80211_send_event_skb);
8584
Johannes Bergaff89a92009-07-01 21:26:51 +02008585#ifdef CONFIG_NL80211_TESTMODE
Johannes Bergaff89a92009-07-01 21:26:51 +02008586static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
8587{
Johannes Berg4c476992010-10-04 21:36:35 +02008588 struct cfg80211_registered_device *rdev = info->user_ptr[0];
David Spinadelfc73f112013-07-31 18:04:15 +03008589 struct wireless_dev *wdev =
8590 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
Johannes Bergaff89a92009-07-01 21:26:51 +02008591 int err;
8592
David Spinadelfc73f112013-07-31 18:04:15 +03008593 if (!rdev->ops->testmode_cmd)
8594 return -EOPNOTSUPP;
8595
8596 if (IS_ERR(wdev)) {
8597 err = PTR_ERR(wdev);
8598 if (err != -EINVAL)
8599 return err;
8600 wdev = NULL;
8601 } else if (wdev->wiphy != &rdev->wiphy) {
8602 return -EINVAL;
8603 }
8604
Johannes Bergaff89a92009-07-01 21:26:51 +02008605 if (!info->attrs[NL80211_ATTR_TESTDATA])
8606 return -EINVAL;
8607
Johannes Bergad7e7182013-11-13 13:37:47 +01008608 rdev->cur_cmd_info = info;
David Spinadelfc73f112013-07-31 18:04:15 +03008609 err = rdev_testmode_cmd(rdev, wdev,
Johannes Bergaff89a92009-07-01 21:26:51 +02008610 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
8611 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
Johannes Bergad7e7182013-11-13 13:37:47 +01008612 rdev->cur_cmd_info = NULL;
Johannes Bergaff89a92009-07-01 21:26:51 +02008613
Johannes Bergaff89a92009-07-01 21:26:51 +02008614 return err;
8615}
8616
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008617static int nl80211_testmode_dump(struct sk_buff *skb,
8618 struct netlink_callback *cb)
8619{
Johannes Berg00918d32011-12-13 17:22:05 +01008620 struct cfg80211_registered_device *rdev;
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008621 int err;
8622 long phy_idx;
8623 void *data = NULL;
8624 int data_len = 0;
8625
Johannes Berg5fe231e2013-05-08 21:45:15 +02008626 rtnl_lock();
8627
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008628 if (cb->args[0]) {
8629 /*
8630 * 0 is a valid index, but not valid for args[0],
8631 * so we need to offset by 1.
8632 */
8633 phy_idx = cb->args[0] - 1;
Luca Coelhoa4956dc2017-02-07 22:13:56 +02008634
8635 rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
8636 if (!rdev) {
8637 err = -ENOENT;
8638 goto out_err;
8639 }
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008640 } else {
Johannes Bergc90c39d2016-10-24 14:40:01 +02008641 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
8642
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008643 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +02008644 attrbuf, nl80211_fam.maxattr, nl80211_policy);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008645 if (err)
Johannes Berg5fe231e2013-05-08 21:45:15 +02008646 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008647
Johannes Bergc90c39d2016-10-24 14:40:01 +02008648 rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg2bd7e352012-06-15 14:23:16 +02008649 if (IS_ERR(rdev)) {
Johannes Berg5fe231e2013-05-08 21:45:15 +02008650 err = PTR_ERR(rdev);
8651 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008652 }
Johannes Berg2bd7e352012-06-15 14:23:16 +02008653 phy_idx = rdev->wiphy_idx;
Johannes Berg2bd7e352012-06-15 14:23:16 +02008654
Johannes Bergc90c39d2016-10-24 14:40:01 +02008655 if (attrbuf[NL80211_ATTR_TESTDATA])
8656 cb->args[1] = (long)attrbuf[NL80211_ATTR_TESTDATA];
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008657 }
8658
8659 if (cb->args[1]) {
8660 data = nla_data((void *)cb->args[1]);
8661 data_len = nla_len((void *)cb->args[1]);
8662 }
8663
Johannes Berg00918d32011-12-13 17:22:05 +01008664 if (!rdev->ops->testmode_dump) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008665 err = -EOPNOTSUPP;
8666 goto out_err;
8667 }
8668
8669 while (1) {
Eric W. Biederman15e47302012-09-07 20:12:54 +00008670 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008671 cb->nlh->nlmsg_seq, NLM_F_MULTI,
8672 NL80211_CMD_TESTMODE);
8673 struct nlattr *tmdata;
8674
Dan Carpentercb35fba2013-08-14 14:50:01 +03008675 if (!hdr)
8676 break;
8677
David S. Miller9360ffd2012-03-29 04:41:26 -04008678 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008679 genlmsg_cancel(skb, hdr);
8680 break;
8681 }
8682
8683 tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
8684 if (!tmdata) {
8685 genlmsg_cancel(skb, hdr);
8686 break;
8687 }
Hila Gonene35e4d22012-06-27 17:19:42 +03008688 err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008689 nla_nest_end(skb, tmdata);
8690
8691 if (err == -ENOBUFS || err == -ENOENT) {
8692 genlmsg_cancel(skb, hdr);
8693 break;
8694 } else if (err) {
8695 genlmsg_cancel(skb, hdr);
8696 goto out_err;
8697 }
8698
8699 genlmsg_end(skb, hdr);
8700 }
8701
8702 err = skb->len;
8703 /* see above */
8704 cb->args[0] = phy_idx + 1;
8705 out_err:
Johannes Berg5fe231e2013-05-08 21:45:15 +02008706 rtnl_unlock();
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008707 return err;
8708}
Johannes Bergaff89a92009-07-01 21:26:51 +02008709#endif
8710
Samuel Ortizb23aa672009-07-01 21:26:54 +02008711static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
8712{
Johannes Berg4c476992010-10-04 21:36:35 +02008713 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8714 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02008715 struct cfg80211_connect_params connect;
8716 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008717 struct cfg80211_cached_keys *connkeys = NULL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008718 int err;
8719
8720 memset(&connect, 0, sizeof(connect));
8721
8722 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8723 return -EINVAL;
8724
8725 if (!info->attrs[NL80211_ATTR_SSID] ||
8726 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8727 return -EINVAL;
8728
8729 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
8730 connect.auth_type =
8731 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008732 if (!nl80211_valid_auth_type(rdev, connect.auth_type,
8733 NL80211_CMD_CONNECT))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008734 return -EINVAL;
8735 } else
8736 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
8737
8738 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
8739
Johannes Bergc0692b82010-08-27 14:26:53 +03008740 err = nl80211_crypto_settings(rdev, info, &connect.crypto,
Johannes Berg3dc27d22009-07-02 21:36:37 +02008741 NL80211_MAX_NR_CIPHER_SUITES);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008742 if (err)
8743 return err;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008744
Johannes Berg074ac8d2010-09-16 14:58:22 +02008745 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008746 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8747 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008748
Johannes Berg79c97e92009-07-07 03:56:12 +02008749 wiphy = &rdev->wiphy;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008750
Bala Shanmugam4486ea92012-03-07 17:27:12 +05308751 connect.bg_scan_period = -1;
8752 if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
8753 (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
8754 connect.bg_scan_period =
8755 nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
8756 }
8757
Samuel Ortizb23aa672009-07-01 21:26:54 +02008758 if (info->attrs[NL80211_ATTR_MAC])
8759 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen1df4a512014-01-15 00:00:47 +02008760 else if (info->attrs[NL80211_ATTR_MAC_HINT])
8761 connect.bssid_hint =
8762 nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008763 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8764 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8765
8766 if (info->attrs[NL80211_ATTR_IE]) {
8767 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8768 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8769 }
8770
Jouni Malinencee00a92013-01-15 17:15:57 +02008771 if (info->attrs[NL80211_ATTR_USE_MFP]) {
8772 connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
8773 if (connect.mfp != NL80211_MFP_REQUIRED &&
8774 connect.mfp != NL80211_MFP_NO)
8775 return -EINVAL;
8776 } else {
8777 connect.mfp = NL80211_MFP_NO;
8778 }
8779
Jouni Malinenba6fbac2016-03-29 13:53:27 +03008780 if (info->attrs[NL80211_ATTR_PREV_BSSID])
8781 connect.prev_bssid =
8782 nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
8783
Samuel Ortizb23aa672009-07-01 21:26:54 +02008784 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02008785 connect.channel = nl80211_get_valid_chan(
8786 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8787 if (!connect.channel)
Johannes Berg4c476992010-10-04 21:36:35 +02008788 return -EINVAL;
Jouni Malinen1df4a512014-01-15 00:00:47 +02008789 } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02008790 connect.channel_hint = nl80211_get_valid_chan(
8791 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
8792 if (!connect.channel_hint)
Jouni Malinen1df4a512014-01-15 00:00:47 +02008793 return -EINVAL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008794 }
8795
Johannes Bergfffd0932009-07-08 14:22:54 +02008796 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
8797 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308798 info->attrs[NL80211_ATTR_KEYS], NULL);
Johannes Berg4c476992010-10-04 21:36:35 +02008799 if (IS_ERR(connkeys))
8800 return PTR_ERR(connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008801 }
8802
Ben Greear7e7c8922011-11-18 11:31:59 -08008803 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
8804 connect.flags |= ASSOC_REQ_DISABLE_HT;
8805
8806 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8807 memcpy(&connect.ht_capa_mask,
8808 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8809 sizeof(connect.ht_capa_mask));
8810
8811 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Wei Yongjunb4e4f472012-09-02 21:41:04 +08008812 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03008813 kzfree(connkeys);
Ben Greear7e7c8922011-11-18 11:31:59 -08008814 return -EINVAL;
Wei Yongjunb4e4f472012-09-02 21:41:04 +08008815 }
Ben Greear7e7c8922011-11-18 11:31:59 -08008816 memcpy(&connect.ht_capa,
8817 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8818 sizeof(connect.ht_capa));
8819 }
8820
Johannes Bergee2aca32013-02-21 17:36:01 +01008821 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
8822 connect.flags |= ASSOC_REQ_DISABLE_VHT;
8823
8824 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
8825 memcpy(&connect.vht_capa_mask,
8826 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8827 sizeof(connect.vht_capa_mask));
8828
8829 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
8830 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03008831 kzfree(connkeys);
Johannes Bergee2aca32013-02-21 17:36:01 +01008832 return -EINVAL;
8833 }
8834 memcpy(&connect.vht_capa,
8835 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8836 sizeof(connect.vht_capa));
8837 }
8838
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008839 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008840 if (!((rdev->wiphy.features &
8841 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8842 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8843 !wiphy_ext_feature_isset(&rdev->wiphy,
8844 NL80211_EXT_FEATURE_RRM)) {
Ola Olsson707554b2015-12-11 21:04:52 +01008845 kzfree(connkeys);
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008846 return -EINVAL;
Ola Olsson707554b2015-12-11 21:04:52 +01008847 }
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008848 connect.flags |= ASSOC_REQ_USE_RRM;
8849 }
8850
Lior David34d50512016-01-28 10:58:25 +02008851 connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
Johannes Berg57fbcce2016-04-12 15:56:15 +02008852 if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
Lior David34d50512016-01-28 10:58:25 +02008853 kzfree(connkeys);
8854 return -EOPNOTSUPP;
8855 }
8856
Arend van Spriel38de03d2016-03-02 20:37:18 +01008857 if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
8858 /* bss selection makes no sense if bssid is set */
8859 if (connect.bssid) {
8860 kzfree(connkeys);
8861 return -EINVAL;
8862 }
8863
8864 err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
8865 wiphy, &connect.bss_select);
8866 if (err) {
8867 kzfree(connkeys);
8868 return err;
8869 }
8870 }
8871
Johannes Berg83739b02013-05-15 17:44:01 +02008872 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008873
Jouni Malinen4ce2bd92016-03-29 13:53:28 +03008874 err = cfg80211_connect(rdev, dev, &connect, connkeys,
8875 connect.prev_bssid);
Johannes Bergfffd0932009-07-08 14:22:54 +02008876 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008877 kzfree(connkeys);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008878
8879 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8880 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
8881 if (connect.bssid)
8882 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8883 connect.bssid, ETH_ALEN);
8884 else
8885 memset(dev->ieee80211_ptr->disconnect_bssid,
8886 0, ETH_ALEN);
8887 }
8888
8889 wdev_unlock(dev->ieee80211_ptr);
8890
Samuel Ortizb23aa672009-07-01 21:26:54 +02008891 return err;
8892}
8893
vamsi krishna088e8df2016-10-27 16:51:11 +03008894static int nl80211_update_connect_params(struct sk_buff *skb,
8895 struct genl_info *info)
8896{
8897 struct cfg80211_connect_params connect = {};
8898 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8899 struct net_device *dev = info->user_ptr[1];
8900 struct wireless_dev *wdev = dev->ieee80211_ptr;
8901 u32 changed = 0;
8902 int ret;
8903
8904 if (!rdev->ops->update_connect_params)
8905 return -EOPNOTSUPP;
8906
8907 if (info->attrs[NL80211_ATTR_IE]) {
8908 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8909 return -EINVAL;
8910 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8911 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8912 changed |= UPDATE_ASSOC_IES;
8913 }
8914
8915 wdev_lock(dev->ieee80211_ptr);
8916 if (!wdev->current_bss)
8917 ret = -ENOLINK;
8918 else
8919 ret = rdev_update_connect_params(rdev, dev, &connect, changed);
8920 wdev_unlock(dev->ieee80211_ptr);
8921
8922 return ret;
8923}
8924
Samuel Ortizb23aa672009-07-01 21:26:54 +02008925static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
8926{
Johannes Berg4c476992010-10-04 21:36:35 +02008927 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8928 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02008929 u16 reason;
Johannes Berg83739b02013-05-15 17:44:01 +02008930 int ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008931
8932 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8933 reason = WLAN_REASON_DEAUTH_LEAVING;
8934 else
8935 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8936
8937 if (reason == 0)
8938 return -EINVAL;
8939
Johannes Berg074ac8d2010-09-16 14:58:22 +02008940 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008941 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8942 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008943
Johannes Berg83739b02013-05-15 17:44:01 +02008944 wdev_lock(dev->ieee80211_ptr);
8945 ret = cfg80211_disconnect(rdev, dev, reason, true);
8946 wdev_unlock(dev->ieee80211_ptr);
8947 return ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008948}
8949
Johannes Berg463d0182009-07-14 00:33:35 +02008950static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
8951{
Johannes Berg4c476992010-10-04 21:36:35 +02008952 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg463d0182009-07-14 00:33:35 +02008953 struct net *net;
8954 int err;
Johannes Berg463d0182009-07-14 00:33:35 +02008955
Vadim Kochan4b681c82015-01-12 16:34:05 +02008956 if (info->attrs[NL80211_ATTR_PID]) {
8957 u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
8958
8959 net = get_net_ns_by_pid(pid);
8960 } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
8961 u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
8962
8963 net = get_net_ns_by_fd(fd);
8964 } else {
Johannes Berg463d0182009-07-14 00:33:35 +02008965 return -EINVAL;
Vadim Kochan4b681c82015-01-12 16:34:05 +02008966 }
Johannes Berg463d0182009-07-14 00:33:35 +02008967
Johannes Berg4c476992010-10-04 21:36:35 +02008968 if (IS_ERR(net))
8969 return PTR_ERR(net);
Johannes Berg463d0182009-07-14 00:33:35 +02008970
8971 err = 0;
8972
8973 /* check if anything to do */
Johannes Berg4c476992010-10-04 21:36:35 +02008974 if (!net_eq(wiphy_net(&rdev->wiphy), net))
8975 err = cfg80211_switch_netns(rdev, net);
Johannes Berg463d0182009-07-14 00:33:35 +02008976
Johannes Berg463d0182009-07-14 00:33:35 +02008977 put_net(net);
Johannes Berg463d0182009-07-14 00:33:35 +02008978 return err;
8979}
8980
Samuel Ortiz67fbb162009-11-24 23:59:15 +01008981static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
8982{
Johannes Berg4c476992010-10-04 21:36:35 +02008983 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01008984 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
8985 struct cfg80211_pmksa *pmksa) = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02008986 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01008987 struct cfg80211_pmksa pmksa;
8988
8989 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
8990
8991 if (!info->attrs[NL80211_ATTR_MAC])
8992 return -EINVAL;
8993
8994 if (!info->attrs[NL80211_ATTR_PMKID])
8995 return -EINVAL;
8996
Samuel Ortiz67fbb162009-11-24 23:59:15 +01008997 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
8998 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
8999
Johannes Berg074ac8d2010-09-16 14:58:22 +02009000 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009001 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9002 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009003
9004 switch (info->genlhdr->cmd) {
9005 case NL80211_CMD_SET_PMKSA:
9006 rdev_ops = rdev->ops->set_pmksa;
9007 break;
9008 case NL80211_CMD_DEL_PMKSA:
9009 rdev_ops = rdev->ops->del_pmksa;
9010 break;
9011 default:
9012 WARN_ON(1);
9013 break;
9014 }
9015
Johannes Berg4c476992010-10-04 21:36:35 +02009016 if (!rdev_ops)
9017 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009018
Johannes Berg4c476992010-10-04 21:36:35 +02009019 return rdev_ops(&rdev->wiphy, dev, &pmksa);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009020}
9021
9022static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
9023{
Johannes Berg4c476992010-10-04 21:36:35 +02009024 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9025 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009026
Johannes Berg074ac8d2010-09-16 14:58:22 +02009027 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009028 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9029 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009030
Johannes Berg4c476992010-10-04 21:36:35 +02009031 if (!rdev->ops->flush_pmksa)
9032 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009033
Hila Gonene35e4d22012-06-27 17:19:42 +03009034 return rdev_flush_pmksa(rdev, dev);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009035}
9036
Arik Nemtsov109086c2011-09-28 14:12:50 +03009037static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
9038{
9039 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9040 struct net_device *dev = info->user_ptr[1];
9041 u8 action_code, dialog_token;
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309042 u32 peer_capability = 0;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009043 u16 status_code;
9044 u8 *peer;
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009045 bool initiator;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009046
9047 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9048 !rdev->ops->tdls_mgmt)
9049 return -EOPNOTSUPP;
9050
9051 if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
9052 !info->attrs[NL80211_ATTR_STATUS_CODE] ||
9053 !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
9054 !info->attrs[NL80211_ATTR_IE] ||
9055 !info->attrs[NL80211_ATTR_MAC])
9056 return -EINVAL;
9057
9058 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9059 action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
9060 status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
9061 dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009062 initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309063 if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
9064 peer_capability =
9065 nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009066
Hila Gonene35e4d22012-06-27 17:19:42 +03009067 return rdev_tdls_mgmt(rdev, dev, peer, action_code,
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309068 dialog_token, status_code, peer_capability,
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009069 initiator,
Hila Gonene35e4d22012-06-27 17:19:42 +03009070 nla_data(info->attrs[NL80211_ATTR_IE]),
9071 nla_len(info->attrs[NL80211_ATTR_IE]));
Arik Nemtsov109086c2011-09-28 14:12:50 +03009072}
9073
9074static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
9075{
9076 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9077 struct net_device *dev = info->user_ptr[1];
9078 enum nl80211_tdls_operation operation;
9079 u8 *peer;
9080
9081 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9082 !rdev->ops->tdls_oper)
9083 return -EOPNOTSUPP;
9084
9085 if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
9086 !info->attrs[NL80211_ATTR_MAC])
9087 return -EINVAL;
9088
9089 operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
9090 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9091
Hila Gonene35e4d22012-06-27 17:19:42 +03009092 return rdev_tdls_oper(rdev, dev, peer, operation);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009093}
9094
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009095static int nl80211_remain_on_channel(struct sk_buff *skb,
9096 struct genl_info *info)
9097{
Johannes Berg4c476992010-10-04 21:36:35 +02009098 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009099 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009100 struct cfg80211_chan_def chandef;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009101 struct sk_buff *msg;
9102 void *hdr;
9103 u64 cookie;
Johannes Berg683b6d32012-11-08 21:25:48 +01009104 u32 duration;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009105 int err;
9106
9107 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
9108 !info->attrs[NL80211_ATTR_DURATION])
9109 return -EINVAL;
9110
9111 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
9112
Johannes Berg7c4ef712011-11-18 15:33:48 +01009113 if (!rdev->ops->remain_on_channel ||
9114 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
Johannes Berg4c476992010-10-04 21:36:35 +02009115 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009116
Johannes Bergebf348f2012-06-01 12:50:54 +02009117 /*
9118 * We should be on that channel for at least a minimum amount of
9119 * time (10ms) but no longer than the driver supports.
9120 */
9121 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9122 duration > rdev->wiphy.max_remain_on_channel_duration)
9123 return -EINVAL;
9124
Johannes Berg683b6d32012-11-08 21:25:48 +01009125 err = nl80211_parse_chandef(rdev, info, &chandef);
9126 if (err)
9127 return err;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009128
9129 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009130 if (!msg)
9131 return -ENOMEM;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009132
Eric W. Biederman15e47302012-09-07 20:12:54 +00009133 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009134 NL80211_CMD_REMAIN_ON_CHANNEL);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009135 if (!hdr) {
9136 err = -ENOBUFS;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009137 goto free_msg;
9138 }
9139
Johannes Berg683b6d32012-11-08 21:25:48 +01009140 err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
9141 duration, &cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009142
9143 if (err)
9144 goto free_msg;
9145
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009146 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9147 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009148 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009149
9150 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009151
9152 return genlmsg_reply(msg, info);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009153
9154 nla_put_failure:
9155 err = -ENOBUFS;
9156 free_msg:
9157 nlmsg_free(msg);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009158 return err;
9159}
9160
9161static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
9162 struct genl_info *info)
9163{
Johannes Berg4c476992010-10-04 21:36:35 +02009164 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009165 struct wireless_dev *wdev = info->user_ptr[1];
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009166 u64 cookie;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009167
9168 if (!info->attrs[NL80211_ATTR_COOKIE])
9169 return -EINVAL;
9170
Johannes Berg4c476992010-10-04 21:36:35 +02009171 if (!rdev->ops->cancel_remain_on_channel)
9172 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009173
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009174 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9175
Hila Gonene35e4d22012-06-27 17:19:42 +03009176 return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009177}
9178
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009179static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
9180 struct genl_info *info)
9181{
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009182 struct cfg80211_bitrate_mask mask;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309183 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009184 struct net_device *dev = info->user_ptr[1];
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309185 int err;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009186
Johannes Berg4c476992010-10-04 21:36:35 +02009187 if (!rdev->ops->set_bitrate_mask)
9188 return -EOPNOTSUPP;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009189
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309190 err = nl80211_parse_tx_bitrate_mask(info, &mask);
9191 if (err)
9192 return err;
Janusz Dziedzic78693032013-12-03 09:50:44 +01009193
Hila Gonene35e4d22012-06-27 17:19:42 +03009194 return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009195}
9196
Johannes Berg2e161f782010-08-12 15:38:38 +02009197static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009198{
Johannes Berg4c476992010-10-04 21:36:35 +02009199 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009200 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2e161f782010-08-12 15:38:38 +02009201 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
Jouni Malinen026331c2010-02-15 12:53:10 +02009202
9203 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
9204 return -EINVAL;
9205
Johannes Berg2e161f782010-08-12 15:38:38 +02009206 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
9207 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
Jouni Malinen026331c2010-02-15 12:53:10 +02009208
Johannes Berg71bbc992012-06-15 15:30:18 +02009209 switch (wdev->iftype) {
9210 case NL80211_IFTYPE_STATION:
9211 case NL80211_IFTYPE_ADHOC:
9212 case NL80211_IFTYPE_P2P_CLIENT:
9213 case NL80211_IFTYPE_AP:
9214 case NL80211_IFTYPE_AP_VLAN:
9215 case NL80211_IFTYPE_MESH_POINT:
9216 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009217 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009218 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009219 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009220 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009221 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009222 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009223
9224 /* not much point in registering if we can't reply */
Johannes Berg4c476992010-10-04 21:36:35 +02009225 if (!rdev->ops->mgmt_tx)
9226 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009227
Eric W. Biederman15e47302012-09-07 20:12:54 +00009228 return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
Jouni Malinen026331c2010-02-15 12:53:10 +02009229 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
9230 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
Jouni Malinen026331c2010-02-15 12:53:10 +02009231}
9232
Johannes Berg2e161f782010-08-12 15:38:38 +02009233static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009234{
Johannes Berg4c476992010-10-04 21:36:35 +02009235 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009236 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009237 struct cfg80211_chan_def chandef;
Jouni Malinen026331c2010-02-15 12:53:10 +02009238 int err;
Johannes Bergd64d3732011-11-10 09:44:46 +01009239 void *hdr = NULL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009240 u64 cookie;
Johannes Berge247bd902011-11-04 11:18:21 +01009241 struct sk_buff *msg = NULL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009242 struct cfg80211_mgmt_tx_params params = {
9243 .dont_wait_for_ack =
9244 info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
9245 };
Jouni Malinen026331c2010-02-15 12:53:10 +02009246
Johannes Berg683b6d32012-11-08 21:25:48 +01009247 if (!info->attrs[NL80211_ATTR_FRAME])
Jouni Malinen026331c2010-02-15 12:53:10 +02009248 return -EINVAL;
9249
Johannes Berg4c476992010-10-04 21:36:35 +02009250 if (!rdev->ops->mgmt_tx)
9251 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009252
Johannes Berg71bbc992012-06-15 15:30:18 +02009253 switch (wdev->iftype) {
Antonio Quartulliea141b752013-06-11 14:20:03 +02009254 case NL80211_IFTYPE_P2P_DEVICE:
9255 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
9256 return -EINVAL;
Johannes Berg71bbc992012-06-15 15:30:18 +02009257 case NL80211_IFTYPE_STATION:
9258 case NL80211_IFTYPE_ADHOC:
9259 case NL80211_IFTYPE_P2P_CLIENT:
9260 case NL80211_IFTYPE_AP:
9261 case NL80211_IFTYPE_AP_VLAN:
9262 case NL80211_IFTYPE_MESH_POINT:
9263 case NL80211_IFTYPE_P2P_GO:
9264 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009265 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009266 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009267 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009268 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009269
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009270 if (info->attrs[NL80211_ATTR_DURATION]) {
Johannes Berg7c4ef712011-11-18 15:33:48 +01009271 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009272 return -EINVAL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009273 params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
Johannes Bergebf348f2012-06-01 12:50:54 +02009274
9275 /*
9276 * We should wait on the channel for at least a minimum amount
9277 * of time (10ms) but no longer than the driver supports.
9278 */
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009279 if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9280 params.wait > rdev->wiphy.max_remain_on_channel_duration)
Johannes Bergebf348f2012-06-01 12:50:54 +02009281 return -EINVAL;
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009282 }
9283
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009284 params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009285
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009286 if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Berg7c4ef712011-11-18 15:33:48 +01009287 return -EINVAL;
9288
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009289 params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05309290
Antonio Quartulliea141b752013-06-11 14:20:03 +02009291 /* get the channel if any has been specified, otherwise pass NULL to
9292 * the driver. The latter will use the current one
9293 */
9294 chandef.chan = NULL;
9295 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
9296 err = nl80211_parse_chandef(rdev, info, &chandef);
9297 if (err)
9298 return err;
9299 }
9300
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009301 if (!chandef.chan && params.offchan)
Antonio Quartulliea141b752013-06-11 14:20:03 +02009302 return -EINVAL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009303
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +03009304 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
9305 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
9306
9307 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
9308 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9309 int i;
9310
9311 if (len % sizeof(u16))
9312 return -EINVAL;
9313
9314 params.n_csa_offsets = len / sizeof(u16);
9315 params.csa_offsets =
9316 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9317
9318 /* check that all the offsets fit the frame */
9319 for (i = 0; i < params.n_csa_offsets; i++) {
9320 if (params.csa_offsets[i] >= params.len)
9321 return -EINVAL;
9322 }
9323 }
9324
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009325 if (!params.dont_wait_for_ack) {
Johannes Berge247bd902011-11-04 11:18:21 +01009326 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9327 if (!msg)
9328 return -ENOMEM;
Jouni Malinen026331c2010-02-15 12:53:10 +02009329
Eric W. Biederman15e47302012-09-07 20:12:54 +00009330 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berge247bd902011-11-04 11:18:21 +01009331 NL80211_CMD_FRAME);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009332 if (!hdr) {
9333 err = -ENOBUFS;
Johannes Berge247bd902011-11-04 11:18:21 +01009334 goto free_msg;
9335 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009336 }
Johannes Berge247bd902011-11-04 11:18:21 +01009337
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009338 params.chan = chandef.chan;
9339 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
Jouni Malinen026331c2010-02-15 12:53:10 +02009340 if (err)
9341 goto free_msg;
9342
Johannes Berge247bd902011-11-04 11:18:21 +01009343 if (msg) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009344 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9345 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009346 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +02009347
Johannes Berge247bd902011-11-04 11:18:21 +01009348 genlmsg_end(msg, hdr);
9349 return genlmsg_reply(msg, info);
9350 }
9351
9352 return 0;
Jouni Malinen026331c2010-02-15 12:53:10 +02009353
9354 nla_put_failure:
9355 err = -ENOBUFS;
9356 free_msg:
9357 nlmsg_free(msg);
Jouni Malinen026331c2010-02-15 12:53:10 +02009358 return err;
9359}
9360
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009361static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
9362{
9363 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009364 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009365 u64 cookie;
9366
9367 if (!info->attrs[NL80211_ATTR_COOKIE])
9368 return -EINVAL;
9369
9370 if (!rdev->ops->mgmt_tx_cancel_wait)
9371 return -EOPNOTSUPP;
9372
Johannes Berg71bbc992012-06-15 15:30:18 +02009373 switch (wdev->iftype) {
9374 case NL80211_IFTYPE_STATION:
9375 case NL80211_IFTYPE_ADHOC:
9376 case NL80211_IFTYPE_P2P_CLIENT:
9377 case NL80211_IFTYPE_AP:
9378 case NL80211_IFTYPE_AP_VLAN:
9379 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009380 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009381 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009382 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009383 default:
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009384 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009385 }
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009386
9387 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9388
Hila Gonene35e4d22012-06-27 17:19:42 +03009389 return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009390}
9391
Kalle Valoffb9eb32010-02-17 17:58:10 +02009392static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
9393{
Johannes Berg4c476992010-10-04 21:36:35 +02009394 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009395 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009396 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009397 u8 ps_state;
9398 bool state;
9399 int err;
9400
Johannes Berg4c476992010-10-04 21:36:35 +02009401 if (!info->attrs[NL80211_ATTR_PS_STATE])
9402 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009403
9404 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
9405
Johannes Berg4c476992010-10-04 21:36:35 +02009406 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
9407 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009408
9409 wdev = dev->ieee80211_ptr;
9410
Johannes Berg4c476992010-10-04 21:36:35 +02009411 if (!rdev->ops->set_power_mgmt)
9412 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009413
9414 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
9415
9416 if (state == wdev->ps)
Johannes Berg4c476992010-10-04 21:36:35 +02009417 return 0;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009418
Hila Gonene35e4d22012-06-27 17:19:42 +03009419 err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
Johannes Berg4c476992010-10-04 21:36:35 +02009420 if (!err)
9421 wdev->ps = state;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009422 return err;
9423}
9424
9425static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
9426{
Johannes Berg4c476992010-10-04 21:36:35 +02009427 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009428 enum nl80211_ps_state ps_state;
9429 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009430 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009431 struct sk_buff *msg;
9432 void *hdr;
9433 int err;
9434
Kalle Valoffb9eb32010-02-17 17:58:10 +02009435 wdev = dev->ieee80211_ptr;
9436
Johannes Berg4c476992010-10-04 21:36:35 +02009437 if (!rdev->ops->set_power_mgmt)
9438 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009439
9440 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009441 if (!msg)
9442 return -ENOMEM;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009443
Eric W. Biederman15e47302012-09-07 20:12:54 +00009444 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Kalle Valoffb9eb32010-02-17 17:58:10 +02009445 NL80211_CMD_GET_POWER_SAVE);
9446 if (!hdr) {
Johannes Berg4c476992010-10-04 21:36:35 +02009447 err = -ENOBUFS;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009448 goto free_msg;
9449 }
9450
9451 if (wdev->ps)
9452 ps_state = NL80211_PS_ENABLED;
9453 else
9454 ps_state = NL80211_PS_DISABLED;
9455
David S. Miller9360ffd2012-03-29 04:41:26 -04009456 if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
9457 goto nla_put_failure;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009458
9459 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009460 return genlmsg_reply(msg, info);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009461
Johannes Berg4c476992010-10-04 21:36:35 +02009462 nla_put_failure:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009463 err = -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +02009464 free_msg:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009465 nlmsg_free(msg);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009466 return err;
9467}
9468
Johannes Berg94e860f2014-01-20 23:58:15 +01009469static const struct nla_policy
9470nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009471 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
9472 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
9473 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
Thomas Pedersen84f10702012-07-12 16:17:33 -07009474 [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
9475 [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
9476 [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009477};
9478
Thomas Pedersen84f10702012-07-12 16:17:33 -07009479static int nl80211_set_cqm_txe(struct genl_info *info,
Johannes Bergd9d8b012012-11-26 12:51:52 +01009480 u32 rate, u32 pkts, u32 intvl)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009481{
9482 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Thomas Pedersen84f10702012-07-12 16:17:33 -07009483 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009484 struct wireless_dev *wdev = dev->ieee80211_ptr;
Thomas Pedersen84f10702012-07-12 16:17:33 -07009485
Johannes Bergd9d8b012012-11-26 12:51:52 +01009486 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009487 return -EINVAL;
9488
Thomas Pedersen84f10702012-07-12 16:17:33 -07009489 if (!rdev->ops->set_cqm_txe_config)
9490 return -EOPNOTSUPP;
9491
9492 if (wdev->iftype != NL80211_IFTYPE_STATION &&
9493 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9494 return -EOPNOTSUPP;
9495
Hila Gonene35e4d22012-06-27 17:19:42 +03009496 return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
Thomas Pedersen84f10702012-07-12 16:17:33 -07009497}
9498
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009499static int nl80211_set_cqm_rssi(struct genl_info *info,
9500 s32 threshold, u32 hysteresis)
9501{
Johannes Berg4c476992010-10-04 21:36:35 +02009502 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009503 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009504 struct wireless_dev *wdev = dev->ieee80211_ptr;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009505
9506 if (threshold > 0)
9507 return -EINVAL;
9508
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009509 /* disabling - hysteresis should also be zero then */
9510 if (threshold == 0)
9511 hysteresis = 0;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009512
Johannes Berg4c476992010-10-04 21:36:35 +02009513 if (!rdev->ops->set_cqm_rssi_config)
9514 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009515
Johannes Berg074ac8d2010-09-16 14:58:22 +02009516 if (wdev->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009517 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9518 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009519
Hila Gonene35e4d22012-06-27 17:19:42 +03009520 return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009521}
9522
9523static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
9524{
9525 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
9526 struct nlattr *cqm;
9527 int err;
9528
9529 cqm = info->attrs[NL80211_ATTR_CQM];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009530 if (!cqm)
9531 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009532
9533 err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
9534 nl80211_attr_cqm_policy);
9535 if (err)
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009536 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009537
9538 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
9539 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009540 s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
9541 u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009542
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009543 return nl80211_set_cqm_rssi(info, threshold, hysteresis);
9544 }
9545
9546 if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
9547 attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
9548 attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
9549 u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
9550 u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
9551 u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
9552
9553 return nl80211_set_cqm_txe(info, rate, pkts, intvl);
9554 }
9555
9556 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009557}
9558
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01009559static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
9560{
9561 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9562 struct net_device *dev = info->user_ptr[1];
9563 struct ocb_setup setup = {};
9564 int err;
9565
9566 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9567 if (err)
9568 return err;
9569
9570 return cfg80211_join_ocb(rdev, dev, &setup);
9571}
9572
9573static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
9574{
9575 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9576 struct net_device *dev = info->user_ptr[1];
9577
9578 return cfg80211_leave_ocb(rdev, dev);
9579}
9580
Johannes Berg29cbe682010-12-03 09:20:44 +01009581static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
9582{
9583 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9584 struct net_device *dev = info->user_ptr[1];
9585 struct mesh_config cfg;
Javier Cardonac80d5452010-12-16 17:37:49 -08009586 struct mesh_setup setup;
Johannes Berg29cbe682010-12-03 09:20:44 +01009587 int err;
9588
9589 /* start with default */
9590 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
Javier Cardonac80d5452010-12-16 17:37:49 -08009591 memcpy(&setup, &default_mesh_setup, sizeof(setup));
Johannes Berg29cbe682010-12-03 09:20:44 +01009592
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009593 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01009594 /* and parse parameters if given */
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009595 err = nl80211_parse_mesh_config(info, &cfg, NULL);
Johannes Berg29cbe682010-12-03 09:20:44 +01009596 if (err)
9597 return err;
9598 }
9599
9600 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
9601 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
9602 return -EINVAL;
9603
Javier Cardonac80d5452010-12-16 17:37:49 -08009604 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
9605 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
9606
Chun-Yeow Yeoh4bb62342011-11-24 17:15:20 -08009607 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
9608 !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
9609 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
9610 return -EINVAL;
9611
Marco Porsch9bdbf042013-01-07 16:04:51 +01009612 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
9613 setup.beacon_interval =
9614 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309615
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05309616 err = cfg80211_validate_beacon_int(rdev,
9617 NL80211_IFTYPE_MESH_POINT,
9618 setup.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309619 if (err)
9620 return err;
Marco Porsch9bdbf042013-01-07 16:04:51 +01009621 }
9622
9623 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
9624 setup.dtim_period =
9625 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
9626 if (setup.dtim_period < 1 || setup.dtim_period > 100)
9627 return -EINVAL;
9628 }
9629
Javier Cardonac80d5452010-12-16 17:37:49 -08009630 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
9631 /* parse additional setup parameters if given */
9632 err = nl80211_parse_mesh_setup(info, &setup);
9633 if (err)
9634 return err;
9635 }
9636
Thomas Pedersend37bb182013-03-04 13:06:13 -08009637 if (setup.user_mpm)
9638 cfg.auto_open_plinks = false;
9639
Johannes Bergcc1d2802012-05-16 23:50:20 +02009640 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01009641 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9642 if (err)
9643 return err;
Johannes Bergcc1d2802012-05-16 23:50:20 +02009644 } else {
9645 /* cfg80211_join_mesh() will sort it out */
Johannes Berg683b6d32012-11-08 21:25:48 +01009646 setup.chandef.chan = NULL;
Johannes Bergcc1d2802012-05-16 23:50:20 +02009647 }
9648
Ashok Nagarajanffb3cf32013-06-03 10:33:36 -07009649 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
9650 u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9651 int n_rates =
9652 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9653 struct ieee80211_supported_band *sband;
9654
9655 if (!setup.chandef.chan)
9656 return -EINVAL;
9657
9658 sband = rdev->wiphy.bands[setup.chandef.chan->band];
9659
9660 err = ieee80211_get_ratemask(sband, rates, n_rates,
9661 &setup.basic_rates);
9662 if (err)
9663 return err;
9664 }
9665
Johannes Berg8564e382016-09-19 09:44:44 +02009666 if (info->attrs[NL80211_ATTR_TX_RATES]) {
9667 err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
9668 if (err)
9669 return err;
9670
9671 err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
9672 &setup.beacon_rate);
9673 if (err)
9674 return err;
9675 }
9676
Javier Cardonac80d5452010-12-16 17:37:49 -08009677 return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01009678}
9679
9680static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
9681{
9682 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9683 struct net_device *dev = info->user_ptr[1];
9684
9685 return cfg80211_leave_mesh(rdev, dev);
9686}
9687
Johannes Bergdfb89c52012-06-27 09:23:48 +02009688#ifdef CONFIG_PM
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009689static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
9690 struct cfg80211_registered_device *rdev)
9691{
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009692 struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009693 struct nlattr *nl_pats, *nl_pat;
9694 int i, pat_len;
9695
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009696 if (!wowlan->n_patterns)
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009697 return 0;
9698
9699 nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
9700 if (!nl_pats)
9701 return -ENOBUFS;
9702
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009703 for (i = 0; i < wowlan->n_patterns; i++) {
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009704 nl_pat = nla_nest_start(msg, i + 1);
9705 if (!nl_pat)
9706 return -ENOBUFS;
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009707 pat_len = wowlan->patterns[i].pattern_len;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07009708 if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009709 wowlan->patterns[i].mask) ||
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07009710 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
9711 wowlan->patterns[i].pattern) ||
9712 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009713 wowlan->patterns[i].pkt_offset))
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009714 return -ENOBUFS;
9715 nla_nest_end(msg, nl_pat);
9716 }
9717 nla_nest_end(msg, nl_pats);
9718
9719 return 0;
9720}
9721
Johannes Berg2a0e0472013-01-23 22:57:40 +01009722static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
9723 struct cfg80211_wowlan_tcp *tcp)
9724{
9725 struct nlattr *nl_tcp;
9726
9727 if (!tcp)
9728 return 0;
9729
9730 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
9731 if (!nl_tcp)
9732 return -ENOBUFS;
9733
Jiri Benc930345e2015-03-29 16:59:25 +02009734 if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
9735 nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
Johannes Berg2a0e0472013-01-23 22:57:40 +01009736 nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
9737 nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
9738 nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
9739 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
9740 tcp->payload_len, tcp->payload) ||
9741 nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
9742 tcp->data_interval) ||
9743 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
9744 tcp->wake_len, tcp->wake_data) ||
9745 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
9746 DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
9747 return -ENOBUFS;
9748
9749 if (tcp->payload_seq.len &&
9750 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
9751 sizeof(tcp->payload_seq), &tcp->payload_seq))
9752 return -ENOBUFS;
9753
9754 if (tcp->payload_tok.len &&
9755 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
9756 sizeof(tcp->payload_tok) + tcp->tokens_size,
9757 &tcp->payload_tok))
9758 return -ENOBUFS;
9759
Johannes Berge248ad32013-05-16 10:24:28 +02009760 nla_nest_end(msg, nl_tcp);
9761
Johannes Berg2a0e0472013-01-23 22:57:40 +01009762 return 0;
9763}
9764
Luciano Coelho75453cc2015-01-09 14:06:37 +02009765static int nl80211_send_wowlan_nd(struct sk_buff *msg,
9766 struct cfg80211_sched_scan_request *req)
9767{
Avraham Stern3b06d272015-10-12 09:51:34 +03009768 struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
Luciano Coelho75453cc2015-01-09 14:06:37 +02009769 int i;
9770
9771 if (!req)
9772 return 0;
9773
9774 nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
9775 if (!nd)
9776 return -ENOBUFS;
9777
Avraham Stern3b06d272015-10-12 09:51:34 +03009778 if (req->n_scan_plans == 1 &&
9779 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
9780 req->scan_plans[0].interval * 1000))
Luciano Coelho75453cc2015-01-09 14:06:37 +02009781 return -ENOBUFS;
9782
Luciano Coelho21fea562015-03-17 16:36:01 +02009783 if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
9784 return -ENOBUFS;
9785
vamsi krishnabf95ecd2017-01-13 01:12:20 +02009786 if (req->relative_rssi_set) {
9787 struct nl80211_bss_select_rssi_adjust rssi_adjust;
9788
9789 if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
9790 req->relative_rssi))
9791 return -ENOBUFS;
9792
9793 rssi_adjust.band = req->rssi_adjust.band;
9794 rssi_adjust.delta = req->rssi_adjust.delta;
9795 if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
9796 sizeof(rssi_adjust), &rssi_adjust))
9797 return -ENOBUFS;
9798 }
9799
Luciano Coelho75453cc2015-01-09 14:06:37 +02009800 freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
9801 if (!freqs)
9802 return -ENOBUFS;
9803
Johannes Berg53b18982016-09-14 09:59:21 +02009804 for (i = 0; i < req->n_channels; i++) {
9805 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
9806 return -ENOBUFS;
9807 }
Luciano Coelho75453cc2015-01-09 14:06:37 +02009808
9809 nla_nest_end(msg, freqs);
9810
9811 if (req->n_match_sets) {
9812 matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009813 if (!matches)
9814 return -ENOBUFS;
9815
Luciano Coelho75453cc2015-01-09 14:06:37 +02009816 for (i = 0; i < req->n_match_sets; i++) {
9817 match = nla_nest_start(msg, i);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009818 if (!match)
9819 return -ENOBUFS;
9820
Johannes Berg53b18982016-09-14 09:59:21 +02009821 if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
9822 req->match_sets[i].ssid.ssid_len,
9823 req->match_sets[i].ssid.ssid))
9824 return -ENOBUFS;
Luciano Coelho75453cc2015-01-09 14:06:37 +02009825 nla_nest_end(msg, match);
9826 }
9827 nla_nest_end(msg, matches);
9828 }
9829
Avraham Stern3b06d272015-10-12 09:51:34 +03009830 scan_plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
9831 if (!scan_plans)
9832 return -ENOBUFS;
9833
9834 for (i = 0; i < req->n_scan_plans; i++) {
9835 scan_plan = nla_nest_start(msg, i + 1);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009836 if (!scan_plan)
9837 return -ENOBUFS;
9838
Avraham Stern3b06d272015-10-12 09:51:34 +03009839 if (!scan_plan ||
9840 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
9841 req->scan_plans[i].interval) ||
9842 (req->scan_plans[i].iterations &&
9843 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
9844 req->scan_plans[i].iterations)))
9845 return -ENOBUFS;
9846 nla_nest_end(msg, scan_plan);
9847 }
9848 nla_nest_end(msg, scan_plans);
9849
Luciano Coelho75453cc2015-01-09 14:06:37 +02009850 nla_nest_end(msg, nd);
9851
9852 return 0;
9853}
9854
Johannes Bergff1b6e62011-05-04 15:37:28 +02009855static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
9856{
9857 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9858 struct sk_buff *msg;
9859 void *hdr;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009860 u32 size = NLMSG_DEFAULT_SIZE;
Johannes Bergff1b6e62011-05-04 15:37:28 +02009861
Johannes Berg964dc9e2013-06-03 17:25:34 +02009862 if (!rdev->wiphy.wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +02009863 return -EOPNOTSUPP;
9864
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009865 if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
Johannes Berg2a0e0472013-01-23 22:57:40 +01009866 /* adjust size to have room for all the data */
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009867 size += rdev->wiphy.wowlan_config->tcp->tokens_size +
9868 rdev->wiphy.wowlan_config->tcp->payload_len +
9869 rdev->wiphy.wowlan_config->tcp->wake_len +
9870 rdev->wiphy.wowlan_config->tcp->wake_len / 8;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009871 }
9872
9873 msg = nlmsg_new(size, GFP_KERNEL);
Johannes Bergff1b6e62011-05-04 15:37:28 +02009874 if (!msg)
9875 return -ENOMEM;
9876
Eric W. Biederman15e47302012-09-07 20:12:54 +00009877 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Bergff1b6e62011-05-04 15:37:28 +02009878 NL80211_CMD_GET_WOWLAN);
9879 if (!hdr)
9880 goto nla_put_failure;
9881
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009882 if (rdev->wiphy.wowlan_config) {
Johannes Bergff1b6e62011-05-04 15:37:28 +02009883 struct nlattr *nl_wowlan;
9884
9885 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
9886 if (!nl_wowlan)
9887 goto nla_put_failure;
9888
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009889 if ((rdev->wiphy.wowlan_config->any &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009890 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009891 (rdev->wiphy.wowlan_config->disconnect &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009892 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009893 (rdev->wiphy.wowlan_config->magic_pkt &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009894 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009895 (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009896 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009897 (rdev->wiphy.wowlan_config->eap_identity_req &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009898 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009899 (rdev->wiphy.wowlan_config->four_way_handshake &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009900 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009901 (rdev->wiphy.wowlan_config->rfkill_release &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009902 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
9903 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009904
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009905 if (nl80211_send_wowlan_patterns(msg, rdev))
9906 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009907
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009908 if (nl80211_send_wowlan_tcp(msg,
9909 rdev->wiphy.wowlan_config->tcp))
Johannes Berg2a0e0472013-01-23 22:57:40 +01009910 goto nla_put_failure;
9911
Luciano Coelho75453cc2015-01-09 14:06:37 +02009912 if (nl80211_send_wowlan_nd(
9913 msg,
9914 rdev->wiphy.wowlan_config->nd_config))
9915 goto nla_put_failure;
9916
Johannes Bergff1b6e62011-05-04 15:37:28 +02009917 nla_nest_end(msg, nl_wowlan);
9918 }
9919
9920 genlmsg_end(msg, hdr);
9921 return genlmsg_reply(msg, info);
9922
9923nla_put_failure:
9924 nlmsg_free(msg);
9925 return -ENOBUFS;
9926}
9927
Johannes Berg2a0e0472013-01-23 22:57:40 +01009928static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
9929 struct nlattr *attr,
9930 struct cfg80211_wowlan *trig)
9931{
9932 struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
9933 struct cfg80211_wowlan_tcp *cfg;
9934 struct nl80211_wowlan_tcp_data_token *tok = NULL;
9935 struct nl80211_wowlan_tcp_data_seq *seq = NULL;
9936 u32 size;
9937 u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
9938 int err, port;
9939
Johannes Berg964dc9e2013-06-03 17:25:34 +02009940 if (!rdev->wiphy.wowlan->tcp)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009941 return -EINVAL;
9942
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02009943 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TCP, attr,
9944 nl80211_wowlan_tcp_policy);
Johannes Berg2a0e0472013-01-23 22:57:40 +01009945 if (err)
9946 return err;
9947
9948 if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
9949 !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
9950 !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
9951 !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
9952 !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
9953 !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
9954 !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
9955 !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
9956 return -EINVAL;
9957
9958 data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +02009959 if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009960 return -EINVAL;
9961
9962 if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
Johannes Berg964dc9e2013-06-03 17:25:34 +02009963 rdev->wiphy.wowlan->tcp->data_interval_max ||
Johannes Berg723d5682013-02-26 13:56:40 +01009964 nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009965 return -EINVAL;
9966
9967 wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +02009968 if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009969 return -EINVAL;
9970
9971 wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
9972 if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
9973 return -EINVAL;
9974
9975 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
9976 u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
9977
9978 tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
9979 tokens_size = tokln - sizeof(*tok);
9980
9981 if (!tok->len || tokens_size % tok->len)
9982 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +02009983 if (!rdev->wiphy.wowlan->tcp->tok)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009984 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +02009985 if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009986 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +02009987 if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009988 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +02009989 if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009990 return -EINVAL;
9991 if (tok->offset + tok->len > data_size)
9992 return -EINVAL;
9993 }
9994
9995 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
9996 seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
Johannes Berg964dc9e2013-06-03 17:25:34 +02009997 if (!rdev->wiphy.wowlan->tcp->seq)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009998 return -EINVAL;
9999 if (seq->len == 0 || seq->len > 4)
10000 return -EINVAL;
10001 if (seq->len + seq->offset > data_size)
10002 return -EINVAL;
10003 }
10004
10005 size = sizeof(*cfg);
10006 size += data_size;
10007 size += wake_size + wake_mask_size;
10008 size += tokens_size;
10009
10010 cfg = kzalloc(size, GFP_KERNEL);
10011 if (!cfg)
10012 return -ENOMEM;
Jiri Benc67b61f62015-03-29 16:59:26 +020010013 cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
10014 cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010015 memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
10016 ETH_ALEN);
10017 if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
10018 port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
10019 else
10020 port = 0;
10021#ifdef CONFIG_INET
10022 /* allocate a socket and port for it and use it */
10023 err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
10024 IPPROTO_TCP, &cfg->sock, 1);
10025 if (err) {
10026 kfree(cfg);
10027 return err;
10028 }
10029 if (inet_csk_get_port(cfg->sock->sk, port)) {
10030 sock_release(cfg->sock);
10031 kfree(cfg);
10032 return -EADDRINUSE;
10033 }
10034 cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
10035#else
10036 if (!port) {
10037 kfree(cfg);
10038 return -EINVAL;
10039 }
10040 cfg->src_port = port;
10041#endif
10042
10043 cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
10044 cfg->payload_len = data_size;
10045 cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
10046 memcpy((void *)cfg->payload,
10047 nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
10048 data_size);
10049 if (seq)
10050 cfg->payload_seq = *seq;
10051 cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
10052 cfg->wake_len = wake_size;
10053 cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
10054 memcpy((void *)cfg->wake_data,
10055 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
10056 wake_size);
10057 cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
10058 data_size + wake_size;
10059 memcpy((void *)cfg->wake_mask,
10060 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
10061 wake_mask_size);
10062 if (tok) {
10063 cfg->tokens_size = tokens_size;
10064 memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
10065 }
10066
10067 trig->tcp = cfg;
10068
10069 return 0;
10070}
10071
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010072static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
10073 const struct wiphy_wowlan_support *wowlan,
10074 struct nlattr *attr,
10075 struct cfg80211_wowlan *trig)
10076{
10077 struct nlattr **tb;
10078 int err;
10079
10080 tb = kzalloc(NUM_NL80211_ATTR * sizeof(*tb), GFP_KERNEL);
10081 if (!tb)
10082 return -ENOMEM;
10083
10084 if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
10085 err = -EOPNOTSUPP;
10086 goto out;
10087 }
10088
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010089 err = nla_parse_nested(tb, NL80211_ATTR_MAX, attr, nl80211_policy);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010090 if (err)
10091 goto out;
10092
Arend Van Sprielaad1e812017-01-27 12:27:44 +000010093 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb,
10094 wowlan->max_nd_match_sets);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010095 err = PTR_ERR_OR_ZERO(trig->nd_config);
10096 if (err)
10097 trig->nd_config = NULL;
10098
10099out:
10100 kfree(tb);
10101 return err;
10102}
10103
Johannes Bergff1b6e62011-05-04 15:37:28 +020010104static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
10105{
10106 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10107 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010108 struct cfg80211_wowlan new_triggers = {};
Johannes Bergae33bd82012-07-12 16:25:02 +020010109 struct cfg80211_wowlan *ntrig;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010110 const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010111 int err, i;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010112 bool prev_enabled = rdev->wiphy.wowlan_config;
Johannes Berg98fc4382015-03-01 09:10:13 +020010113 bool regular = false;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010114
Johannes Berg964dc9e2013-06-03 17:25:34 +020010115 if (!wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010116 return -EOPNOTSUPP;
10117
Johannes Bergae33bd82012-07-12 16:25:02 +020010118 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
10119 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010120 rdev->wiphy.wowlan_config = NULL;
Johannes Bergae33bd82012-07-12 16:25:02 +020010121 goto set_wakeup;
10122 }
Johannes Bergff1b6e62011-05-04 15:37:28 +020010123
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010124 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TRIG,
10125 info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
10126 nl80211_wowlan_policy);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010127 if (err)
10128 return err;
10129
10130 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
10131 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
10132 return -EINVAL;
10133 new_triggers.any = true;
10134 }
10135
10136 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
10137 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
10138 return -EINVAL;
10139 new_triggers.disconnect = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010140 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010141 }
10142
10143 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
10144 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
10145 return -EINVAL;
10146 new_triggers.magic_pkt = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010147 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010148 }
10149
Johannes Berg77dbbb12011-07-13 10:48:55 +020010150 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
10151 return -EINVAL;
10152
10153 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
10154 if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
10155 return -EINVAL;
10156 new_triggers.gtk_rekey_failure = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010157 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010158 }
10159
10160 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
10161 if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
10162 return -EINVAL;
10163 new_triggers.eap_identity_req = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010164 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010165 }
10166
10167 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
10168 if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
10169 return -EINVAL;
10170 new_triggers.four_way_handshake = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010171 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010172 }
10173
10174 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
10175 if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
10176 return -EINVAL;
10177 new_triggers.rfkill_release = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010178 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010179 }
10180
Johannes Bergff1b6e62011-05-04 15:37:28 +020010181 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
10182 struct nlattr *pat;
10183 int n_patterns = 0;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010184 int rem, pat_len, mask_len, pkt_offset;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010185 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010186
Johannes Berg98fc4382015-03-01 09:10:13 +020010187 regular = true;
10188
Johannes Bergff1b6e62011-05-04 15:37:28 +020010189 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10190 rem)
10191 n_patterns++;
10192 if (n_patterns > wowlan->n_patterns)
10193 return -EINVAL;
10194
10195 new_triggers.patterns = kcalloc(n_patterns,
10196 sizeof(new_triggers.patterns[0]),
10197 GFP_KERNEL);
10198 if (!new_triggers.patterns)
10199 return -ENOMEM;
10200
10201 new_triggers.n_patterns = n_patterns;
10202 i = 0;
10203
10204 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10205 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010206 u8 *mask_pat;
10207
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010208 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
10209 NULL);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010210 err = -EINVAL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010211 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10212 !pat_tb[NL80211_PKTPAT_PATTERN])
Johannes Bergff1b6e62011-05-04 15:37:28 +020010213 goto error;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010214 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010215 mask_len = DIV_ROUND_UP(pat_len, 8);
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010216 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010217 goto error;
10218 if (pat_len > wowlan->pattern_max_len ||
10219 pat_len < wowlan->pattern_min_len)
10220 goto error;
10221
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010222 if (!pat_tb[NL80211_PKTPAT_OFFSET])
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010223 pkt_offset = 0;
10224 else
10225 pkt_offset = nla_get_u32(
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010226 pat_tb[NL80211_PKTPAT_OFFSET]);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010227 if (pkt_offset > wowlan->max_pkt_offset)
10228 goto error;
10229 new_triggers.patterns[i].pkt_offset = pkt_offset;
10230
Johannes Berg922bd802014-05-19 17:59:50 +020010231 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10232 if (!mask_pat) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010233 err = -ENOMEM;
10234 goto error;
10235 }
Johannes Berg922bd802014-05-19 17:59:50 +020010236 new_triggers.patterns[i].mask = mask_pat;
10237 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010238 mask_len);
Johannes Berg922bd802014-05-19 17:59:50 +020010239 mask_pat += mask_len;
10240 new_triggers.patterns[i].pattern = mask_pat;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010241 new_triggers.patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010242 memcpy(mask_pat,
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010243 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010244 pat_len);
10245 i++;
10246 }
10247 }
10248
Johannes Berg2a0e0472013-01-23 22:57:40 +010010249 if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010250 regular = true;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010251 err = nl80211_parse_wowlan_tcp(
10252 rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
10253 &new_triggers);
10254 if (err)
10255 goto error;
10256 }
10257
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010258 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010259 regular = true;
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010260 err = nl80211_parse_wowlan_nd(
10261 rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
10262 &new_triggers);
10263 if (err)
10264 goto error;
10265 }
10266
Johannes Berg98fc4382015-03-01 09:10:13 +020010267 /* The 'any' trigger means the device continues operating more or less
10268 * as in its normal operation mode and wakes up the host on most of the
10269 * normal interrupts (like packet RX, ...)
10270 * It therefore makes little sense to combine with the more constrained
10271 * wakeup trigger modes.
10272 */
10273 if (new_triggers.any && regular) {
10274 err = -EINVAL;
10275 goto error;
10276 }
10277
Johannes Bergae33bd82012-07-12 16:25:02 +020010278 ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
10279 if (!ntrig) {
10280 err = -ENOMEM;
10281 goto error;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010282 }
Johannes Bergae33bd82012-07-12 16:25:02 +020010283 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010284 rdev->wiphy.wowlan_config = ntrig;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010285
Johannes Bergae33bd82012-07-12 16:25:02 +020010286 set_wakeup:
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010287 if (rdev->ops->set_wakeup &&
10288 prev_enabled != !!rdev->wiphy.wowlan_config)
10289 rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
Johannes Berg6d525632012-04-04 15:05:25 +020010290
Johannes Bergff1b6e62011-05-04 15:37:28 +020010291 return 0;
10292 error:
10293 for (i = 0; i < new_triggers.n_patterns; i++)
10294 kfree(new_triggers.patterns[i].mask);
10295 kfree(new_triggers.patterns);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010296 if (new_triggers.tcp && new_triggers.tcp->sock)
10297 sock_release(new_triggers.tcp->sock);
10298 kfree(new_triggers.tcp);
Ola Olssone5dbe072015-12-12 23:17:17 +010010299 kfree(new_triggers.nd_config);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010300 return err;
10301}
Johannes Bergdfb89c52012-06-27 09:23:48 +020010302#endif
Johannes Bergff1b6e62011-05-04 15:37:28 +020010303
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010304static int nl80211_send_coalesce_rules(struct sk_buff *msg,
10305 struct cfg80211_registered_device *rdev)
10306{
10307 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
10308 int i, j, pat_len;
10309 struct cfg80211_coalesce_rules *rule;
10310
10311 if (!rdev->coalesce->n_rules)
10312 return 0;
10313
10314 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
10315 if (!nl_rules)
10316 return -ENOBUFS;
10317
10318 for (i = 0; i < rdev->coalesce->n_rules; i++) {
10319 nl_rule = nla_nest_start(msg, i + 1);
10320 if (!nl_rule)
10321 return -ENOBUFS;
10322
10323 rule = &rdev->coalesce->rules[i];
10324 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
10325 rule->delay))
10326 return -ENOBUFS;
10327
10328 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
10329 rule->condition))
10330 return -ENOBUFS;
10331
10332 nl_pats = nla_nest_start(msg,
10333 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
10334 if (!nl_pats)
10335 return -ENOBUFS;
10336
10337 for (j = 0; j < rule->n_patterns; j++) {
10338 nl_pat = nla_nest_start(msg, j + 1);
10339 if (!nl_pat)
10340 return -ENOBUFS;
10341 pat_len = rule->patterns[j].pattern_len;
10342 if (nla_put(msg, NL80211_PKTPAT_MASK,
10343 DIV_ROUND_UP(pat_len, 8),
10344 rule->patterns[j].mask) ||
10345 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
10346 rule->patterns[j].pattern) ||
10347 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
10348 rule->patterns[j].pkt_offset))
10349 return -ENOBUFS;
10350 nla_nest_end(msg, nl_pat);
10351 }
10352 nla_nest_end(msg, nl_pats);
10353 nla_nest_end(msg, nl_rule);
10354 }
10355 nla_nest_end(msg, nl_rules);
10356
10357 return 0;
10358}
10359
10360static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
10361{
10362 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10363 struct sk_buff *msg;
10364 void *hdr;
10365
10366 if (!rdev->wiphy.coalesce)
10367 return -EOPNOTSUPP;
10368
10369 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10370 if (!msg)
10371 return -ENOMEM;
10372
10373 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10374 NL80211_CMD_GET_COALESCE);
10375 if (!hdr)
10376 goto nla_put_failure;
10377
10378 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
10379 goto nla_put_failure;
10380
10381 genlmsg_end(msg, hdr);
10382 return genlmsg_reply(msg, info);
10383
10384nla_put_failure:
10385 nlmsg_free(msg);
10386 return -ENOBUFS;
10387}
10388
10389void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
10390{
10391 struct cfg80211_coalesce *coalesce = rdev->coalesce;
10392 int i, j;
10393 struct cfg80211_coalesce_rules *rule;
10394
10395 if (!coalesce)
10396 return;
10397
10398 for (i = 0; i < coalesce->n_rules; i++) {
10399 rule = &coalesce->rules[i];
10400 for (j = 0; j < rule->n_patterns; j++)
10401 kfree(rule->patterns[j].mask);
10402 kfree(rule->patterns);
10403 }
10404 kfree(coalesce->rules);
10405 kfree(coalesce);
10406 rdev->coalesce = NULL;
10407}
10408
10409static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
10410 struct nlattr *rule,
10411 struct cfg80211_coalesce_rules *new_rule)
10412{
10413 int err, i;
10414 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10415 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
10416 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
10417 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
10418
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010419 err = nla_parse_nested(tb, NL80211_ATTR_COALESCE_RULE_MAX, rule,
10420 nl80211_coalesce_policy);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010421 if (err)
10422 return err;
10423
10424 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
10425 new_rule->delay =
10426 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
10427 if (new_rule->delay > coalesce->max_delay)
10428 return -EINVAL;
10429
10430 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
10431 new_rule->condition =
10432 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
10433 if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
10434 new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
10435 return -EINVAL;
10436
10437 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
10438 return -EINVAL;
10439
10440 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10441 rem)
10442 n_patterns++;
10443 if (n_patterns > coalesce->n_patterns)
10444 return -EINVAL;
10445
10446 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
10447 GFP_KERNEL);
10448 if (!new_rule->patterns)
10449 return -ENOMEM;
10450
10451 new_rule->n_patterns = n_patterns;
10452 i = 0;
10453
10454 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10455 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010456 u8 *mask_pat;
10457
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010458 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010459 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10460 !pat_tb[NL80211_PKTPAT_PATTERN])
10461 return -EINVAL;
10462 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
10463 mask_len = DIV_ROUND_UP(pat_len, 8);
10464 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
10465 return -EINVAL;
10466 if (pat_len > coalesce->pattern_max_len ||
10467 pat_len < coalesce->pattern_min_len)
10468 return -EINVAL;
10469
10470 if (!pat_tb[NL80211_PKTPAT_OFFSET])
10471 pkt_offset = 0;
10472 else
10473 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
10474 if (pkt_offset > coalesce->max_pkt_offset)
10475 return -EINVAL;
10476 new_rule->patterns[i].pkt_offset = pkt_offset;
10477
Johannes Berg922bd802014-05-19 17:59:50 +020010478 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10479 if (!mask_pat)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010480 return -ENOMEM;
Johannes Berg922bd802014-05-19 17:59:50 +020010481
10482 new_rule->patterns[i].mask = mask_pat;
10483 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
10484 mask_len);
10485
10486 mask_pat += mask_len;
10487 new_rule->patterns[i].pattern = mask_pat;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010488 new_rule->patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010489 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
10490 pat_len);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010491 i++;
10492 }
10493
10494 return 0;
10495}
10496
10497static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
10498{
10499 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10500 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10501 struct cfg80211_coalesce new_coalesce = {};
10502 struct cfg80211_coalesce *n_coalesce;
10503 int err, rem_rule, n_rules = 0, i, j;
10504 struct nlattr *rule;
10505 struct cfg80211_coalesce_rules *tmp_rule;
10506
10507 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
10508 return -EOPNOTSUPP;
10509
10510 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
10511 cfg80211_rdev_free_coalesce(rdev);
Ilan Peera1056b1b2015-10-22 22:27:46 +030010512 rdev_set_coalesce(rdev, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010513 return 0;
10514 }
10515
10516 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10517 rem_rule)
10518 n_rules++;
10519 if (n_rules > coalesce->n_rules)
10520 return -EINVAL;
10521
10522 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
10523 GFP_KERNEL);
10524 if (!new_coalesce.rules)
10525 return -ENOMEM;
10526
10527 new_coalesce.n_rules = n_rules;
10528 i = 0;
10529
10530 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10531 rem_rule) {
10532 err = nl80211_parse_coalesce_rule(rdev, rule,
10533 &new_coalesce.rules[i]);
10534 if (err)
10535 goto error;
10536
10537 i++;
10538 }
10539
Ilan Peera1056b1b2015-10-22 22:27:46 +030010540 err = rdev_set_coalesce(rdev, &new_coalesce);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010541 if (err)
10542 goto error;
10543
10544 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
10545 if (!n_coalesce) {
10546 err = -ENOMEM;
10547 goto error;
10548 }
10549 cfg80211_rdev_free_coalesce(rdev);
10550 rdev->coalesce = n_coalesce;
10551
10552 return 0;
10553error:
10554 for (i = 0; i < new_coalesce.n_rules; i++) {
10555 tmp_rule = &new_coalesce.rules[i];
10556 for (j = 0; j < tmp_rule->n_patterns; j++)
10557 kfree(tmp_rule->patterns[j].mask);
10558 kfree(tmp_rule->patterns);
10559 }
10560 kfree(new_coalesce.rules);
10561
10562 return err;
10563}
10564
Johannes Berge5497d72011-07-05 16:35:40 +020010565static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
10566{
10567 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10568 struct net_device *dev = info->user_ptr[1];
10569 struct wireless_dev *wdev = dev->ieee80211_ptr;
10570 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
10571 struct cfg80211_gtk_rekey_data rekey_data;
10572 int err;
10573
10574 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
10575 return -EINVAL;
10576
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010577 err = nla_parse_nested(tb, MAX_NL80211_REKEY_DATA,
10578 info->attrs[NL80211_ATTR_REKEY_DATA],
10579 nl80211_rekey_policy);
Johannes Berge5497d72011-07-05 16:35:40 +020010580 if (err)
10581 return err;
10582
10583 if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
10584 return -ERANGE;
10585 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
10586 return -ERANGE;
10587 if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
10588 return -ERANGE;
10589
Johannes Berg78f686c2014-09-10 22:28:06 +030010590 rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
10591 rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
10592 rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
Johannes Berge5497d72011-07-05 16:35:40 +020010593
10594 wdev_lock(wdev);
10595 if (!wdev->current_bss) {
10596 err = -ENOTCONN;
10597 goto out;
10598 }
10599
10600 if (!rdev->ops->set_rekey_data) {
10601 err = -EOPNOTSUPP;
10602 goto out;
10603 }
10604
Hila Gonene35e4d22012-06-27 17:19:42 +030010605 err = rdev_set_rekey_data(rdev, dev, &rekey_data);
Johannes Berge5497d72011-07-05 16:35:40 +020010606 out:
10607 wdev_unlock(wdev);
10608 return err;
10609}
10610
Johannes Berg28946da2011-11-04 11:18:12 +010010611static int nl80211_register_unexpected_frame(struct sk_buff *skb,
10612 struct genl_info *info)
10613{
10614 struct net_device *dev = info->user_ptr[1];
10615 struct wireless_dev *wdev = dev->ieee80211_ptr;
10616
10617 if (wdev->iftype != NL80211_IFTYPE_AP &&
10618 wdev->iftype != NL80211_IFTYPE_P2P_GO)
10619 return -EINVAL;
10620
Eric W. Biederman15e47302012-09-07 20:12:54 +000010621 if (wdev->ap_unexpected_nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010010622 return -EBUSY;
10623
Eric W. Biederman15e47302012-09-07 20:12:54 +000010624 wdev->ap_unexpected_nlportid = info->snd_portid;
Johannes Berg28946da2011-11-04 11:18:12 +010010625 return 0;
10626}
10627
Johannes Berg7f6cf312011-11-04 11:18:15 +010010628static int nl80211_probe_client(struct sk_buff *skb,
10629 struct genl_info *info)
10630{
10631 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10632 struct net_device *dev = info->user_ptr[1];
10633 struct wireless_dev *wdev = dev->ieee80211_ptr;
10634 struct sk_buff *msg;
10635 void *hdr;
10636 const u8 *addr;
10637 u64 cookie;
10638 int err;
10639
10640 if (wdev->iftype != NL80211_IFTYPE_AP &&
10641 wdev->iftype != NL80211_IFTYPE_P2P_GO)
10642 return -EOPNOTSUPP;
10643
10644 if (!info->attrs[NL80211_ATTR_MAC])
10645 return -EINVAL;
10646
10647 if (!rdev->ops->probe_client)
10648 return -EOPNOTSUPP;
10649
10650 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10651 if (!msg)
10652 return -ENOMEM;
10653
Eric W. Biederman15e47302012-09-07 20:12:54 +000010654 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg7f6cf312011-11-04 11:18:15 +010010655 NL80211_CMD_PROBE_CLIENT);
Dan Carpentercb35fba2013-08-14 14:50:01 +030010656 if (!hdr) {
10657 err = -ENOBUFS;
Johannes Berg7f6cf312011-11-04 11:18:15 +010010658 goto free_msg;
10659 }
10660
10661 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
10662
Hila Gonene35e4d22012-06-27 17:19:42 +030010663 err = rdev_probe_client(rdev, dev, addr, &cookie);
Johannes Berg7f6cf312011-11-04 11:18:15 +010010664 if (err)
10665 goto free_msg;
10666
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020010667 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
10668 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040010669 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010010670
10671 genlmsg_end(msg, hdr);
10672
10673 return genlmsg_reply(msg, info);
10674
10675 nla_put_failure:
10676 err = -ENOBUFS;
10677 free_msg:
10678 nlmsg_free(msg);
10679 return err;
10680}
10681
Johannes Berg5e760232011-11-04 11:18:17 +010010682static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
10683{
10684 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Ben Greear37c73b52012-10-26 14:49:25 -070010685 struct cfg80211_beacon_registration *reg, *nreg;
10686 int rv;
Johannes Berg5e760232011-11-04 11:18:17 +010010687
10688 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
10689 return -EOPNOTSUPP;
10690
Ben Greear37c73b52012-10-26 14:49:25 -070010691 nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
10692 if (!nreg)
10693 return -ENOMEM;
Johannes Berg5e760232011-11-04 11:18:17 +010010694
Ben Greear37c73b52012-10-26 14:49:25 -070010695 /* First, check if already registered. */
10696 spin_lock_bh(&rdev->beacon_registrations_lock);
10697 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
10698 if (reg->nlportid == info->snd_portid) {
10699 rv = -EALREADY;
10700 goto out_err;
10701 }
10702 }
10703 /* Add it to the list */
10704 nreg->nlportid = info->snd_portid;
10705 list_add(&nreg->list, &rdev->beacon_registrations);
10706
10707 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010010708
10709 return 0;
Ben Greear37c73b52012-10-26 14:49:25 -070010710out_err:
10711 spin_unlock_bh(&rdev->beacon_registrations_lock);
10712 kfree(nreg);
10713 return rv;
Johannes Berg5e760232011-11-04 11:18:17 +010010714}
10715
Johannes Berg98104fde2012-06-16 00:19:54 +020010716static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
10717{
10718 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10719 struct wireless_dev *wdev = info->user_ptr[1];
10720 int err;
10721
10722 if (!rdev->ops->start_p2p_device)
10723 return -EOPNOTSUPP;
10724
10725 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
10726 return -EOPNOTSUPP;
10727
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010728 if (wdev_running(wdev))
Johannes Berg98104fde2012-06-16 00:19:54 +020010729 return 0;
10730
Luciano Coelhob6a55012014-02-27 11:07:21 +020010731 if (rfkill_blocked(rdev->rfkill))
10732 return -ERFKILL;
Johannes Berg98104fde2012-06-16 00:19:54 +020010733
Johannes Bergeeb126e2012-10-23 15:16:50 +020010734 err = rdev_start_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020010735 if (err)
10736 return err;
10737
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010738 wdev->is_running = true;
Johannes Berg98104fde2012-06-16 00:19:54 +020010739 rdev->opencount++;
Johannes Berg98104fde2012-06-16 00:19:54 +020010740
10741 return 0;
10742}
10743
10744static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
10745{
10746 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10747 struct wireless_dev *wdev = info->user_ptr[1];
10748
10749 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
10750 return -EOPNOTSUPP;
10751
10752 if (!rdev->ops->stop_p2p_device)
10753 return -EOPNOTSUPP;
10754
Johannes Bergf9f47522013-03-19 15:04:07 +010010755 cfg80211_stop_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020010756
10757 return 0;
10758}
10759
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010760static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
10761{
10762 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10763 struct wireless_dev *wdev = info->user_ptr[1];
10764 struct cfg80211_nan_conf conf = {};
10765 int err;
10766
10767 if (wdev->iftype != NL80211_IFTYPE_NAN)
10768 return -EOPNOTSUPP;
10769
Johannes Bergeeb04a92016-11-21 13:55:48 +010010770 if (wdev_running(wdev))
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010771 return -EEXIST;
10772
10773 if (rfkill_blocked(rdev->rfkill))
10774 return -ERFKILL;
10775
10776 if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
10777 return -EINVAL;
10778
10779 if (!info->attrs[NL80211_ATTR_NAN_DUAL])
10780 return -EINVAL;
10781
10782 conf.master_pref =
10783 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
10784 if (!conf.master_pref)
10785 return -EINVAL;
10786
10787 conf.dual = nla_get_u8(info->attrs[NL80211_ATTR_NAN_DUAL]);
10788
10789 err = rdev_start_nan(rdev, wdev, &conf);
10790 if (err)
10791 return err;
10792
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010793 wdev->is_running = true;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010794 rdev->opencount++;
10795
10796 return 0;
10797}
10798
10799static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
10800{
10801 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10802 struct wireless_dev *wdev = info->user_ptr[1];
10803
10804 if (wdev->iftype != NL80211_IFTYPE_NAN)
10805 return -EOPNOTSUPP;
10806
10807 cfg80211_stop_nan(rdev, wdev);
10808
10809 return 0;
10810}
10811
Ayala Bekera442b762016-09-20 17:31:15 +030010812static int validate_nan_filter(struct nlattr *filter_attr)
10813{
10814 struct nlattr *attr;
10815 int len = 0, n_entries = 0, rem;
10816
10817 nla_for_each_nested(attr, filter_attr, rem) {
10818 len += nla_len(attr);
10819 n_entries++;
10820 }
10821
10822 if (len >= U8_MAX)
10823 return -EINVAL;
10824
10825 return n_entries;
10826}
10827
10828static int handle_nan_filter(struct nlattr *attr_filter,
10829 struct cfg80211_nan_func *func,
10830 bool tx)
10831{
10832 struct nlattr *attr;
10833 int n_entries, rem, i;
10834 struct cfg80211_nan_func_filter *filter;
10835
10836 n_entries = validate_nan_filter(attr_filter);
10837 if (n_entries < 0)
10838 return n_entries;
10839
10840 BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
10841
10842 filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
10843 if (!filter)
10844 return -ENOMEM;
10845
10846 i = 0;
10847 nla_for_each_nested(attr, attr_filter, rem) {
Thomas Grafb15ca182016-10-26 10:53:16 +020010848 filter[i].filter = nla_memdup(attr, GFP_KERNEL);
Ayala Bekera442b762016-09-20 17:31:15 +030010849 filter[i].len = nla_len(attr);
10850 i++;
10851 }
10852 if (tx) {
10853 func->num_tx_filters = n_entries;
10854 func->tx_filters = filter;
10855 } else {
10856 func->num_rx_filters = n_entries;
10857 func->rx_filters = filter;
10858 }
10859
10860 return 0;
10861}
10862
10863static int nl80211_nan_add_func(struct sk_buff *skb,
10864 struct genl_info *info)
10865{
10866 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10867 struct wireless_dev *wdev = info->user_ptr[1];
10868 struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
10869 struct cfg80211_nan_func *func;
10870 struct sk_buff *msg = NULL;
10871 void *hdr = NULL;
10872 int err = 0;
10873
10874 if (wdev->iftype != NL80211_IFTYPE_NAN)
10875 return -EOPNOTSUPP;
10876
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010877 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030010878 return -ENOTCONN;
10879
10880 if (!info->attrs[NL80211_ATTR_NAN_FUNC])
10881 return -EINVAL;
10882
10883 if (wdev->owner_nlportid &&
10884 wdev->owner_nlportid != info->snd_portid)
10885 return -ENOTCONN;
10886
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010887 err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,
10888 info->attrs[NL80211_ATTR_NAN_FUNC],
10889 nl80211_nan_func_policy);
Ayala Bekera442b762016-09-20 17:31:15 +030010890 if (err)
10891 return err;
10892
10893 func = kzalloc(sizeof(*func), GFP_KERNEL);
10894 if (!func)
10895 return -ENOMEM;
10896
10897 func->cookie = wdev->wiphy->cookie_counter++;
10898
10899 if (!tb[NL80211_NAN_FUNC_TYPE] ||
10900 nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) {
10901 err = -EINVAL;
10902 goto out;
10903 }
10904
10905
10906 func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
10907
10908 if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
10909 err = -EINVAL;
10910 goto out;
10911 }
10912
10913 memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
10914 sizeof(func->service_id));
10915
10916 func->close_range =
10917 nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
10918
10919 if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
10920 func->serv_spec_info_len =
10921 nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
10922 func->serv_spec_info =
10923 kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
10924 func->serv_spec_info_len,
10925 GFP_KERNEL);
10926 if (!func->serv_spec_info) {
10927 err = -ENOMEM;
10928 goto out;
10929 }
10930 }
10931
10932 if (tb[NL80211_NAN_FUNC_TTL])
10933 func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
10934
10935 switch (func->type) {
10936 case NL80211_NAN_FUNC_PUBLISH:
10937 if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
10938 err = -EINVAL;
10939 goto out;
10940 }
10941
10942 func->publish_type =
10943 nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
10944 func->publish_bcast =
10945 nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
10946
10947 if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
10948 func->publish_bcast) {
10949 err = -EINVAL;
10950 goto out;
10951 }
10952 break;
10953 case NL80211_NAN_FUNC_SUBSCRIBE:
10954 func->subscribe_active =
10955 nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
10956 break;
10957 case NL80211_NAN_FUNC_FOLLOW_UP:
10958 if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
10959 !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]) {
10960 err = -EINVAL;
10961 goto out;
10962 }
10963
10964 func->followup_id =
10965 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
10966 func->followup_reqid =
10967 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
10968 memcpy(func->followup_dest.addr,
10969 nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
10970 sizeof(func->followup_dest.addr));
10971 if (func->ttl) {
10972 err = -EINVAL;
10973 goto out;
10974 }
10975 break;
10976 default:
10977 err = -EINVAL;
10978 goto out;
10979 }
10980
10981 if (tb[NL80211_NAN_FUNC_SRF]) {
10982 struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
10983
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010984 err = nla_parse_nested(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
10985 tb[NL80211_NAN_FUNC_SRF],
10986 nl80211_nan_srf_policy);
Ayala Bekera442b762016-09-20 17:31:15 +030010987 if (err)
10988 goto out;
10989
10990 func->srf_include =
10991 nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
10992
10993 if (srf_tb[NL80211_NAN_SRF_BF]) {
10994 if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
10995 !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
10996 err = -EINVAL;
10997 goto out;
10998 }
10999
11000 func->srf_bf_len =
11001 nla_len(srf_tb[NL80211_NAN_SRF_BF]);
11002 func->srf_bf =
11003 kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
11004 func->srf_bf_len, GFP_KERNEL);
11005 if (!func->srf_bf) {
11006 err = -ENOMEM;
11007 goto out;
11008 }
11009
11010 func->srf_bf_idx =
11011 nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
11012 } else {
11013 struct nlattr *attr, *mac_attr =
11014 srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
11015 int n_entries, rem, i = 0;
11016
11017 if (!mac_attr) {
11018 err = -EINVAL;
11019 goto out;
11020 }
11021
11022 n_entries = validate_acl_mac_addrs(mac_attr);
11023 if (n_entries <= 0) {
11024 err = -EINVAL;
11025 goto out;
11026 }
11027
11028 func->srf_num_macs = n_entries;
11029 func->srf_macs =
11030 kzalloc(sizeof(*func->srf_macs) * n_entries,
11031 GFP_KERNEL);
11032 if (!func->srf_macs) {
11033 err = -ENOMEM;
11034 goto out;
11035 }
11036
11037 nla_for_each_nested(attr, mac_attr, rem)
11038 memcpy(func->srf_macs[i++].addr, nla_data(attr),
11039 sizeof(*func->srf_macs));
11040 }
11041 }
11042
11043 if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
11044 err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
11045 func, true);
11046 if (err)
11047 goto out;
11048 }
11049
11050 if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
11051 err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
11052 func, false);
11053 if (err)
11054 goto out;
11055 }
11056
11057 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11058 if (!msg) {
11059 err = -ENOMEM;
11060 goto out;
11061 }
11062
11063 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11064 NL80211_CMD_ADD_NAN_FUNCTION);
11065 /* This can't really happen - we just allocated 4KB */
11066 if (WARN_ON(!hdr)) {
11067 err = -ENOMEM;
11068 goto out;
11069 }
11070
11071 err = rdev_add_nan_func(rdev, wdev, func);
11072out:
11073 if (err < 0) {
11074 cfg80211_free_nan_func(func);
11075 nlmsg_free(msg);
11076 return err;
11077 }
11078
11079 /* propagate the instance id and cookie to userspace */
11080 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
11081 NL80211_ATTR_PAD))
11082 goto nla_put_failure;
11083
11084 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11085 if (!func_attr)
11086 goto nla_put_failure;
11087
11088 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
11089 func->instance_id))
11090 goto nla_put_failure;
11091
11092 nla_nest_end(msg, func_attr);
11093
11094 genlmsg_end(msg, hdr);
11095 return genlmsg_reply(msg, info);
11096
11097nla_put_failure:
11098 nlmsg_free(msg);
11099 return -ENOBUFS;
11100}
11101
11102static int nl80211_nan_del_func(struct sk_buff *skb,
11103 struct genl_info *info)
11104{
11105 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11106 struct wireless_dev *wdev = info->user_ptr[1];
11107 u64 cookie;
11108
11109 if (wdev->iftype != NL80211_IFTYPE_NAN)
11110 return -EOPNOTSUPP;
11111
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011112 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030011113 return -ENOTCONN;
11114
11115 if (!info->attrs[NL80211_ATTR_COOKIE])
11116 return -EINVAL;
11117
11118 if (wdev->owner_nlportid &&
11119 wdev->owner_nlportid != info->snd_portid)
11120 return -ENOTCONN;
11121
11122 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
11123
11124 rdev_del_nan_func(rdev, wdev, cookie);
11125
11126 return 0;
11127}
11128
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011129static int nl80211_nan_change_config(struct sk_buff *skb,
11130 struct genl_info *info)
11131{
11132 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11133 struct wireless_dev *wdev = info->user_ptr[1];
11134 struct cfg80211_nan_conf conf = {};
11135 u32 changed = 0;
11136
11137 if (wdev->iftype != NL80211_IFTYPE_NAN)
11138 return -EOPNOTSUPP;
11139
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011140 if (!wdev_running(wdev))
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011141 return -ENOTCONN;
11142
11143 if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
11144 conf.master_pref =
11145 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11146 if (conf.master_pref <= 1 || conf.master_pref == 255)
11147 return -EINVAL;
11148
11149 changed |= CFG80211_NAN_CONF_CHANGED_PREF;
11150 }
11151
11152 if (info->attrs[NL80211_ATTR_NAN_DUAL]) {
11153 conf.dual = nla_get_u8(info->attrs[NL80211_ATTR_NAN_DUAL]);
11154 changed |= CFG80211_NAN_CONF_CHANGED_DUAL;
11155 }
11156
11157 if (!changed)
11158 return -EINVAL;
11159
11160 return rdev_nan_change_conf(rdev, wdev, &conf, changed);
11161}
11162
Ayala Beker50bcd312016-09-20 17:31:17 +030011163void cfg80211_nan_match(struct wireless_dev *wdev,
11164 struct cfg80211_nan_match_params *match, gfp_t gfp)
11165{
11166 struct wiphy *wiphy = wdev->wiphy;
11167 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11168 struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
11169 struct sk_buff *msg;
11170 void *hdr;
11171
11172 if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
11173 return;
11174
11175 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11176 if (!msg)
11177 return;
11178
11179 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
11180 if (!hdr) {
11181 nlmsg_free(msg);
11182 return;
11183 }
11184
11185 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11186 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11187 wdev->netdev->ifindex)) ||
11188 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11189 NL80211_ATTR_PAD))
11190 goto nla_put_failure;
11191
11192 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
11193 NL80211_ATTR_PAD) ||
11194 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
11195 goto nla_put_failure;
11196
11197 match_attr = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH);
11198 if (!match_attr)
11199 goto nla_put_failure;
11200
11201 local_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_LOCAL);
11202 if (!local_func_attr)
11203 goto nla_put_failure;
11204
11205 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
11206 goto nla_put_failure;
11207
11208 nla_nest_end(msg, local_func_attr);
11209
11210 peer_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_PEER);
11211 if (!peer_func_attr)
11212 goto nla_put_failure;
11213
11214 if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
11215 nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
11216 goto nla_put_failure;
11217
11218 if (match->info && match->info_len &&
11219 nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
11220 match->info))
11221 goto nla_put_failure;
11222
11223 nla_nest_end(msg, peer_func_attr);
11224 nla_nest_end(msg, match_attr);
11225 genlmsg_end(msg, hdr);
11226
11227 if (!wdev->owner_nlportid)
11228 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11229 msg, 0, NL80211_MCGRP_NAN, gfp);
11230 else
11231 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11232 wdev->owner_nlportid);
11233
11234 return;
11235
11236nla_put_failure:
11237 nlmsg_free(msg);
11238}
11239EXPORT_SYMBOL(cfg80211_nan_match);
11240
Ayala Beker368e5a72016-09-20 17:31:18 +030011241void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
11242 u8 inst_id,
11243 enum nl80211_nan_func_term_reason reason,
11244 u64 cookie, gfp_t gfp)
11245{
11246 struct wiphy *wiphy = wdev->wiphy;
11247 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11248 struct sk_buff *msg;
11249 struct nlattr *func_attr;
11250 void *hdr;
11251
11252 if (WARN_ON(!inst_id))
11253 return;
11254
11255 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11256 if (!msg)
11257 return;
11258
11259 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
11260 if (!hdr) {
11261 nlmsg_free(msg);
11262 return;
11263 }
11264
11265 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11266 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11267 wdev->netdev->ifindex)) ||
11268 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11269 NL80211_ATTR_PAD))
11270 goto nla_put_failure;
11271
11272 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11273 NL80211_ATTR_PAD))
11274 goto nla_put_failure;
11275
11276 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11277 if (!func_attr)
11278 goto nla_put_failure;
11279
11280 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
11281 nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
11282 goto nla_put_failure;
11283
11284 nla_nest_end(msg, func_attr);
11285 genlmsg_end(msg, hdr);
11286
11287 if (!wdev->owner_nlportid)
11288 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11289 msg, 0, NL80211_MCGRP_NAN, gfp);
11290 else
11291 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11292 wdev->owner_nlportid);
11293
11294 return;
11295
11296nla_put_failure:
11297 nlmsg_free(msg);
11298}
11299EXPORT_SYMBOL(cfg80211_nan_func_terminated);
11300
Johannes Berg3713b4e2013-02-14 16:19:38 +010011301static int nl80211_get_protocol_features(struct sk_buff *skb,
11302 struct genl_info *info)
11303{
11304 void *hdr;
11305 struct sk_buff *msg;
11306
11307 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11308 if (!msg)
11309 return -ENOMEM;
11310
11311 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11312 NL80211_CMD_GET_PROTOCOL_FEATURES);
11313 if (!hdr)
11314 goto nla_put_failure;
11315
11316 if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
11317 NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
11318 goto nla_put_failure;
11319
11320 genlmsg_end(msg, hdr);
11321 return genlmsg_reply(msg, info);
11322
11323 nla_put_failure:
11324 kfree_skb(msg);
11325 return -ENOBUFS;
11326}
11327
Jouni Malinen355199e2013-02-27 17:14:27 +020011328static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
11329{
11330 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11331 struct cfg80211_update_ft_ies_params ft_params;
11332 struct net_device *dev = info->user_ptr[1];
11333
11334 if (!rdev->ops->update_ft_ies)
11335 return -EOPNOTSUPP;
11336
11337 if (!info->attrs[NL80211_ATTR_MDID] ||
11338 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
11339 return -EINVAL;
11340
11341 memset(&ft_params, 0, sizeof(ft_params));
11342 ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
11343 ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
11344 ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
11345
11346 return rdev_update_ft_ies(rdev, dev, &ft_params);
11347}
11348
Arend van Spriel5de17982013-04-18 15:49:00 +020011349static int nl80211_crit_protocol_start(struct sk_buff *skb,
11350 struct genl_info *info)
11351{
11352 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11353 struct wireless_dev *wdev = info->user_ptr[1];
11354 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
11355 u16 duration;
11356 int ret;
11357
11358 if (!rdev->ops->crit_proto_start)
11359 return -EOPNOTSUPP;
11360
11361 if (WARN_ON(!rdev->ops->crit_proto_stop))
11362 return -EINVAL;
11363
11364 if (rdev->crit_proto_nlportid)
11365 return -EBUSY;
11366
11367 /* determine protocol if provided */
11368 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
11369 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
11370
11371 if (proto >= NUM_NL80211_CRIT_PROTO)
11372 return -EINVAL;
11373
11374 /* timeout must be provided */
11375 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
11376 return -EINVAL;
11377
11378 duration =
11379 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
11380
11381 if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
11382 return -ERANGE;
11383
11384 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
11385 if (!ret)
11386 rdev->crit_proto_nlportid = info->snd_portid;
11387
11388 return ret;
11389}
11390
11391static int nl80211_crit_protocol_stop(struct sk_buff *skb,
11392 struct genl_info *info)
11393{
11394 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11395 struct wireless_dev *wdev = info->user_ptr[1];
11396
11397 if (!rdev->ops->crit_proto_stop)
11398 return -EOPNOTSUPP;
11399
11400 if (rdev->crit_proto_nlportid) {
11401 rdev->crit_proto_nlportid = 0;
11402 rdev_crit_proto_stop(rdev, wdev);
11403 }
11404 return 0;
11405}
11406
Johannes Bergad7e7182013-11-13 13:37:47 +010011407static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
11408{
11409 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11410 struct wireless_dev *wdev =
11411 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
11412 int i, err;
11413 u32 vid, subcmd;
11414
11415 if (!rdev->wiphy.vendor_commands)
11416 return -EOPNOTSUPP;
11417
11418 if (IS_ERR(wdev)) {
11419 err = PTR_ERR(wdev);
11420 if (err != -EINVAL)
11421 return err;
11422 wdev = NULL;
11423 } else if (wdev->wiphy != &rdev->wiphy) {
11424 return -EINVAL;
11425 }
11426
11427 if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
11428 !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
11429 return -EINVAL;
11430
11431 vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
11432 subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
11433 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
11434 const struct wiphy_vendor_command *vcmd;
11435 void *data = NULL;
11436 int len = 0;
11437
11438 vcmd = &rdev->wiphy.vendor_commands[i];
11439
11440 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11441 continue;
11442
11443 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11444 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
11445 if (!wdev)
11446 return -EINVAL;
11447 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
11448 !wdev->netdev)
11449 return -EINVAL;
11450
11451 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011452 if (!wdev_running(wdev))
Johannes Bergad7e7182013-11-13 13:37:47 +010011453 return -ENETDOWN;
11454 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030011455
11456 if (!vcmd->doit)
11457 return -EOPNOTSUPP;
Johannes Bergad7e7182013-11-13 13:37:47 +010011458 } else {
11459 wdev = NULL;
11460 }
11461
11462 if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
11463 data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11464 len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11465 }
11466
11467 rdev->cur_cmd_info = info;
11468 err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
11469 data, len);
11470 rdev->cur_cmd_info = NULL;
11471 return err;
11472 }
11473
11474 return -EOPNOTSUPP;
11475}
11476
Johannes Berg7bdbe402015-08-15 22:39:49 +030011477static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
11478 struct netlink_callback *cb,
11479 struct cfg80211_registered_device **rdev,
11480 struct wireless_dev **wdev)
11481{
Johannes Bergc90c39d2016-10-24 14:40:01 +020011482 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011483 u32 vid, subcmd;
11484 unsigned int i;
11485 int vcmd_idx = -1;
11486 int err;
11487 void *data = NULL;
11488 unsigned int data_len = 0;
11489
11490 rtnl_lock();
11491
11492 if (cb->args[0]) {
11493 /* subtract the 1 again here */
11494 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
11495 struct wireless_dev *tmp;
11496
11497 if (!wiphy) {
11498 err = -ENODEV;
11499 goto out_unlock;
11500 }
11501 *rdev = wiphy_to_rdev(wiphy);
11502 *wdev = NULL;
11503
11504 if (cb->args[1]) {
Johannes Berg53873f12016-05-03 16:52:04 +030011505 list_for_each_entry(tmp, &wiphy->wdev_list, list) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011506 if (tmp->identifier == cb->args[1] - 1) {
11507 *wdev = tmp;
11508 break;
11509 }
11510 }
11511 }
11512
11513 /* keep rtnl locked in successful case */
11514 return 0;
11515 }
11516
11517 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +020011518 attrbuf, nl80211_fam.maxattr, nl80211_policy);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011519 if (err)
11520 goto out_unlock;
11521
Johannes Bergc90c39d2016-10-24 14:40:01 +020011522 if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
11523 !attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011524 err = -EINVAL;
11525 goto out_unlock;
11526 }
11527
Johannes Bergc90c39d2016-10-24 14:40:01 +020011528 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011529 if (IS_ERR(*wdev))
11530 *wdev = NULL;
11531
Johannes Bergc90c39d2016-10-24 14:40:01 +020011532 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011533 if (IS_ERR(*rdev)) {
11534 err = PTR_ERR(*rdev);
11535 goto out_unlock;
11536 }
11537
Johannes Bergc90c39d2016-10-24 14:40:01 +020011538 vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
11539 subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011540
11541 for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
11542 const struct wiphy_vendor_command *vcmd;
11543
11544 vcmd = &(*rdev)->wiphy.vendor_commands[i];
11545
11546 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11547 continue;
11548
11549 if (!vcmd->dumpit) {
11550 err = -EOPNOTSUPP;
11551 goto out_unlock;
11552 }
11553
11554 vcmd_idx = i;
11555 break;
11556 }
11557
11558 if (vcmd_idx < 0) {
11559 err = -EOPNOTSUPP;
11560 goto out_unlock;
11561 }
11562
Johannes Bergc90c39d2016-10-24 14:40:01 +020011563 if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
11564 data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
11565 data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011566 }
11567
11568 /* 0 is the first index - add 1 to parse only once */
11569 cb->args[0] = (*rdev)->wiphy_idx + 1;
11570 /* add 1 to know if it was NULL */
11571 cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
11572 cb->args[2] = vcmd_idx;
11573 cb->args[3] = (unsigned long)data;
11574 cb->args[4] = data_len;
11575
11576 /* keep rtnl locked in successful case */
11577 return 0;
11578 out_unlock:
11579 rtnl_unlock();
11580 return err;
11581}
11582
11583static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
11584 struct netlink_callback *cb)
11585{
11586 struct cfg80211_registered_device *rdev;
11587 struct wireless_dev *wdev;
11588 unsigned int vcmd_idx;
11589 const struct wiphy_vendor_command *vcmd;
11590 void *data;
11591 int data_len;
11592 int err;
11593 struct nlattr *vendor_data;
11594
11595 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
11596 if (err)
11597 return err;
11598
11599 vcmd_idx = cb->args[2];
11600 data = (void *)cb->args[3];
11601 data_len = cb->args[4];
11602 vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
11603
11604 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11605 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
11606 if (!wdev)
11607 return -EINVAL;
11608 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
11609 !wdev->netdev)
11610 return -EINVAL;
11611
11612 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011613 if (!wdev_running(wdev))
Johannes Berg7bdbe402015-08-15 22:39:49 +030011614 return -ENETDOWN;
11615 }
11616 }
11617
11618 while (1) {
11619 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
11620 cb->nlh->nlmsg_seq, NLM_F_MULTI,
11621 NL80211_CMD_VENDOR);
11622 if (!hdr)
11623 break;
11624
11625 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020011626 (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
11627 wdev_id(wdev),
11628 NL80211_ATTR_PAD))) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011629 genlmsg_cancel(skb, hdr);
11630 break;
11631 }
11632
11633 vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
11634 if (!vendor_data) {
11635 genlmsg_cancel(skb, hdr);
11636 break;
11637 }
11638
11639 err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
11640 (unsigned long *)&cb->args[5]);
11641 nla_nest_end(skb, vendor_data);
11642
11643 if (err == -ENOBUFS || err == -ENOENT) {
11644 genlmsg_cancel(skb, hdr);
11645 break;
11646 } else if (err) {
11647 genlmsg_cancel(skb, hdr);
11648 goto out;
11649 }
11650
11651 genlmsg_end(skb, hdr);
11652 }
11653
11654 err = skb->len;
11655 out:
11656 rtnl_unlock();
11657 return err;
11658}
11659
Johannes Bergad7e7182013-11-13 13:37:47 +010011660struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
11661 enum nl80211_commands cmd,
11662 enum nl80211_attrs attr,
11663 int approxlen)
11664{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080011665 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Bergad7e7182013-11-13 13:37:47 +010011666
11667 if (WARN_ON(!rdev->cur_cmd_info))
11668 return NULL;
11669
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020011670 return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
Johannes Bergad7e7182013-11-13 13:37:47 +010011671 rdev->cur_cmd_info->snd_portid,
11672 rdev->cur_cmd_info->snd_seq,
Johannes Berg567ffc32013-12-18 14:43:31 +010011673 cmd, attr, NULL, GFP_KERNEL);
Johannes Bergad7e7182013-11-13 13:37:47 +010011674}
11675EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
11676
11677int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
11678{
11679 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
11680 void *hdr = ((void **)skb->cb)[1];
11681 struct nlattr *data = ((void **)skb->cb)[2];
11682
Johannes Bergbd8c78e2014-07-30 14:55:26 +020011683 /* clear CB data for netlink core to own from now on */
11684 memset(skb->cb, 0, sizeof(skb->cb));
11685
Johannes Bergad7e7182013-11-13 13:37:47 +010011686 if (WARN_ON(!rdev->cur_cmd_info)) {
11687 kfree_skb(skb);
11688 return -EINVAL;
11689 }
11690
11691 nla_nest_end(skb, data);
11692 genlmsg_end(skb, hdr);
11693 return genlmsg_reply(skb, rdev->cur_cmd_info);
11694}
11695EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
11696
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080011697static int nl80211_set_qos_map(struct sk_buff *skb,
11698 struct genl_info *info)
11699{
11700 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11701 struct cfg80211_qos_map *qos_map = NULL;
11702 struct net_device *dev = info->user_ptr[1];
11703 u8 *pos, len, num_des, des_len, des;
11704 int ret;
11705
11706 if (!rdev->ops->set_qos_map)
11707 return -EOPNOTSUPP;
11708
11709 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
11710 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
11711 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
11712
11713 if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
11714 len > IEEE80211_QOS_MAP_LEN_MAX)
11715 return -EINVAL;
11716
11717 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
11718 if (!qos_map)
11719 return -ENOMEM;
11720
11721 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
11722 if (num_des) {
11723 des_len = num_des *
11724 sizeof(struct cfg80211_dscp_exception);
11725 memcpy(qos_map->dscp_exception, pos, des_len);
11726 qos_map->num_des = num_des;
11727 for (des = 0; des < num_des; des++) {
11728 if (qos_map->dscp_exception[des].up > 7) {
11729 kfree(qos_map);
11730 return -EINVAL;
11731 }
11732 }
11733 pos += des_len;
11734 }
11735 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
11736 }
11737
11738 wdev_lock(dev->ieee80211_ptr);
11739 ret = nl80211_key_allowed(dev->ieee80211_ptr);
11740 if (!ret)
11741 ret = rdev_set_qos_map(rdev, dev, qos_map);
11742 wdev_unlock(dev->ieee80211_ptr);
11743
11744 kfree(qos_map);
11745 return ret;
11746}
11747
Johannes Berg960d01a2014-09-09 22:55:35 +030011748static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
11749{
11750 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11751 struct net_device *dev = info->user_ptr[1];
11752 struct wireless_dev *wdev = dev->ieee80211_ptr;
11753 const u8 *peer;
11754 u8 tsid, up;
11755 u16 admitted_time = 0;
11756 int err;
11757
Johannes Berg723e73a2014-10-22 09:25:06 +020011758 if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
Johannes Berg960d01a2014-09-09 22:55:35 +030011759 return -EOPNOTSUPP;
11760
11761 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
11762 !info->attrs[NL80211_ATTR_USER_PRIO])
11763 return -EINVAL;
11764
11765 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
11766 if (tsid >= IEEE80211_NUM_TIDS)
11767 return -EINVAL;
11768
11769 up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
11770 if (up >= IEEE80211_NUM_UPS)
11771 return -EINVAL;
11772
11773 /* WMM uses TIDs 0-7 even for TSPEC */
Johannes Berg723e73a2014-10-22 09:25:06 +020011774 if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
Johannes Berg960d01a2014-09-09 22:55:35 +030011775 /* TODO: handle 802.11 TSPEC/admission control
Johannes Berg723e73a2014-10-22 09:25:06 +020011776 * need more attributes for that (e.g. BA session requirement);
11777 * change the WMM adminssion test above to allow both then
Johannes Berg960d01a2014-09-09 22:55:35 +030011778 */
11779 return -EINVAL;
11780 }
11781
11782 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
11783
11784 if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
11785 admitted_time =
11786 nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
11787 if (!admitted_time)
11788 return -EINVAL;
11789 }
11790
11791 wdev_lock(wdev);
11792 switch (wdev->iftype) {
11793 case NL80211_IFTYPE_STATION:
11794 case NL80211_IFTYPE_P2P_CLIENT:
11795 if (wdev->current_bss)
11796 break;
11797 err = -ENOTCONN;
11798 goto out;
11799 default:
11800 err = -EOPNOTSUPP;
11801 goto out;
11802 }
11803
11804 err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
11805
11806 out:
11807 wdev_unlock(wdev);
11808 return err;
11809}
11810
11811static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
11812{
11813 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11814 struct net_device *dev = info->user_ptr[1];
11815 struct wireless_dev *wdev = dev->ieee80211_ptr;
11816 const u8 *peer;
11817 u8 tsid;
11818 int err;
11819
11820 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
11821 return -EINVAL;
11822
11823 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
11824 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
11825
11826 wdev_lock(wdev);
11827 err = rdev_del_tx_ts(rdev, dev, tsid, peer);
11828 wdev_unlock(wdev);
11829
11830 return err;
11831}
11832
Arik Nemtsov1057d352014-11-19 12:54:26 +020011833static int nl80211_tdls_channel_switch(struct sk_buff *skb,
11834 struct genl_info *info)
11835{
11836 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11837 struct net_device *dev = info->user_ptr[1];
11838 struct wireless_dev *wdev = dev->ieee80211_ptr;
11839 struct cfg80211_chan_def chandef = {};
11840 const u8 *addr;
11841 u8 oper_class;
11842 int err;
11843
11844 if (!rdev->ops->tdls_channel_switch ||
11845 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
11846 return -EOPNOTSUPP;
11847
11848 switch (dev->ieee80211_ptr->iftype) {
11849 case NL80211_IFTYPE_STATION:
11850 case NL80211_IFTYPE_P2P_CLIENT:
11851 break;
11852 default:
11853 return -EOPNOTSUPP;
11854 }
11855
11856 if (!info->attrs[NL80211_ATTR_MAC] ||
11857 !info->attrs[NL80211_ATTR_OPER_CLASS])
11858 return -EINVAL;
11859
11860 err = nl80211_parse_chandef(rdev, info, &chandef);
11861 if (err)
11862 return err;
11863
11864 /*
11865 * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
11866 * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
11867 * specification is not defined for them.
11868 */
Johannes Berg57fbcce2016-04-12 15:56:15 +020011869 if (chandef.chan->band == NL80211_BAND_2GHZ &&
Arik Nemtsov1057d352014-11-19 12:54:26 +020011870 chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
11871 chandef.width != NL80211_CHAN_WIDTH_20)
11872 return -EINVAL;
11873
11874 /* we will be active on the TDLS link */
Arik Nemtsov923b3522015-07-08 15:41:44 +030011875 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
11876 wdev->iftype))
Arik Nemtsov1057d352014-11-19 12:54:26 +020011877 return -EINVAL;
11878
11879 /* don't allow switching to DFS channels */
11880 if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
11881 return -EINVAL;
11882
11883 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
11884 oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
11885
11886 wdev_lock(wdev);
11887 err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
11888 wdev_unlock(wdev);
11889
11890 return err;
11891}
11892
11893static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
11894 struct genl_info *info)
11895{
11896 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11897 struct net_device *dev = info->user_ptr[1];
11898 struct wireless_dev *wdev = dev->ieee80211_ptr;
11899 const u8 *addr;
11900
11901 if (!rdev->ops->tdls_channel_switch ||
11902 !rdev->ops->tdls_cancel_channel_switch ||
11903 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
11904 return -EOPNOTSUPP;
11905
11906 switch (dev->ieee80211_ptr->iftype) {
11907 case NL80211_IFTYPE_STATION:
11908 case NL80211_IFTYPE_P2P_CLIENT:
11909 break;
11910 default:
11911 return -EOPNOTSUPP;
11912 }
11913
11914 if (!info->attrs[NL80211_ATTR_MAC])
11915 return -EINVAL;
11916
11917 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
11918
11919 wdev_lock(wdev);
11920 rdev_tdls_cancel_channel_switch(rdev, dev, addr);
11921 wdev_unlock(wdev);
11922
11923 return 0;
11924}
11925
Michael Braunce0ce132016-10-10 19:12:22 +020011926static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
11927 struct genl_info *info)
11928{
11929 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11930 struct net_device *dev = info->user_ptr[1];
11931 struct wireless_dev *wdev = dev->ieee80211_ptr;
11932 const struct nlattr *nla;
11933 bool enabled;
11934
Michael Braunce0ce132016-10-10 19:12:22 +020011935 if (!rdev->ops->set_multicast_to_unicast)
11936 return -EOPNOTSUPP;
11937
11938 if (wdev->iftype != NL80211_IFTYPE_AP &&
11939 wdev->iftype != NL80211_IFTYPE_P2P_GO)
11940 return -EOPNOTSUPP;
11941
11942 nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
11943 enabled = nla_get_flag(nla);
11944
11945 return rdev_set_multicast_to_unicast(rdev, dev, enabled);
11946}
11947
Johannes Berg4c476992010-10-04 21:36:35 +020011948#define NL80211_FLAG_NEED_WIPHY 0x01
11949#define NL80211_FLAG_NEED_NETDEV 0x02
11950#define NL80211_FLAG_NEED_RTNL 0x04
Johannes Berg41265712010-10-04 21:14:05 +020011951#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
11952#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
11953 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg1bf614e2012-06-15 15:23:36 +020011954#define NL80211_FLAG_NEED_WDEV 0x10
Johannes Berg98104fde2012-06-16 00:19:54 +020011955/* If a netdev is associated, it must be UP, P2P must be started */
Johannes Berg1bf614e2012-06-15 15:23:36 +020011956#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
11957 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg5393b912014-09-10 15:00:16 +030011958#define NL80211_FLAG_CLEAR_SKB 0x20
Johannes Berg4c476992010-10-04 21:36:35 +020011959
Johannes Bergf84f7712013-11-14 17:14:45 +010011960static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020011961 struct genl_info *info)
11962{
11963 struct cfg80211_registered_device *rdev;
Johannes Berg89a54e42012-06-15 14:33:17 +020011964 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020011965 struct net_device *dev;
Johannes Berg4c476992010-10-04 21:36:35 +020011966 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
11967
11968 if (rtnl)
11969 rtnl_lock();
11970
11971 if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
Johannes Berg4f7eff12012-06-15 14:14:22 +020011972 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
Johannes Berg4c476992010-10-04 21:36:35 +020011973 if (IS_ERR(rdev)) {
11974 if (rtnl)
11975 rtnl_unlock();
11976 return PTR_ERR(rdev);
11977 }
11978 info->user_ptr[0] = rdev;
Johannes Berg1bf614e2012-06-15 15:23:36 +020011979 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
11980 ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020011981 ASSERT_RTNL();
11982
Johannes Berg89a54e42012-06-15 14:33:17 +020011983 wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
11984 info->attrs);
11985 if (IS_ERR(wdev)) {
Johannes Berg4c476992010-10-04 21:36:35 +020011986 if (rtnl)
11987 rtnl_unlock();
Johannes Berg89a54e42012-06-15 14:33:17 +020011988 return PTR_ERR(wdev);
Johannes Berg4c476992010-10-04 21:36:35 +020011989 }
Johannes Berg89a54e42012-06-15 14:33:17 +020011990
Johannes Berg89a54e42012-06-15 14:33:17 +020011991 dev = wdev->netdev;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080011992 rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg89a54e42012-06-15 14:33:17 +020011993
Johannes Berg1bf614e2012-06-15 15:23:36 +020011994 if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
11995 if (!dev) {
Johannes Berg1bf614e2012-06-15 15:23:36 +020011996 if (rtnl)
11997 rtnl_unlock();
11998 return -EINVAL;
11999 }
12000
12001 info->user_ptr[1] = dev;
12002 } else {
12003 info->user_ptr[1] = wdev;
Johannes Berg41265712010-10-04 21:14:05 +020012004 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012005
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012006 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
12007 !wdev_running(wdev)) {
12008 if (rtnl)
12009 rtnl_unlock();
12010 return -ENETDOWN;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012011 }
12012
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012013 if (dev)
12014 dev_hold(dev);
12015
Johannes Berg4c476992010-10-04 21:36:35 +020012016 info->user_ptr[0] = rdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012017 }
12018
12019 return 0;
12020}
12021
Johannes Bergf84f7712013-11-14 17:14:45 +010012022static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012023 struct genl_info *info)
12024{
Johannes Berg1bf614e2012-06-15 15:23:36 +020012025 if (info->user_ptr[1]) {
12026 if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
12027 struct wireless_dev *wdev = info->user_ptr[1];
12028
12029 if (wdev->netdev)
12030 dev_put(wdev->netdev);
12031 } else {
12032 dev_put(info->user_ptr[1]);
12033 }
12034 }
Johannes Berg5393b912014-09-10 15:00:16 +030012035
Johannes Berg4c476992010-10-04 21:36:35 +020012036 if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
12037 rtnl_unlock();
Johannes Berg5393b912014-09-10 15:00:16 +030012038
12039 /* If needed, clear the netlink message payload from the SKB
12040 * as it might contain key data that shouldn't stick around on
12041 * the heap after the SKB is freed. The netlink message header
12042 * is still needed for further processing, so leave it intact.
12043 */
12044 if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
12045 struct nlmsghdr *nlh = nlmsg_hdr(skb);
12046
12047 memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
12048 }
Johannes Berg4c476992010-10-04 21:36:35 +020012049}
12050
Johannes Berg4534de82013-11-14 17:14:46 +010012051static const struct genl_ops nl80211_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040012052 {
12053 .cmd = NL80211_CMD_GET_WIPHY,
12054 .doit = nl80211_get_wiphy,
12055 .dumpit = nl80211_dump_wiphy,
Johannes Berg86e8cf92013-06-19 10:57:22 +020012056 .done = nl80211_dump_wiphy_done,
Johannes Berg55682962007-09-20 13:09:35 -040012057 .policy = nl80211_policy,
12058 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012059 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12060 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012061 },
12062 {
12063 .cmd = NL80211_CMD_SET_WIPHY,
12064 .doit = nl80211_set_wiphy,
12065 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012066 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012067 .internal_flags = NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012068 },
12069 {
12070 .cmd = NL80211_CMD_GET_INTERFACE,
12071 .doit = nl80211_get_interface,
12072 .dumpit = nl80211_dump_interface,
12073 .policy = nl80211_policy,
12074 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012075 .internal_flags = NL80211_FLAG_NEED_WDEV |
12076 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012077 },
12078 {
12079 .cmd = NL80211_CMD_SET_INTERFACE,
12080 .doit = nl80211_set_interface,
12081 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012082 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012083 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12084 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012085 },
12086 {
12087 .cmd = NL80211_CMD_NEW_INTERFACE,
12088 .doit = nl80211_new_interface,
12089 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012090 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012091 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12092 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012093 },
12094 {
12095 .cmd = NL80211_CMD_DEL_INTERFACE,
12096 .doit = nl80211_del_interface,
12097 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012098 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg84efbb82012-06-16 00:00:26 +020012099 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012100 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012101 },
Johannes Berg41ade002007-12-19 02:03:29 +010012102 {
12103 .cmd = NL80211_CMD_GET_KEY,
12104 .doit = nl80211_get_key,
12105 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012106 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012107 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012108 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012109 },
12110 {
12111 .cmd = NL80211_CMD_SET_KEY,
12112 .doit = nl80211_set_key,
12113 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012114 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012115 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012116 NL80211_FLAG_NEED_RTNL |
12117 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012118 },
12119 {
12120 .cmd = NL80211_CMD_NEW_KEY,
12121 .doit = nl80211_new_key,
12122 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012123 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012124 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012125 NL80211_FLAG_NEED_RTNL |
12126 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012127 },
12128 {
12129 .cmd = NL80211_CMD_DEL_KEY,
12130 .doit = nl80211_del_key,
12131 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012132 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012133 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012134 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012135 },
Johannes Berged1b6cc2007-12-19 02:03:32 +010012136 {
12137 .cmd = NL80211_CMD_SET_BEACON,
12138 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012139 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012140 .doit = nl80211_set_beacon,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012141 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012142 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012143 },
12144 {
Johannes Berg88600202012-02-13 15:17:18 +010012145 .cmd = NL80211_CMD_START_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012146 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012147 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012148 .doit = nl80211_start_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012149 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012150 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012151 },
12152 {
Johannes Berg88600202012-02-13 15:17:18 +010012153 .cmd = NL80211_CMD_STOP_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012154 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012155 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012156 .doit = nl80211_stop_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012157 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012158 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012159 },
Johannes Berg5727ef12007-12-19 02:03:34 +010012160 {
12161 .cmd = NL80211_CMD_GET_STATION,
12162 .doit = nl80211_get_station,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012163 .dumpit = nl80211_dump_station,
Johannes Berg5727ef12007-12-19 02:03:34 +010012164 .policy = nl80211_policy,
Johannes Berg4c476992010-10-04 21:36:35 +020012165 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12166 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012167 },
12168 {
12169 .cmd = NL80211_CMD_SET_STATION,
12170 .doit = nl80211_set_station,
12171 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012172 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012173 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012174 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012175 },
12176 {
12177 .cmd = NL80211_CMD_NEW_STATION,
12178 .doit = nl80211_new_station,
12179 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012180 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012181 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012182 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012183 },
12184 {
12185 .cmd = NL80211_CMD_DEL_STATION,
12186 .doit = nl80211_del_station,
12187 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012188 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012189 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012190 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012191 },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012192 {
12193 .cmd = NL80211_CMD_GET_MPATH,
12194 .doit = nl80211_get_mpath,
12195 .dumpit = nl80211_dump_mpath,
12196 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012197 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012198 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012199 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012200 },
12201 {
Henning Rogge66be7d22014-09-12 08:58:49 +020012202 .cmd = NL80211_CMD_GET_MPP,
12203 .doit = nl80211_get_mpp,
12204 .dumpit = nl80211_dump_mpp,
12205 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012206 .flags = GENL_UNS_ADMIN_PERM,
Henning Rogge66be7d22014-09-12 08:58:49 +020012207 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12208 NL80211_FLAG_NEED_RTNL,
12209 },
12210 {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012211 .cmd = NL80211_CMD_SET_MPATH,
12212 .doit = nl80211_set_mpath,
12213 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012214 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012215 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012216 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012217 },
12218 {
12219 .cmd = NL80211_CMD_NEW_MPATH,
12220 .doit = nl80211_new_mpath,
12221 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012222 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012223 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012224 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012225 },
12226 {
12227 .cmd = NL80211_CMD_DEL_MPATH,
12228 .doit = nl80211_del_mpath,
12229 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012230 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012231 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012232 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012233 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012234 {
12235 .cmd = NL80211_CMD_SET_BSS,
12236 .doit = nl80211_set_bss,
12237 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012238 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012239 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012240 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012241 },
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012242 {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012243 .cmd = NL80211_CMD_GET_REG,
Arik Nemtsovad30ca22014-12-15 19:25:59 +020012244 .doit = nl80211_get_reg_do,
12245 .dumpit = nl80211_get_reg_dump,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012246 .policy = nl80211_policy,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012247 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012248 /* can be retrieved by unprivileged users */
12249 },
Johannes Bergb6863032015-10-15 09:25:18 +020012250#ifdef CONFIG_CFG80211_CRDA_SUPPORT
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012251 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012252 .cmd = NL80211_CMD_SET_REG,
12253 .doit = nl80211_set_reg,
12254 .policy = nl80211_policy,
12255 .flags = GENL_ADMIN_PERM,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012256 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012257 },
Johannes Bergb6863032015-10-15 09:25:18 +020012258#endif
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012259 {
12260 .cmd = NL80211_CMD_REQ_SET_REG,
12261 .doit = nl80211_req_set_reg,
12262 .policy = nl80211_policy,
12263 .flags = GENL_ADMIN_PERM,
12264 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012265 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012266 .cmd = NL80211_CMD_GET_MESH_CONFIG,
12267 .doit = nl80211_get_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012268 .policy = nl80211_policy,
12269 /* can be retrieved by unprivileged users */
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012270 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012271 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012272 },
12273 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012274 .cmd = NL80211_CMD_SET_MESH_CONFIG,
12275 .doit = nl80211_update_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012276 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012277 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012278 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012279 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012280 },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +020012281 {
Johannes Berg2a519312009-02-10 21:25:55 +010012282 .cmd = NL80211_CMD_TRIGGER_SCAN,
12283 .doit = nl80211_trigger_scan,
12284 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012285 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergfd014282012-06-18 19:17:03 +020012286 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012287 NL80211_FLAG_NEED_RTNL,
Johannes Berg2a519312009-02-10 21:25:55 +010012288 },
12289 {
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012290 .cmd = NL80211_CMD_ABORT_SCAN,
12291 .doit = nl80211_abort_scan,
12292 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012293 .flags = GENL_UNS_ADMIN_PERM,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012294 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12295 NL80211_FLAG_NEED_RTNL,
12296 },
12297 {
Johannes Berg2a519312009-02-10 21:25:55 +010012298 .cmd = NL80211_CMD_GET_SCAN,
12299 .policy = nl80211_policy,
12300 .dumpit = nl80211_dump_scan,
12301 },
Jouni Malinen636a5d32009-03-19 13:39:22 +020012302 {
Luciano Coelho807f8a82011-05-11 17:09:35 +030012303 .cmd = NL80211_CMD_START_SCHED_SCAN,
12304 .doit = nl80211_start_sched_scan,
12305 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012306 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012307 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12308 NL80211_FLAG_NEED_RTNL,
12309 },
12310 {
12311 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
12312 .doit = nl80211_stop_sched_scan,
12313 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012314 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012315 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12316 NL80211_FLAG_NEED_RTNL,
12317 },
12318 {
Jouni Malinen636a5d32009-03-19 13:39:22 +020012319 .cmd = NL80211_CMD_AUTHENTICATE,
12320 .doit = nl80211_authenticate,
12321 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012322 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012323 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012324 NL80211_FLAG_NEED_RTNL |
12325 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012326 },
12327 {
12328 .cmd = NL80211_CMD_ASSOCIATE,
12329 .doit = nl80211_associate,
12330 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012331 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012332 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012333 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012334 },
12335 {
12336 .cmd = NL80211_CMD_DEAUTHENTICATE,
12337 .doit = nl80211_deauthenticate,
12338 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012339 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012340 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012341 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012342 },
12343 {
12344 .cmd = NL80211_CMD_DISASSOCIATE,
12345 .doit = nl80211_disassociate,
12346 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012347 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012348 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012349 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012350 },
Johannes Berg04a773a2009-04-19 21:24:32 +020012351 {
12352 .cmd = NL80211_CMD_JOIN_IBSS,
12353 .doit = nl80211_join_ibss,
12354 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012355 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012356 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012357 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012358 },
12359 {
12360 .cmd = NL80211_CMD_LEAVE_IBSS,
12361 .doit = nl80211_leave_ibss,
12362 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012363 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012364 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012365 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012366 },
Johannes Bergaff89a92009-07-01 21:26:51 +020012367#ifdef CONFIG_NL80211_TESTMODE
12368 {
12369 .cmd = NL80211_CMD_TESTMODE,
12370 .doit = nl80211_testmode_do,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070012371 .dumpit = nl80211_testmode_dump,
Johannes Bergaff89a92009-07-01 21:26:51 +020012372 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012373 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012374 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12375 NL80211_FLAG_NEED_RTNL,
Johannes Bergaff89a92009-07-01 21:26:51 +020012376 },
12377#endif
Samuel Ortizb23aa672009-07-01 21:26:54 +020012378 {
12379 .cmd = NL80211_CMD_CONNECT,
12380 .doit = nl80211_connect,
12381 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012382 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012383 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012384 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012385 },
12386 {
vamsi krishna088e8df2016-10-27 16:51:11 +030012387 .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
12388 .doit = nl80211_update_connect_params,
12389 .policy = nl80211_policy,
12390 .flags = GENL_ADMIN_PERM,
12391 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12392 NL80211_FLAG_NEED_RTNL,
12393 },
12394 {
Samuel Ortizb23aa672009-07-01 21:26:54 +020012395 .cmd = NL80211_CMD_DISCONNECT,
12396 .doit = nl80211_disconnect,
12397 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012398 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012399 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012400 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012401 },
Johannes Berg463d0182009-07-14 00:33:35 +020012402 {
12403 .cmd = NL80211_CMD_SET_WIPHY_NETNS,
12404 .doit = nl80211_wiphy_netns,
12405 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012406 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012407 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12408 NL80211_FLAG_NEED_RTNL,
Johannes Berg463d0182009-07-14 00:33:35 +020012409 },
Holger Schurig61fa7132009-11-11 12:25:40 +010012410 {
12411 .cmd = NL80211_CMD_GET_SURVEY,
12412 .policy = nl80211_policy,
12413 .dumpit = nl80211_dump_survey,
12414 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012415 {
12416 .cmd = NL80211_CMD_SET_PMKSA,
12417 .doit = nl80211_setdel_pmksa,
12418 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012419 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012420 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012421 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012422 },
12423 {
12424 .cmd = NL80211_CMD_DEL_PMKSA,
12425 .doit = nl80211_setdel_pmksa,
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,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012430 },
12431 {
12432 .cmd = NL80211_CMD_FLUSH_PMKSA,
12433 .doit = nl80211_flush_pmksa,
12434 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012435 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012436 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012437 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012438 },
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012439 {
12440 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
12441 .doit = nl80211_remain_on_channel,
12442 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012443 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012444 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012445 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012446 },
12447 {
12448 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
12449 .doit = nl80211_cancel_remain_on_channel,
12450 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012451 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012452 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012453 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012454 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012455 {
12456 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
12457 .doit = nl80211_set_tx_bitrate_mask,
12458 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012459 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012460 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12461 NL80211_FLAG_NEED_RTNL,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012462 },
Jouni Malinen026331c2010-02-15 12:53:10 +020012463 {
Johannes Berg2e161f782010-08-12 15:38:38 +020012464 .cmd = NL80211_CMD_REGISTER_FRAME,
12465 .doit = nl80211_register_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012466 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012467 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012468 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012469 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012470 },
12471 {
Johannes Berg2e161f782010-08-12 15:38:38 +020012472 .cmd = NL80211_CMD_FRAME,
12473 .doit = nl80211_tx_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012474 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012475 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012476 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012477 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012478 },
Kalle Valoffb9eb32010-02-17 17:58:10 +020012479 {
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012480 .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
12481 .doit = nl80211_tx_mgmt_cancel_wait,
12482 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012483 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012484 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012485 NL80211_FLAG_NEED_RTNL,
12486 },
12487 {
Kalle Valoffb9eb32010-02-17 17:58:10 +020012488 .cmd = NL80211_CMD_SET_POWER_SAVE,
12489 .doit = nl80211_set_power_save,
12490 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012491 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012492 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12493 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012494 },
12495 {
12496 .cmd = NL80211_CMD_GET_POWER_SAVE,
12497 .doit = nl80211_get_power_save,
12498 .policy = nl80211_policy,
12499 /* can be retrieved by unprivileged users */
Johannes Berg4c476992010-10-04 21:36:35 +020012500 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12501 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012502 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012503 {
12504 .cmd = NL80211_CMD_SET_CQM,
12505 .doit = nl80211_set_cqm,
12506 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012507 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012508 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12509 NL80211_FLAG_NEED_RTNL,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012510 },
Johannes Bergf444de02010-05-05 15:25:02 +020012511 {
12512 .cmd = NL80211_CMD_SET_CHANNEL,
12513 .doit = nl80211_set_channel,
12514 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012515 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012516 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12517 NL80211_FLAG_NEED_RTNL,
Johannes Bergf444de02010-05-05 15:25:02 +020012518 },
Bill Jordane8347eb2010-10-01 13:54:28 -040012519 {
12520 .cmd = NL80211_CMD_SET_WDS_PEER,
12521 .doit = nl80211_set_wds_peer,
12522 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012523 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg43b19952010-10-07 13:10:30 +020012524 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12525 NL80211_FLAG_NEED_RTNL,
Bill Jordane8347eb2010-10-01 13:54:28 -040012526 },
Johannes Berg29cbe682010-12-03 09:20:44 +010012527 {
12528 .cmd = NL80211_CMD_JOIN_MESH,
12529 .doit = nl80211_join_mesh,
12530 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012531 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012532 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12533 NL80211_FLAG_NEED_RTNL,
12534 },
12535 {
12536 .cmd = NL80211_CMD_LEAVE_MESH,
12537 .doit = nl80211_leave_mesh,
12538 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012539 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012540 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12541 NL80211_FLAG_NEED_RTNL,
12542 },
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012543 {
12544 .cmd = NL80211_CMD_JOIN_OCB,
12545 .doit = nl80211_join_ocb,
12546 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012547 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012548 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12549 NL80211_FLAG_NEED_RTNL,
12550 },
12551 {
12552 .cmd = NL80211_CMD_LEAVE_OCB,
12553 .doit = nl80211_leave_ocb,
12554 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012555 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012556 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12557 NL80211_FLAG_NEED_RTNL,
12558 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020012559#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +020012560 {
12561 .cmd = NL80211_CMD_GET_WOWLAN,
12562 .doit = nl80211_get_wowlan,
12563 .policy = nl80211_policy,
12564 /* can be retrieved by unprivileged users */
12565 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12566 NL80211_FLAG_NEED_RTNL,
12567 },
12568 {
12569 .cmd = NL80211_CMD_SET_WOWLAN,
12570 .doit = nl80211_set_wowlan,
12571 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012572 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergff1b6e62011-05-04 15:37:28 +020012573 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12574 NL80211_FLAG_NEED_RTNL,
12575 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020012576#endif
Johannes Berge5497d72011-07-05 16:35:40 +020012577 {
12578 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
12579 .doit = nl80211_set_rekey_data,
12580 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012581 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berge5497d72011-07-05 16:35:40 +020012582 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012583 NL80211_FLAG_NEED_RTNL |
12584 NL80211_FLAG_CLEAR_SKB,
Johannes Berge5497d72011-07-05 16:35:40 +020012585 },
Arik Nemtsov109086c2011-09-28 14:12:50 +030012586 {
12587 .cmd = NL80211_CMD_TDLS_MGMT,
12588 .doit = nl80211_tdls_mgmt,
12589 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012590 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030012591 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12592 NL80211_FLAG_NEED_RTNL,
12593 },
12594 {
12595 .cmd = NL80211_CMD_TDLS_OPER,
12596 .doit = nl80211_tdls_oper,
12597 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012598 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030012599 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12600 NL80211_FLAG_NEED_RTNL,
12601 },
Johannes Berg28946da2011-11-04 11:18:12 +010012602 {
12603 .cmd = NL80211_CMD_UNEXPECTED_FRAME,
12604 .doit = nl80211_register_unexpected_frame,
12605 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012606 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg28946da2011-11-04 11:18:12 +010012607 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12608 NL80211_FLAG_NEED_RTNL,
12609 },
Johannes Berg7f6cf312011-11-04 11:18:15 +010012610 {
12611 .cmd = NL80211_CMD_PROBE_CLIENT,
12612 .doit = nl80211_probe_client,
12613 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012614 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012615 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg7f6cf312011-11-04 11:18:15 +010012616 NL80211_FLAG_NEED_RTNL,
12617 },
Johannes Berg5e760232011-11-04 11:18:17 +010012618 {
12619 .cmd = NL80211_CMD_REGISTER_BEACONS,
12620 .doit = nl80211_register_beacons,
12621 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012622 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg5e760232011-11-04 11:18:17 +010012623 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12624 NL80211_FLAG_NEED_RTNL,
12625 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010012626 {
12627 .cmd = NL80211_CMD_SET_NOACK_MAP,
12628 .doit = nl80211_set_noack_map,
12629 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012630 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010012631 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12632 NL80211_FLAG_NEED_RTNL,
12633 },
Johannes Berg98104fde2012-06-16 00:19:54 +020012634 {
12635 .cmd = NL80211_CMD_START_P2P_DEVICE,
12636 .doit = nl80211_start_p2p_device,
12637 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012638 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020012639 .internal_flags = NL80211_FLAG_NEED_WDEV |
12640 NL80211_FLAG_NEED_RTNL,
12641 },
12642 {
12643 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
12644 .doit = nl80211_stop_p2p_device,
12645 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012646 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020012647 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12648 NL80211_FLAG_NEED_RTNL,
12649 },
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012650 {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012651 .cmd = NL80211_CMD_START_NAN,
12652 .doit = nl80211_start_nan,
12653 .policy = nl80211_policy,
12654 .flags = GENL_ADMIN_PERM,
12655 .internal_flags = NL80211_FLAG_NEED_WDEV |
12656 NL80211_FLAG_NEED_RTNL,
12657 },
12658 {
12659 .cmd = NL80211_CMD_STOP_NAN,
12660 .doit = nl80211_stop_nan,
12661 .policy = nl80211_policy,
12662 .flags = GENL_ADMIN_PERM,
12663 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12664 NL80211_FLAG_NEED_RTNL,
12665 },
12666 {
Ayala Bekera442b762016-09-20 17:31:15 +030012667 .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
12668 .doit = nl80211_nan_add_func,
12669 .policy = nl80211_policy,
12670 .flags = GENL_ADMIN_PERM,
12671 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12672 NL80211_FLAG_NEED_RTNL,
12673 },
12674 {
12675 .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
12676 .doit = nl80211_nan_del_func,
12677 .policy = nl80211_policy,
12678 .flags = GENL_ADMIN_PERM,
12679 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12680 NL80211_FLAG_NEED_RTNL,
12681 },
12682 {
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030012683 .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
12684 .doit = nl80211_nan_change_config,
12685 .policy = nl80211_policy,
12686 .flags = GENL_ADMIN_PERM,
12687 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12688 NL80211_FLAG_NEED_RTNL,
12689 },
12690 {
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012691 .cmd = NL80211_CMD_SET_MCAST_RATE,
12692 .doit = nl80211_set_mcast_rate,
12693 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012694 .flags = GENL_UNS_ADMIN_PERM,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012695 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12696 NL80211_FLAG_NEED_RTNL,
12697 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053012698 {
12699 .cmd = NL80211_CMD_SET_MAC_ACL,
12700 .doit = nl80211_set_mac_acl,
12701 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012702 .flags = GENL_UNS_ADMIN_PERM,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053012703 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12704 NL80211_FLAG_NEED_RTNL,
12705 },
Simon Wunderlich04f39042013-02-08 18:16:19 +010012706 {
12707 .cmd = NL80211_CMD_RADAR_DETECT,
12708 .doit = nl80211_start_radar_detection,
12709 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012710 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich04f39042013-02-08 18:16:19 +010012711 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12712 NL80211_FLAG_NEED_RTNL,
12713 },
Johannes Berg3713b4e2013-02-14 16:19:38 +010012714 {
12715 .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
12716 .doit = nl80211_get_protocol_features,
12717 .policy = nl80211_policy,
12718 },
Jouni Malinen355199e2013-02-27 17:14:27 +020012719 {
12720 .cmd = NL80211_CMD_UPDATE_FT_IES,
12721 .doit = nl80211_update_ft_ies,
12722 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012723 .flags = GENL_UNS_ADMIN_PERM,
Jouni Malinen355199e2013-02-27 17:14:27 +020012724 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12725 NL80211_FLAG_NEED_RTNL,
12726 },
Arend van Spriel5de17982013-04-18 15:49:00 +020012727 {
12728 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
12729 .doit = nl80211_crit_protocol_start,
12730 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012731 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020012732 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12733 NL80211_FLAG_NEED_RTNL,
12734 },
12735 {
12736 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
12737 .doit = nl80211_crit_protocol_stop,
12738 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012739 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020012740 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12741 NL80211_FLAG_NEED_RTNL,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012742 },
12743 {
12744 .cmd = NL80211_CMD_GET_COALESCE,
12745 .doit = nl80211_get_coalesce,
12746 .policy = nl80211_policy,
12747 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12748 NL80211_FLAG_NEED_RTNL,
12749 },
12750 {
12751 .cmd = NL80211_CMD_SET_COALESCE,
12752 .doit = nl80211_set_coalesce,
12753 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012754 .flags = GENL_UNS_ADMIN_PERM,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012755 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12756 NL80211_FLAG_NEED_RTNL,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020012757 },
12758 {
12759 .cmd = NL80211_CMD_CHANNEL_SWITCH,
12760 .doit = nl80211_channel_switch,
12761 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012762 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020012763 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12764 NL80211_FLAG_NEED_RTNL,
12765 },
Johannes Bergad7e7182013-11-13 13:37:47 +010012766 {
12767 .cmd = NL80211_CMD_VENDOR,
12768 .doit = nl80211_vendor_cmd,
Johannes Berg7bdbe402015-08-15 22:39:49 +030012769 .dumpit = nl80211_vendor_cmd_dump,
Johannes Bergad7e7182013-11-13 13:37:47 +010012770 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012771 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergad7e7182013-11-13 13:37:47 +010012772 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12773 NL80211_FLAG_NEED_RTNL,
12774 },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080012775 {
12776 .cmd = NL80211_CMD_SET_QOS_MAP,
12777 .doit = nl80211_set_qos_map,
12778 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012779 .flags = GENL_UNS_ADMIN_PERM,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080012780 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12781 NL80211_FLAG_NEED_RTNL,
12782 },
Johannes Berg960d01a2014-09-09 22:55:35 +030012783 {
12784 .cmd = NL80211_CMD_ADD_TX_TS,
12785 .doit = nl80211_add_tx_ts,
12786 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012787 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030012788 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12789 NL80211_FLAG_NEED_RTNL,
12790 },
12791 {
12792 .cmd = NL80211_CMD_DEL_TX_TS,
12793 .doit = nl80211_del_tx_ts,
12794 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012795 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030012796 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12797 NL80211_FLAG_NEED_RTNL,
12798 },
Arik Nemtsov1057d352014-11-19 12:54:26 +020012799 {
12800 .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
12801 .doit = nl80211_tdls_channel_switch,
12802 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012803 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020012804 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12805 NL80211_FLAG_NEED_RTNL,
12806 },
12807 {
12808 .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
12809 .doit = nl80211_tdls_cancel_channel_switch,
12810 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012811 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020012812 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12813 NL80211_FLAG_NEED_RTNL,
12814 },
Michael Braunce0ce132016-10-10 19:12:22 +020012815 {
12816 .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
12817 .doit = nl80211_set_multicast_to_unicast,
12818 .policy = nl80211_policy,
12819 .flags = GENL_UNS_ADMIN_PERM,
12820 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12821 NL80211_FLAG_NEED_RTNL,
12822 },
Johannes Berg55682962007-09-20 13:09:35 -040012823};
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012824
Johannes Berg56989f62016-10-24 14:40:05 +020012825static struct genl_family nl80211_fam __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +020012826 .name = NL80211_GENL_NAME, /* have users key off the name instead */
12827 .hdrsize = 0, /* no private header */
12828 .version = 1, /* no particular meaning now */
12829 .maxattr = NL80211_ATTR_MAX,
12830 .netnsok = true,
12831 .pre_doit = nl80211_pre_doit,
12832 .post_doit = nl80211_post_doit,
12833 .module = THIS_MODULE,
12834 .ops = nl80211_ops,
12835 .n_ops = ARRAY_SIZE(nl80211_ops),
12836 .mcgrps = nl80211_mcgrps,
12837 .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
12838};
12839
Johannes Berg55682962007-09-20 13:09:35 -040012840/* notification functions */
12841
Johannes Berg3bb20552014-05-26 13:52:25 +020012842void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
12843 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -040012844{
12845 struct sk_buff *msg;
Johannes Berg86e8cf92013-06-19 10:57:22 +020012846 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -040012847
Johannes Berg3bb20552014-05-26 13:52:25 +020012848 WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
12849 cmd != NL80211_CMD_DEL_WIPHY);
12850
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070012851 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040012852 if (!msg)
12853 return;
12854
Johannes Berg3bb20552014-05-26 13:52:25 +020012855 if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
Johannes Berg55682962007-09-20 13:09:35 -040012856 nlmsg_free(msg);
12857 return;
12858 }
12859
Johannes Berg68eb5502013-11-19 15:19:38 +010012860 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010012861 NL80211_MCGRP_CONFIG, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040012862}
12863
Denis Kenzior896ff062016-08-03 16:58:33 -050012864void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
12865 struct wireless_dev *wdev,
12866 enum nl80211_commands cmd)
12867{
12868 struct sk_buff *msg;
12869
12870 WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
12871 cmd != NL80211_CMD_DEL_INTERFACE);
12872
12873 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12874 if (!msg)
12875 return;
12876
12877 if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
12878 cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
12879 nlmsg_free(msg);
12880 return;
12881 }
12882
12883 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
12884 NL80211_MCGRP_CONFIG, GFP_KERNEL);
12885}
12886
Johannes Berg362a4152009-05-24 16:43:15 +020012887static int nl80211_add_scan_req(struct sk_buff *msg,
12888 struct cfg80211_registered_device *rdev)
12889{
12890 struct cfg80211_scan_request *req = rdev->scan_req;
12891 struct nlattr *nest;
12892 int i;
12893
12894 if (WARN_ON(!req))
12895 return 0;
12896
12897 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
12898 if (!nest)
12899 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040012900 for (i = 0; i < req->n_ssids; i++) {
12901 if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
12902 goto nla_put_failure;
12903 }
Johannes Berg362a4152009-05-24 16:43:15 +020012904 nla_nest_end(msg, nest);
12905
12906 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
12907 if (!nest)
12908 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040012909 for (i = 0; i < req->n_channels; i++) {
12910 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
12911 goto nla_put_failure;
12912 }
Johannes Berg362a4152009-05-24 16:43:15 +020012913 nla_nest_end(msg, nest);
12914
David S. Miller9360ffd2012-03-29 04:41:26 -040012915 if (req->ie &&
12916 nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
12917 goto nla_put_failure;
Johannes Berg362a4152009-05-24 16:43:15 +020012918
Johannes Bergae917c92013-10-25 11:05:22 +020012919 if (req->flags &&
12920 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
12921 goto nla_put_failure;
Sam Lefflered4737712012-10-11 21:03:31 -070012922
Avraham Stern1d762502016-07-05 17:10:13 +030012923 if (req->info.scan_start_tsf &&
12924 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
12925 req->info.scan_start_tsf, NL80211_BSS_PAD) ||
12926 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
12927 req->info.tsf_bssid)))
12928 goto nla_put_failure;
12929
Johannes Berg362a4152009-05-24 16:43:15 +020012930 return 0;
12931 nla_put_failure:
12932 return -ENOBUFS;
12933}
12934
Arend Van Spriel505a2e82016-12-16 11:21:54 +000012935static int nl80211_prep_scan_msg(struct sk_buff *msg,
Johannes Berga538e2d2009-06-16 19:56:42 +020012936 struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020012937 struct wireless_dev *wdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000012938 u32 portid, u32 seq, int flags,
Johannes Berga538e2d2009-06-16 19:56:42 +020012939 u32 cmd)
Johannes Berg2a519312009-02-10 21:25:55 +010012940{
12941 void *hdr;
12942
Eric W. Biederman15e47302012-09-07 20:12:54 +000012943 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg2a519312009-02-10 21:25:55 +010012944 if (!hdr)
12945 return -1;
12946
David S. Miller9360ffd2012-03-29 04:41:26 -040012947 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Bergfd014282012-06-18 19:17:03 +020012948 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
12949 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020012950 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
12951 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040012952 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +010012953
Johannes Berg362a4152009-05-24 16:43:15 +020012954 /* ignore errors and send incomplete event anyway */
12955 nl80211_add_scan_req(msg, rdev);
Johannes Berg2a519312009-02-10 21:25:55 +010012956
Johannes Berg053c0952015-01-16 22:09:00 +010012957 genlmsg_end(msg, hdr);
12958 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +010012959
12960 nla_put_failure:
12961 genlmsg_cancel(msg, hdr);
12962 return -EMSGSIZE;
12963}
12964
Luciano Coelho807f8a82011-05-11 17:09:35 +030012965static int
Arend Van Spriel505a2e82016-12-16 11:21:54 +000012966nl80211_prep_sched_scan_msg(struct sk_buff *msg,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012967 struct cfg80211_registered_device *rdev,
12968 struct net_device *netdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000012969 u32 portid, u32 seq, int flags, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030012970{
12971 void *hdr;
12972
Eric W. Biederman15e47302012-09-07 20:12:54 +000012973 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Luciano Coelho807f8a82011-05-11 17:09:35 +030012974 if (!hdr)
12975 return -1;
12976
David S. Miller9360ffd2012-03-29 04:41:26 -040012977 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
12978 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
12979 goto nla_put_failure;
Luciano Coelho807f8a82011-05-11 17:09:35 +030012980
Johannes Berg053c0952015-01-16 22:09:00 +010012981 genlmsg_end(msg, hdr);
12982 return 0;
Luciano Coelho807f8a82011-05-11 17:09:35 +030012983
12984 nla_put_failure:
12985 genlmsg_cancel(msg, hdr);
12986 return -EMSGSIZE;
12987}
12988
Johannes Berga538e2d2009-06-16 19:56:42 +020012989void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020012990 struct wireless_dev *wdev)
Johannes Berga538e2d2009-06-16 19:56:42 +020012991{
12992 struct sk_buff *msg;
12993
Thomas Graf58050fc2012-06-28 03:57:45 +000012994 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020012995 if (!msg)
12996 return;
12997
Arend Van Spriel505a2e82016-12-16 11:21:54 +000012998 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Berga538e2d2009-06-16 19:56:42 +020012999 NL80211_CMD_TRIGGER_SCAN) < 0) {
13000 nlmsg_free(msg);
13001 return;
13002 }
13003
Johannes Berg68eb5502013-11-19 15:19:38 +010013004 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013005 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013006}
13007
Johannes Bergf9d15d12014-01-22 11:14:19 +020013008struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
13009 struct wireless_dev *wdev, bool aborted)
Johannes Berg2a519312009-02-10 21:25:55 +010013010{
13011 struct sk_buff *msg;
13012
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013013 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013014 if (!msg)
Johannes Bergf9d15d12014-01-22 11:14:19 +020013015 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013016
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013017 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Bergf9d15d12014-01-22 11:14:19 +020013018 aborted ? NL80211_CMD_SCAN_ABORTED :
13019 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +010013020 nlmsg_free(msg);
Johannes Bergf9d15d12014-01-22 11:14:19 +020013021 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013022 }
13023
Johannes Bergf9d15d12014-01-22 11:14:19 +020013024 return msg;
Johannes Berg2a519312009-02-10 21:25:55 +010013025}
13026
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013027/* send message created by nl80211_build_scan_msg() */
13028void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
13029 struct sk_buff *msg)
Johannes Berg2a519312009-02-10 21:25:55 +010013030{
Johannes Berg2a519312009-02-10 21:25:55 +010013031 if (!msg)
13032 return;
13033
Johannes Berg68eb5502013-11-19 15:19:38 +010013034 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013035 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013036}
13037
Luciano Coelho807f8a82011-05-11 17:09:35 +030013038void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
13039 struct net_device *netdev, u32 cmd)
13040{
13041 struct sk_buff *msg;
13042
Thomas Graf58050fc2012-06-28 03:57:45 +000013043 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013044 if (!msg)
13045 return;
13046
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013047 if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
Luciano Coelho807f8a82011-05-11 17:09:35 +030013048 nlmsg_free(msg);
13049 return;
13050 }
13051
Johannes Berg68eb5502013-11-19 15:19:38 +010013052 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013053 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013054}
13055
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013056static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
13057 struct regulatory_request *request)
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013058{
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013059 /* Userspace can always count this one always being set */
David S. Miller9360ffd2012-03-29 04:41:26 -040013060 if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
13061 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013062
David S. Miller9360ffd2012-03-29 04:41:26 -040013063 if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
13064 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13065 NL80211_REGDOM_TYPE_WORLD))
13066 goto nla_put_failure;
13067 } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
13068 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13069 NL80211_REGDOM_TYPE_CUSTOM_WORLD))
13070 goto nla_put_failure;
13071 } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
13072 request->intersect) {
13073 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13074 NL80211_REGDOM_TYPE_INTERSECTION))
13075 goto nla_put_failure;
13076 } else {
13077 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13078 NL80211_REGDOM_TYPE_COUNTRY) ||
13079 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
13080 request->alpha2))
13081 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013082 }
13083
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013084 if (request->wiphy_idx != WIPHY_IDX_INVALID) {
13085 struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
13086
13087 if (wiphy &&
13088 nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
13089 goto nla_put_failure;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +020013090
13091 if (wiphy &&
13092 wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
13093 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
13094 goto nla_put_failure;
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013095 }
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013096
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013097 return true;
13098
13099nla_put_failure:
13100 return false;
13101}
13102
13103/*
13104 * This can happen on global regulatory changes or device specific settings
13105 * based on custom regulatory domains.
13106 */
13107void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
13108 struct regulatory_request *request)
13109{
13110 struct sk_buff *msg;
13111 void *hdr;
13112
13113 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13114 if (!msg)
13115 return;
13116
13117 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
13118 if (!hdr) {
13119 nlmsg_free(msg);
13120 return;
13121 }
13122
13123 if (nl80211_reg_change_event_fill(msg, request) == false)
13124 goto nla_put_failure;
13125
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013126 genlmsg_end(msg, hdr);
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013127
Johannes Bergbc43b282009-07-25 10:54:13 +020013128 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013129 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013130 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Bergbc43b282009-07-25 10:54:13 +020013131 rcu_read_unlock();
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013132
13133 return;
13134
13135nla_put_failure:
13136 genlmsg_cancel(msg, hdr);
13137 nlmsg_free(msg);
13138}
13139
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013140static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
13141 struct net_device *netdev,
13142 const u8 *buf, size_t len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013143 enum nl80211_commands cmd, gfp_t gfp,
13144 int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013145{
13146 struct sk_buff *msg;
13147 void *hdr;
13148
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013149 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013150 if (!msg)
13151 return;
13152
13153 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13154 if (!hdr) {
13155 nlmsg_free(msg);
13156 return;
13157 }
13158
David S. Miller9360ffd2012-03-29 04:41:26 -040013159 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13160 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13161 nla_put(msg, NL80211_ATTR_FRAME, len, buf))
13162 goto nla_put_failure;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013163
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013164 if (uapsd_queues >= 0) {
13165 struct nlattr *nla_wmm =
13166 nla_nest_start(msg, NL80211_ATTR_STA_WME);
13167 if (!nla_wmm)
13168 goto nla_put_failure;
13169
13170 if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
13171 uapsd_queues))
13172 goto nla_put_failure;
13173
13174 nla_nest_end(msg, nla_wmm);
13175 }
13176
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013177 genlmsg_end(msg, hdr);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013178
Johannes Berg68eb5502013-11-19 15:19:38 +010013179 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013180 NL80211_MCGRP_MLME, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013181 return;
13182
13183 nla_put_failure:
13184 genlmsg_cancel(msg, hdr);
13185 nlmsg_free(msg);
13186}
13187
13188void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013189 struct net_device *netdev, const u8 *buf,
13190 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013191{
13192 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013193 NL80211_CMD_AUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013194}
13195
13196void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
13197 struct net_device *netdev, const u8 *buf,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013198 size_t len, gfp_t gfp, int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013199{
Johannes Berge6d6e342009-07-01 21:26:47 +020013200 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013201 NL80211_CMD_ASSOCIATE, gfp, uapsd_queues);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013202}
13203
Jouni Malinen53b46b82009-03-27 20:53:56 +020013204void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013205 struct net_device *netdev, const u8 *buf,
13206 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013207{
13208 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013209 NL80211_CMD_DEAUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013210}
13211
Jouni Malinen53b46b82009-03-27 20:53:56 +020013212void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
13213 struct net_device *netdev, const u8 *buf,
Johannes Berge6d6e342009-07-01 21:26:47 +020013214 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013215{
13216 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013217 NL80211_CMD_DISASSOCIATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013218}
13219
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013220void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
13221 size_t len)
Jouni Malinencf4e5942010-12-16 00:52:40 +020013222{
Johannes Berg947add32013-02-22 22:05:20 +010013223 struct wireless_dev *wdev = dev->ieee80211_ptr;
13224 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013225 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013226 const struct ieee80211_mgmt *mgmt = (void *)buf;
13227 u32 cmd;
Jouni Malinencf4e5942010-12-16 00:52:40 +020013228
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013229 if (WARN_ON(len < 2))
13230 return;
13231
13232 if (ieee80211_is_deauth(mgmt->frame_control))
13233 cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
13234 else
13235 cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
13236
13237 trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013238 nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013239}
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013240EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013241
Luis R. Rodriguez1b06bb42009-05-02 00:34:48 -040013242static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
13243 struct net_device *netdev, int cmd,
Johannes Berge6d6e342009-07-01 21:26:47 +020013244 const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013245{
13246 struct sk_buff *msg;
13247 void *hdr;
13248
Johannes Berge6d6e342009-07-01 21:26:47 +020013249 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013250 if (!msg)
13251 return;
13252
13253 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13254 if (!hdr) {
13255 nlmsg_free(msg);
13256 return;
13257 }
13258
David S. Miller9360ffd2012-03-29 04:41:26 -040013259 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13260 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13261 nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
13262 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
13263 goto nla_put_failure;
Jouni Malinen1965c852009-04-22 21:38:25 +030013264
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013265 genlmsg_end(msg, hdr);
Jouni Malinen1965c852009-04-22 21:38:25 +030013266
Johannes Berg68eb5502013-11-19 15:19:38 +010013267 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013268 NL80211_MCGRP_MLME, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013269 return;
13270
13271 nla_put_failure:
13272 genlmsg_cancel(msg, hdr);
13273 nlmsg_free(msg);
13274}
13275
13276void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013277 struct net_device *netdev, const u8 *addr,
13278 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013279{
13280 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
Johannes Berge6d6e342009-07-01 21:26:47 +020013281 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013282}
13283
13284void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013285 struct net_device *netdev, const u8 *addr,
13286 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013287{
Johannes Berge6d6e342009-07-01 21:26:47 +020013288 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
13289 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013290}
13291
Samuel Ortizb23aa672009-07-01 21:26:54 +020013292void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
13293 struct net_device *netdev, const u8 *bssid,
13294 const u8 *req_ie, size_t req_ie_len,
13295 const u8 *resp_ie, size_t resp_ie_len,
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020013296 int status,
13297 enum nl80211_timeout_reason timeout_reason,
13298 gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013299{
13300 struct sk_buff *msg;
13301 void *hdr;
13302
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013303 msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013304 if (!msg)
13305 return;
13306
13307 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
13308 if (!hdr) {
13309 nlmsg_free(msg);
13310 return;
13311 }
13312
David S. Miller9360ffd2012-03-29 04:41:26 -040013313 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13314 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13315 (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
Jouni Malinenbf1ecd22016-05-31 00:16:50 +030013316 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
13317 status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
13318 status) ||
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020013319 (status < 0 &&
13320 (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
13321 nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013322 (req_ie &&
13323 nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
13324 (resp_ie &&
13325 nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
13326 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013327
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013328 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013329
Johannes Berg68eb5502013-11-19 15:19:38 +010013330 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013331 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013332 return;
13333
13334 nla_put_failure:
13335 genlmsg_cancel(msg, hdr);
13336 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013337}
13338
13339void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
13340 struct net_device *netdev, const u8 *bssid,
13341 const u8 *req_ie, size_t req_ie_len,
13342 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
13343{
13344 struct sk_buff *msg;
13345 void *hdr;
13346
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013347 msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013348 if (!msg)
13349 return;
13350
13351 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
13352 if (!hdr) {
13353 nlmsg_free(msg);
13354 return;
13355 }
13356
David S. Miller9360ffd2012-03-29 04:41:26 -040013357 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13358 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13359 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
13360 (req_ie &&
13361 nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
13362 (resp_ie &&
13363 nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
13364 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013365
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013366 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013367
Johannes Berg68eb5502013-11-19 15:19:38 +010013368 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013369 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013370 return;
13371
13372 nla_put_failure:
13373 genlmsg_cancel(msg, hdr);
13374 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013375}
13376
13377void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
13378 struct net_device *netdev, u16 reason,
Johannes Berg667503d2009-07-07 03:56:11 +020013379 const u8 *ie, size_t ie_len, bool from_ap)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013380{
13381 struct sk_buff *msg;
13382 void *hdr;
13383
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013384 msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013385 if (!msg)
13386 return;
13387
13388 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
13389 if (!hdr) {
13390 nlmsg_free(msg);
13391 return;
13392 }
13393
David S. Miller9360ffd2012-03-29 04:41:26 -040013394 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13395 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13396 (from_ap && reason &&
13397 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
13398 (from_ap &&
13399 nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
13400 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
13401 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013402
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013403 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013404
Johannes Berg68eb5502013-11-19 15:19:38 +010013405 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013406 NL80211_MCGRP_MLME, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013407 return;
13408
13409 nla_put_failure:
13410 genlmsg_cancel(msg, hdr);
13411 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013412}
13413
Johannes Berg04a773a2009-04-19 21:24:32 +020013414void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
13415 struct net_device *netdev, const u8 *bssid,
13416 gfp_t gfp)
13417{
13418 struct sk_buff *msg;
13419 void *hdr;
13420
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013421 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013422 if (!msg)
13423 return;
13424
13425 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
13426 if (!hdr) {
13427 nlmsg_free(msg);
13428 return;
13429 }
13430
David S. Miller9360ffd2012-03-29 04:41:26 -040013431 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13432 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13433 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
13434 goto nla_put_failure;
Johannes Berg04a773a2009-04-19 21:24:32 +020013435
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013436 genlmsg_end(msg, hdr);
Johannes Berg04a773a2009-04-19 21:24:32 +020013437
Johannes Berg68eb5502013-11-19 15:19:38 +010013438 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013439 NL80211_MCGRP_MLME, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013440 return;
13441
13442 nla_put_failure:
13443 genlmsg_cancel(msg, hdr);
13444 nlmsg_free(msg);
13445}
13446
Johannes Berg947add32013-02-22 22:05:20 +010013447void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
13448 const u8* ie, u8 ie_len, gfp_t gfp)
Javier Cardonac93b5e72011-04-07 15:08:34 -070013449{
Johannes Berg947add32013-02-22 22:05:20 +010013450 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013451 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013452 struct sk_buff *msg;
13453 void *hdr;
13454
Johannes Berg947add32013-02-22 22:05:20 +010013455 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
13456 return;
13457
13458 trace_cfg80211_notify_new_peer_candidate(dev, addr);
13459
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013460 msg = nlmsg_new(100 + ie_len, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013461 if (!msg)
13462 return;
13463
13464 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
13465 if (!hdr) {
13466 nlmsg_free(msg);
13467 return;
13468 }
13469
David S. Miller9360ffd2012-03-29 04:41:26 -040013470 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010013471 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13472 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013473 (ie_len && ie &&
13474 nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
13475 goto nla_put_failure;
Javier Cardonac93b5e72011-04-07 15:08:34 -070013476
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013477 genlmsg_end(msg, hdr);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013478
Johannes Berg68eb5502013-11-19 15:19:38 +010013479 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013480 NL80211_MCGRP_MLME, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013481 return;
13482
13483 nla_put_failure:
13484 genlmsg_cancel(msg, hdr);
13485 nlmsg_free(msg);
13486}
Johannes Berg947add32013-02-22 22:05:20 +010013487EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013488
Jouni Malinena3b8b052009-03-27 21:59:49 +020013489void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
13490 struct net_device *netdev, const u8 *addr,
13491 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +020013492 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +020013493{
13494 struct sk_buff *msg;
13495 void *hdr;
13496
Johannes Berge6d6e342009-07-01 21:26:47 +020013497 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013498 if (!msg)
13499 return;
13500
13501 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
13502 if (!hdr) {
13503 nlmsg_free(msg);
13504 return;
13505 }
13506
David S. Miller9360ffd2012-03-29 04:41:26 -040013507 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13508 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13509 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
13510 nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
13511 (key_id != -1 &&
13512 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
13513 (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
13514 goto nla_put_failure;
Jouni Malinena3b8b052009-03-27 21:59:49 +020013515
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013516 genlmsg_end(msg, hdr);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013517
Johannes Berg68eb5502013-11-19 15:19:38 +010013518 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013519 NL80211_MCGRP_MLME, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013520 return;
13521
13522 nla_put_failure:
13523 genlmsg_cancel(msg, hdr);
13524 nlmsg_free(msg);
13525}
13526
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013527void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
13528 struct ieee80211_channel *channel_before,
13529 struct ieee80211_channel *channel_after)
13530{
13531 struct sk_buff *msg;
13532 void *hdr;
13533 struct nlattr *nl_freq;
13534
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013535 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013536 if (!msg)
13537 return;
13538
13539 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
13540 if (!hdr) {
13541 nlmsg_free(msg);
13542 return;
13543 }
13544
13545 /*
13546 * Since we are applying the beacon hint to a wiphy we know its
13547 * wiphy_idx is valid
13548 */
David S. Miller9360ffd2012-03-29 04:41:26 -040013549 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
13550 goto nla_put_failure;
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013551
13552 /* Before */
13553 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
13554 if (!nl_freq)
13555 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010013556 if (nl80211_msg_put_channel(msg, channel_before, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013557 goto nla_put_failure;
13558 nla_nest_end(msg, nl_freq);
13559
13560 /* After */
13561 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
13562 if (!nl_freq)
13563 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010013564 if (nl80211_msg_put_channel(msg, channel_after, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013565 goto nla_put_failure;
13566 nla_nest_end(msg, nl_freq);
13567
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013568 genlmsg_end(msg, hdr);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013569
Johannes Berg463d0182009-07-14 00:33:35 +020013570 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013571 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013572 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Berg463d0182009-07-14 00:33:35 +020013573 rcu_read_unlock();
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013574
13575 return;
13576
13577nla_put_failure:
13578 genlmsg_cancel(msg, hdr);
13579 nlmsg_free(msg);
13580}
13581
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013582static void nl80211_send_remain_on_chan_event(
13583 int cmd, struct cfg80211_registered_device *rdev,
Johannes Berg71bbc992012-06-15 15:30:18 +020013584 struct wireless_dev *wdev, u64 cookie,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013585 struct ieee80211_channel *chan,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013586 unsigned int duration, gfp_t gfp)
13587{
13588 struct sk_buff *msg;
13589 void *hdr;
13590
13591 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13592 if (!msg)
13593 return;
13594
13595 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13596 if (!hdr) {
13597 nlmsg_free(msg);
13598 return;
13599 }
13600
David S. Miller9360ffd2012-03-29 04:41:26 -040013601 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013602 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13603 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013604 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13605 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013606 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
Johannes Berg42d97a52012-11-08 18:31:02 +010013607 nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
13608 NL80211_CHAN_NO_HT) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013609 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13610 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013611 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013612
David S. Miller9360ffd2012-03-29 04:41:26 -040013613 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
13614 nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
13615 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013616
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013617 genlmsg_end(msg, hdr);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013618
Johannes Berg68eb5502013-11-19 15:19:38 +010013619 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013620 NL80211_MCGRP_MLME, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013621 return;
13622
13623 nla_put_failure:
13624 genlmsg_cancel(msg, hdr);
13625 nlmsg_free(msg);
13626}
13627
Johannes Berg947add32013-02-22 22:05:20 +010013628void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
13629 struct ieee80211_channel *chan,
13630 unsigned int duration, gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013631{
Johannes Berg947add32013-02-22 22:05:20 +010013632 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013633 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010013634
13635 trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013636 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Berg71bbc992012-06-15 15:30:18 +020013637 rdev, wdev, cookie, chan,
Johannes Berg42d97a52012-11-08 18:31:02 +010013638 duration, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013639}
Johannes Berg947add32013-02-22 22:05:20 +010013640EXPORT_SYMBOL(cfg80211_ready_on_channel);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013641
Johannes Berg947add32013-02-22 22:05:20 +010013642void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
13643 struct ieee80211_channel *chan,
13644 gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013645{
Johannes Berg947add32013-02-22 22:05:20 +010013646 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013647 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010013648
13649 trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013650 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Berg42d97a52012-11-08 18:31:02 +010013651 rdev, wdev, cookie, chan, 0, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013652}
Johannes Berg947add32013-02-22 22:05:20 +010013653EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013654
Johannes Berg947add32013-02-22 22:05:20 +010013655void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
13656 struct station_info *sinfo, gfp_t gfp)
Johannes Berg98b62182009-12-23 13:15:44 +010013657{
Johannes Berg947add32013-02-22 22:05:20 +010013658 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013659 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg98b62182009-12-23 13:15:44 +010013660 struct sk_buff *msg;
13661
Johannes Berg947add32013-02-22 22:05:20 +010013662 trace_cfg80211_new_sta(dev, mac_addr, sinfo);
13663
Thomas Graf58050fc2012-06-28 03:57:45 +000013664 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010013665 if (!msg)
13666 return;
13667
Johannes Bergcf5ead82014-11-14 17:14:00 +010013668 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
John W. Linville66266b32012-03-15 13:25:41 -040013669 rdev, dev, mac_addr, sinfo) < 0) {
Johannes Berg98b62182009-12-23 13:15:44 +010013670 nlmsg_free(msg);
13671 return;
13672 }
13673
Johannes Berg68eb5502013-11-19 15:19:38 +010013674 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013675 NL80211_MCGRP_MLME, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010013676}
Johannes Berg947add32013-02-22 22:05:20 +010013677EXPORT_SYMBOL(cfg80211_new_sta);
Johannes Berg98b62182009-12-23 13:15:44 +010013678
Johannes Bergcf5ead82014-11-14 17:14:00 +010013679void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
13680 struct station_info *sinfo, gfp_t gfp)
Jouni Malinenec15e682011-03-23 15:29:52 +020013681{
Johannes Berg947add32013-02-22 22:05:20 +010013682 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013683 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinenec15e682011-03-23 15:29:52 +020013684 struct sk_buff *msg;
Johannes Bergcf5ead82014-11-14 17:14:00 +010013685 struct station_info empty_sinfo = {};
13686
13687 if (!sinfo)
13688 sinfo = &empty_sinfo;
Jouni Malinenec15e682011-03-23 15:29:52 +020013689
Johannes Berg947add32013-02-22 22:05:20 +010013690 trace_cfg80211_del_sta(dev, mac_addr);
13691
Thomas Graf58050fc2012-06-28 03:57:45 +000013692 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020013693 if (!msg)
13694 return;
13695
Johannes Bergcf5ead82014-11-14 17:14:00 +010013696 if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
Johannes Berg57007122015-01-16 21:05:02 +010013697 rdev, dev, mac_addr, sinfo) < 0) {
Jouni Malinenec15e682011-03-23 15:29:52 +020013698 nlmsg_free(msg);
13699 return;
13700 }
13701
Johannes Berg68eb5502013-11-19 15:19:38 +010013702 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013703 NL80211_MCGRP_MLME, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020013704}
Johannes Bergcf5ead82014-11-14 17:14:00 +010013705EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
Jouni Malinenec15e682011-03-23 15:29:52 +020013706
Johannes Berg947add32013-02-22 22:05:20 +010013707void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
13708 enum nl80211_connect_failed_reason reason,
13709 gfp_t gfp)
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013710{
Johannes Berg947add32013-02-22 22:05:20 +010013711 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013712 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013713 struct sk_buff *msg;
13714 void *hdr;
13715
13716 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
13717 if (!msg)
13718 return;
13719
13720 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
13721 if (!hdr) {
13722 nlmsg_free(msg);
13723 return;
13724 }
13725
13726 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13727 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
13728 nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
13729 goto nla_put_failure;
13730
13731 genlmsg_end(msg, hdr);
13732
Johannes Berg68eb5502013-11-19 15:19:38 +010013733 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013734 NL80211_MCGRP_MLME, gfp);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013735 return;
13736
13737 nla_put_failure:
13738 genlmsg_cancel(msg, hdr);
13739 nlmsg_free(msg);
13740}
Johannes Berg947add32013-02-22 22:05:20 +010013741EXPORT_SYMBOL(cfg80211_conn_failed);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013742
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013743static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
13744 const u8 *addr, gfp_t gfp)
Johannes Berg28946da2011-11-04 11:18:12 +010013745{
13746 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013747 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg28946da2011-11-04 11:18:12 +010013748 struct sk_buff *msg;
13749 void *hdr;
Eric W. Biederman15e47302012-09-07 20:12:54 +000013750 u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010013751
Eric W. Biederman15e47302012-09-07 20:12:54 +000013752 if (!nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010013753 return false;
13754
13755 msg = nlmsg_new(100, gfp);
13756 if (!msg)
13757 return true;
13758
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013759 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Johannes Berg28946da2011-11-04 11:18:12 +010013760 if (!hdr) {
13761 nlmsg_free(msg);
13762 return true;
13763 }
13764
David S. Miller9360ffd2012-03-29 04:41:26 -040013765 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13766 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13767 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
13768 goto nla_put_failure;
Johannes Berg28946da2011-11-04 11:18:12 +010013769
Johannes Berg9c90a9f2013-06-04 12:46:03 +020013770 genlmsg_end(msg, hdr);
Eric W. Biederman15e47302012-09-07 20:12:54 +000013771 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010013772 return true;
13773
13774 nla_put_failure:
13775 genlmsg_cancel(msg, hdr);
13776 nlmsg_free(msg);
13777 return true;
13778}
13779
Johannes Berg947add32013-02-22 22:05:20 +010013780bool cfg80211_rx_spurious_frame(struct net_device *dev,
13781 const u8 *addr, gfp_t gfp)
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013782{
Johannes Berg947add32013-02-22 22:05:20 +010013783 struct wireless_dev *wdev = dev->ieee80211_ptr;
13784 bool ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013785
Johannes Berg947add32013-02-22 22:05:20 +010013786 trace_cfg80211_rx_spurious_frame(dev, addr);
13787
13788 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
13789 wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
13790 trace_cfg80211_return_bool(false);
13791 return false;
13792 }
13793 ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
13794 addr, gfp);
13795 trace_cfg80211_return_bool(ret);
13796 return ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013797}
Johannes Berg947add32013-02-22 22:05:20 +010013798EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
13799
13800bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
13801 const u8 *addr, gfp_t gfp)
13802{
13803 struct wireless_dev *wdev = dev->ieee80211_ptr;
13804 bool ret;
13805
13806 trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
13807
13808 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
13809 wdev->iftype != NL80211_IFTYPE_P2P_GO &&
13810 wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
13811 trace_cfg80211_return_bool(false);
13812 return false;
13813 }
13814 ret = __nl80211_unexpected_frame(dev,
13815 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
13816 addr, gfp);
13817 trace_cfg80211_return_bool(ret);
13818 return ret;
13819}
13820EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013821
Johannes Berg2e161f782010-08-12 15:38:38 +020013822int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013823 struct wireless_dev *wdev, u32 nlportid,
Johannes Berg804483e2012-03-05 22:18:41 +010013824 int freq, int sig_dbm,
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030013825 const u8 *buf, size_t len, u32 flags, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020013826{
Johannes Berg71bbc992012-06-15 15:30:18 +020013827 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020013828 struct sk_buff *msg;
13829 void *hdr;
Jouni Malinen026331c2010-02-15 12:53:10 +020013830
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013831 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020013832 if (!msg)
13833 return -ENOMEM;
13834
Johannes Berg2e161f782010-08-12 15:38:38 +020013835 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
Jouni Malinen026331c2010-02-15 12:53:10 +020013836 if (!hdr) {
13837 nlmsg_free(msg);
13838 return -ENOMEM;
13839 }
13840
David S. Miller9360ffd2012-03-29 04:41:26 -040013841 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013842 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13843 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013844 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13845 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013846 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
13847 (sig_dbm &&
13848 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030013849 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
13850 (flags &&
13851 nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
David S. Miller9360ffd2012-03-29 04:41:26 -040013852 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020013853
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013854 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020013855
Eric W. Biederman15e47302012-09-07 20:12:54 +000013856 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Jouni Malinen026331c2010-02-15 12:53:10 +020013857
13858 nla_put_failure:
13859 genlmsg_cancel(msg, hdr);
13860 nlmsg_free(msg);
13861 return -ENOBUFS;
13862}
13863
Johannes Berg947add32013-02-22 22:05:20 +010013864void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
13865 const u8 *buf, size_t len, bool ack, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020013866{
Johannes Berg947add32013-02-22 22:05:20 +010013867 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013868 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg71bbc992012-06-15 15:30:18 +020013869 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020013870 struct sk_buff *msg;
13871 void *hdr;
13872
Johannes Berg947add32013-02-22 22:05:20 +010013873 trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
13874
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013875 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020013876 if (!msg)
13877 return;
13878
Johannes Berg2e161f782010-08-12 15:38:38 +020013879 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
Jouni Malinen026331c2010-02-15 12:53:10 +020013880 if (!hdr) {
13881 nlmsg_free(msg);
13882 return;
13883 }
13884
David S. Miller9360ffd2012-03-29 04:41:26 -040013885 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013886 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13887 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013888 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13889 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013890 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013891 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13892 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013893 (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
13894 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020013895
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013896 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020013897
Johannes Berg68eb5502013-11-19 15:19:38 +010013898 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013899 NL80211_MCGRP_MLME, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020013900 return;
13901
13902 nla_put_failure:
13903 genlmsg_cancel(msg, hdr);
13904 nlmsg_free(msg);
13905}
Johannes Berg947add32013-02-22 22:05:20 +010013906EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
Jouni Malinen026331c2010-02-15 12:53:10 +020013907
Johannes Berg5b97f492014-11-26 12:37:43 +010013908static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
13909 const char *mac, gfp_t gfp)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013910{
Johannes Berg947add32013-02-22 22:05:20 +010013911 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg5b97f492014-11-26 12:37:43 +010013912 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
13913 struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13914 void **cb;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013915
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013916 if (!msg)
Johannes Berg5b97f492014-11-26 12:37:43 +010013917 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013918
Johannes Berg5b97f492014-11-26 12:37:43 +010013919 cb = (void **)msg->cb;
13920
13921 cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
13922 if (!cb[0]) {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013923 nlmsg_free(msg);
Johannes Berg5b97f492014-11-26 12:37:43 +010013924 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013925 }
13926
David S. Miller9360ffd2012-03-29 04:41:26 -040013927 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010013928 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
David S. Miller9360ffd2012-03-29 04:41:26 -040013929 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013930
Johannes Berg5b97f492014-11-26 12:37:43 +010013931 if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013932 goto nla_put_failure;
13933
Johannes Berg5b97f492014-11-26 12:37:43 +010013934 cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM);
13935 if (!cb[1])
13936 goto nla_put_failure;
13937
13938 cb[2] = rdev;
13939
13940 return msg;
13941 nla_put_failure:
13942 nlmsg_free(msg);
13943 return NULL;
13944}
13945
13946static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
13947{
13948 void **cb = (void **)msg->cb;
13949 struct cfg80211_registered_device *rdev = cb[2];
13950
13951 nla_nest_end(msg, cb[1]);
13952 genlmsg_end(msg, cb[0]);
13953
13954 memset(msg->cb, 0, sizeof(msg->cb));
13955
13956 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
13957 NL80211_MCGRP_MLME, gfp);
13958}
13959
13960void cfg80211_cqm_rssi_notify(struct net_device *dev,
13961 enum nl80211_cqm_rssi_threshold_event rssi_event,
13962 gfp_t gfp)
13963{
13964 struct sk_buff *msg;
13965
13966 trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
13967
Johannes Berg98f03342014-11-26 12:42:02 +010013968 if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
13969 rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
13970 return;
13971
Johannes Berg5b97f492014-11-26 12:37:43 +010013972 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
13973 if (!msg)
13974 return;
13975
David S. Miller9360ffd2012-03-29 04:41:26 -040013976 if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
13977 rssi_event))
13978 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013979
Johannes Berg5b97f492014-11-26 12:37:43 +010013980 cfg80211_send_cqm(msg, gfp);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013981
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013982 return;
13983
13984 nla_put_failure:
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013985 nlmsg_free(msg);
13986}
Johannes Berg947add32013-02-22 22:05:20 +010013987EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013988
Johannes Berg5b97f492014-11-26 12:37:43 +010013989void cfg80211_cqm_txe_notify(struct net_device *dev,
13990 const u8 *peer, u32 num_packets,
13991 u32 rate, u32 intvl, gfp_t gfp)
13992{
13993 struct sk_buff *msg;
13994
13995 msg = cfg80211_prepare_cqm(dev, peer, gfp);
13996 if (!msg)
13997 return;
13998
13999 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
14000 goto nla_put_failure;
14001
14002 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
14003 goto nla_put_failure;
14004
14005 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
14006 goto nla_put_failure;
14007
14008 cfg80211_send_cqm(msg, gfp);
14009 return;
14010
14011 nla_put_failure:
14012 nlmsg_free(msg);
14013}
14014EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
14015
14016void cfg80211_cqm_pktloss_notify(struct net_device *dev,
14017 const u8 *peer, u32 num_packets, gfp_t gfp)
14018{
14019 struct sk_buff *msg;
14020
14021 trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
14022
14023 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14024 if (!msg)
14025 return;
14026
14027 if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
14028 goto nla_put_failure;
14029
14030 cfg80211_send_cqm(msg, gfp);
14031 return;
14032
14033 nla_put_failure:
14034 nlmsg_free(msg);
14035}
14036EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
14037
Johannes Berg98f03342014-11-26 12:42:02 +010014038void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
14039{
14040 struct sk_buff *msg;
14041
14042 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14043 if (!msg)
14044 return;
14045
14046 if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
14047 goto nla_put_failure;
14048
14049 cfg80211_send_cqm(msg, gfp);
14050 return;
14051
14052 nla_put_failure:
14053 nlmsg_free(msg);
14054}
14055EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
14056
Johannes Berg947add32013-02-22 22:05:20 +010014057static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
14058 struct net_device *netdev, const u8 *bssid,
14059 const u8 *replay_ctr, gfp_t gfp)
Johannes Berge5497d72011-07-05 16:35:40 +020014060{
14061 struct sk_buff *msg;
14062 struct nlattr *rekey_attr;
14063 void *hdr;
14064
Thomas Graf58050fc2012-06-28 03:57:45 +000014065 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014066 if (!msg)
14067 return;
14068
14069 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
14070 if (!hdr) {
14071 nlmsg_free(msg);
14072 return;
14073 }
14074
David S. Miller9360ffd2012-03-29 04:41:26 -040014075 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14076 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14077 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
14078 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014079
14080 rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
14081 if (!rekey_attr)
14082 goto nla_put_failure;
14083
David S. Miller9360ffd2012-03-29 04:41:26 -040014084 if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
14085 NL80211_REPLAY_CTR_LEN, replay_ctr))
14086 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014087
14088 nla_nest_end(msg, rekey_attr);
14089
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014090 genlmsg_end(msg, hdr);
Johannes Berge5497d72011-07-05 16:35:40 +020014091
Johannes Berg68eb5502013-11-19 15:19:38 +010014092 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014093 NL80211_MCGRP_MLME, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014094 return;
14095
14096 nla_put_failure:
14097 genlmsg_cancel(msg, hdr);
14098 nlmsg_free(msg);
14099}
14100
Johannes Berg947add32013-02-22 22:05:20 +010014101void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
14102 const u8 *replay_ctr, gfp_t gfp)
14103{
14104 struct wireless_dev *wdev = dev->ieee80211_ptr;
14105 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014106 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014107
14108 trace_cfg80211_gtk_rekey_notify(dev, bssid);
14109 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
14110}
14111EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
14112
14113static void
14114nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
14115 struct net_device *netdev, int index,
14116 const u8 *bssid, bool preauth, gfp_t gfp)
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014117{
14118 struct sk_buff *msg;
14119 struct nlattr *attr;
14120 void *hdr;
14121
Thomas Graf58050fc2012-06-28 03:57:45 +000014122 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014123 if (!msg)
14124 return;
14125
14126 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
14127 if (!hdr) {
14128 nlmsg_free(msg);
14129 return;
14130 }
14131
David S. Miller9360ffd2012-03-29 04:41:26 -040014132 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14133 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14134 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014135
14136 attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
14137 if (!attr)
14138 goto nla_put_failure;
14139
David S. Miller9360ffd2012-03-29 04:41:26 -040014140 if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
14141 nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
14142 (preauth &&
14143 nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
14144 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014145
14146 nla_nest_end(msg, attr);
14147
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014148 genlmsg_end(msg, hdr);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014149
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 Malinenc9df56b2011-09-16 18:56:23 +030014152 return;
14153
14154 nla_put_failure:
14155 genlmsg_cancel(msg, hdr);
14156 nlmsg_free(msg);
14157}
14158
Johannes Berg947add32013-02-22 22:05:20 +010014159void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
14160 const u8 *bssid, bool preauth, gfp_t gfp)
14161{
14162 struct wireless_dev *wdev = dev->ieee80211_ptr;
14163 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014164 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014165
14166 trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
14167 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
14168}
14169EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
14170
14171static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
14172 struct net_device *netdev,
14173 struct cfg80211_chan_def *chandef,
Luciano Coelhof8d75522014-11-07 14:31:35 +020014174 gfp_t gfp,
14175 enum nl80211_commands notif,
14176 u8 count)
Thomas Pedersen53145262012-04-06 13:35:47 -070014177{
14178 struct sk_buff *msg;
14179 void *hdr;
14180
Thomas Graf58050fc2012-06-28 03:57:45 +000014181 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014182 if (!msg)
14183 return;
14184
Luciano Coelhof8d75522014-11-07 14:31:35 +020014185 hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
Thomas Pedersen53145262012-04-06 13:35:47 -070014186 if (!hdr) {
14187 nlmsg_free(msg);
14188 return;
14189 }
14190
Johannes Berg683b6d32012-11-08 21:25:48 +010014191 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14192 goto nla_put_failure;
14193
14194 if (nl80211_send_chandef(msg, chandef))
John W. Linville7eab0f62012-04-12 14:25:14 -040014195 goto nla_put_failure;
Thomas Pedersen53145262012-04-06 13:35:47 -070014196
Luciano Coelhof8d75522014-11-07 14:31:35 +020014197 if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
14198 (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
14199 goto nla_put_failure;
14200
Thomas Pedersen53145262012-04-06 13:35:47 -070014201 genlmsg_end(msg, hdr);
14202
Johannes Berg68eb5502013-11-19 15:19:38 +010014203 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014204 NL80211_MCGRP_MLME, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014205 return;
14206
14207 nla_put_failure:
14208 genlmsg_cancel(msg, hdr);
14209 nlmsg_free(msg);
14210}
14211
Johannes Berg947add32013-02-22 22:05:20 +010014212void cfg80211_ch_switch_notify(struct net_device *dev,
14213 struct cfg80211_chan_def *chandef)
Thomas Pedersen84f10702012-07-12 16:17:33 -070014214{
Johannes Berg947add32013-02-22 22:05:20 +010014215 struct wireless_dev *wdev = dev->ieee80211_ptr;
14216 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014217 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014218
Simon Wunderliche487eae2013-11-21 18:19:51 +010014219 ASSERT_WDEV_LOCK(wdev);
Johannes Berg947add32013-02-22 22:05:20 +010014220
Simon Wunderliche487eae2013-11-21 18:19:51 +010014221 trace_cfg80211_ch_switch_notify(dev, chandef);
Johannes Berg947add32013-02-22 22:05:20 +010014222
Michal Kazior9e0e2962014-01-29 14:22:27 +010014223 wdev->chandef = *chandef;
Janusz Dziedzic96f55f12014-01-24 14:29:21 +010014224 wdev->preset_chandef = *chandef;
Luciano Coelhof8d75522014-11-07 14:31:35 +020014225 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14226 NL80211_CMD_CH_SWITCH_NOTIFY, 0);
Johannes Berg947add32013-02-22 22:05:20 +010014227}
14228EXPORT_SYMBOL(cfg80211_ch_switch_notify);
14229
Luciano Coelhof8d75522014-11-07 14:31:35 +020014230void cfg80211_ch_switch_started_notify(struct net_device *dev,
14231 struct cfg80211_chan_def *chandef,
14232 u8 count)
14233{
14234 struct wireless_dev *wdev = dev->ieee80211_ptr;
14235 struct wiphy *wiphy = wdev->wiphy;
14236 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
14237
14238 trace_cfg80211_ch_switch_started_notify(dev, chandef);
14239
14240 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14241 NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
14242}
14243EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
14244
Thomas Pedersen84f10702012-07-12 16:17:33 -070014245void
Simon Wunderlich04f39042013-02-08 18:16:19 +010014246nl80211_radar_notify(struct cfg80211_registered_device *rdev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +010014247 const struct cfg80211_chan_def *chandef,
Simon Wunderlich04f39042013-02-08 18:16:19 +010014248 enum nl80211_radar_event event,
14249 struct net_device *netdev, gfp_t gfp)
14250{
14251 struct sk_buff *msg;
14252 void *hdr;
14253
14254 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14255 if (!msg)
14256 return;
14257
14258 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
14259 if (!hdr) {
14260 nlmsg_free(msg);
14261 return;
14262 }
14263
14264 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
14265 goto nla_put_failure;
14266
14267 /* NOP and radar events don't need a netdev parameter */
14268 if (netdev) {
14269 struct wireless_dev *wdev = netdev->ieee80211_ptr;
14270
14271 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014272 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14273 NL80211_ATTR_PAD))
Simon Wunderlich04f39042013-02-08 18:16:19 +010014274 goto nla_put_failure;
14275 }
14276
14277 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
14278 goto nla_put_failure;
14279
14280 if (nl80211_send_chandef(msg, chandef))
14281 goto nla_put_failure;
14282
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014283 genlmsg_end(msg, hdr);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014284
Johannes Berg68eb5502013-11-19 15:19:38 +010014285 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014286 NL80211_MCGRP_MLME, gfp);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014287 return;
14288
14289 nla_put_failure:
14290 genlmsg_cancel(msg, hdr);
14291 nlmsg_free(msg);
14292}
14293
Johannes Berg7f6cf312011-11-04 11:18:15 +010014294void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
14295 u64 cookie, bool acked, gfp_t gfp)
14296{
14297 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014298 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014299 struct sk_buff *msg;
14300 void *hdr;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014301
Beni Lev4ee3e062012-08-27 12:49:39 +030014302 trace_cfg80211_probe_status(dev, addr, cookie, acked);
14303
Thomas Graf58050fc2012-06-28 03:57:45 +000014304 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Beni Lev4ee3e062012-08-27 12:49:39 +030014305
Johannes Berg7f6cf312011-11-04 11:18:15 +010014306 if (!msg)
14307 return;
14308
14309 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
14310 if (!hdr) {
14311 nlmsg_free(msg);
14312 return;
14313 }
14314
David S. Miller9360ffd2012-03-29 04:41:26 -040014315 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14316 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14317 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014318 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14319 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014320 (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
14321 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014322
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014323 genlmsg_end(msg, hdr);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014324
Johannes Berg68eb5502013-11-19 15:19:38 +010014325 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014326 NL80211_MCGRP_MLME, gfp);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014327 return;
14328
14329 nla_put_failure:
14330 genlmsg_cancel(msg, hdr);
14331 nlmsg_free(msg);
14332}
14333EXPORT_SYMBOL(cfg80211_probe_status);
14334
Johannes Berg5e760232011-11-04 11:18:17 +010014335void cfg80211_report_obss_beacon(struct wiphy *wiphy,
14336 const u8 *frame, size_t len,
Ben Greear37c73b52012-10-26 14:49:25 -070014337 int freq, int sig_dbm)
Johannes Berg5e760232011-11-04 11:18:17 +010014338{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014339 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg5e760232011-11-04 11:18:17 +010014340 struct sk_buff *msg;
14341 void *hdr;
Ben Greear37c73b52012-10-26 14:49:25 -070014342 struct cfg80211_beacon_registration *reg;
Johannes Berg5e760232011-11-04 11:18:17 +010014343
Beni Lev4ee3e062012-08-27 12:49:39 +030014344 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
14345
Ben Greear37c73b52012-10-26 14:49:25 -070014346 spin_lock_bh(&rdev->beacon_registrations_lock);
14347 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
14348 msg = nlmsg_new(len + 100, GFP_ATOMIC);
14349 if (!msg) {
14350 spin_unlock_bh(&rdev->beacon_registrations_lock);
14351 return;
14352 }
Johannes Berg5e760232011-11-04 11:18:17 +010014353
Ben Greear37c73b52012-10-26 14:49:25 -070014354 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
14355 if (!hdr)
14356 goto nla_put_failure;
Johannes Berg5e760232011-11-04 11:18:17 +010014357
Ben Greear37c73b52012-10-26 14:49:25 -070014358 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14359 (freq &&
14360 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
14361 (sig_dbm &&
14362 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
14363 nla_put(msg, NL80211_ATTR_FRAME, len, frame))
14364 goto nla_put_failure;
14365
14366 genlmsg_end(msg, hdr);
14367
14368 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
Johannes Berg5e760232011-11-04 11:18:17 +010014369 }
Ben Greear37c73b52012-10-26 14:49:25 -070014370 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010014371 return;
14372
14373 nla_put_failure:
Ben Greear37c73b52012-10-26 14:49:25 -070014374 spin_unlock_bh(&rdev->beacon_registrations_lock);
14375 if (hdr)
14376 genlmsg_cancel(msg, hdr);
Johannes Berg5e760232011-11-04 11:18:17 +010014377 nlmsg_free(msg);
14378}
14379EXPORT_SYMBOL(cfg80211_report_obss_beacon);
14380
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014381#ifdef CONFIG_PM
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014382static int cfg80211_net_detect_results(struct sk_buff *msg,
14383 struct cfg80211_wowlan_wakeup *wakeup)
14384{
14385 struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
14386 struct nlattr *nl_results, *nl_match, *nl_freqs;
14387 int i, j;
14388
14389 nl_results = nla_nest_start(
14390 msg, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
14391 if (!nl_results)
14392 return -EMSGSIZE;
14393
14394 for (i = 0; i < nd->n_matches; i++) {
14395 struct cfg80211_wowlan_nd_match *match = nd->matches[i];
14396
14397 nl_match = nla_nest_start(msg, i);
14398 if (!nl_match)
14399 break;
14400
14401 /* The SSID attribute is optional in nl80211, but for
14402 * simplicity reasons it's always present in the
14403 * cfg80211 structure. If a driver can't pass the
14404 * SSID, that needs to be changed. A zero length SSID
14405 * is still a valid SSID (wildcard), so it cannot be
14406 * used for this purpose.
14407 */
14408 if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
14409 match->ssid.ssid)) {
14410 nla_nest_cancel(msg, nl_match);
14411 goto out;
14412 }
14413
14414 if (match->n_channels) {
14415 nl_freqs = nla_nest_start(
14416 msg, NL80211_ATTR_SCAN_FREQUENCIES);
14417 if (!nl_freqs) {
14418 nla_nest_cancel(msg, nl_match);
14419 goto out;
14420 }
14421
14422 for (j = 0; j < match->n_channels; j++) {
Samuel Tan5528fae82015-02-09 21:29:15 +020014423 if (nla_put_u32(msg, j, match->channels[j])) {
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014424 nla_nest_cancel(msg, nl_freqs);
14425 nla_nest_cancel(msg, nl_match);
14426 goto out;
14427 }
14428 }
14429
14430 nla_nest_end(msg, nl_freqs);
14431 }
14432
14433 nla_nest_end(msg, nl_match);
14434 }
14435
14436out:
14437 nla_nest_end(msg, nl_results);
14438 return 0;
14439}
14440
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014441void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
14442 struct cfg80211_wowlan_wakeup *wakeup,
14443 gfp_t gfp)
14444{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014445 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014446 struct sk_buff *msg;
14447 void *hdr;
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014448 int size = 200;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014449
14450 trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
14451
14452 if (wakeup)
14453 size += wakeup->packet_present_len;
14454
14455 msg = nlmsg_new(size, gfp);
14456 if (!msg)
14457 return;
14458
14459 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
14460 if (!hdr)
14461 goto free_msg;
14462
14463 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014464 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14465 NL80211_ATTR_PAD))
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014466 goto free_msg;
14467
14468 if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14469 wdev->netdev->ifindex))
14470 goto free_msg;
14471
14472 if (wakeup) {
14473 struct nlattr *reasons;
14474
14475 reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Berg7fa322c2013-10-25 11:16:58 +020014476 if (!reasons)
14477 goto free_msg;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014478
14479 if (wakeup->disconnect &&
14480 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
14481 goto free_msg;
14482 if (wakeup->magic_pkt &&
14483 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
14484 goto free_msg;
14485 if (wakeup->gtk_rekey_failure &&
14486 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
14487 goto free_msg;
14488 if (wakeup->eap_identity_req &&
14489 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
14490 goto free_msg;
14491 if (wakeup->four_way_handshake &&
14492 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
14493 goto free_msg;
14494 if (wakeup->rfkill_release &&
14495 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
14496 goto free_msg;
14497
14498 if (wakeup->pattern_idx >= 0 &&
14499 nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
14500 wakeup->pattern_idx))
14501 goto free_msg;
14502
Johannes Bergae917c92013-10-25 11:05:22 +020014503 if (wakeup->tcp_match &&
14504 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
14505 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014506
Johannes Bergae917c92013-10-25 11:05:22 +020014507 if (wakeup->tcp_connlost &&
14508 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
14509 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014510
Johannes Bergae917c92013-10-25 11:05:22 +020014511 if (wakeup->tcp_nomoretokens &&
14512 nla_put_flag(msg,
14513 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
14514 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014515
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014516 if (wakeup->packet) {
14517 u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
14518 u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
14519
14520 if (!wakeup->packet_80211) {
14521 pkt_attr =
14522 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
14523 len_attr =
14524 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
14525 }
14526
14527 if (wakeup->packet_len &&
14528 nla_put_u32(msg, len_attr, wakeup->packet_len))
14529 goto free_msg;
14530
14531 if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
14532 wakeup->packet))
14533 goto free_msg;
14534 }
14535
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014536 if (wakeup->net_detect &&
14537 cfg80211_net_detect_results(msg, wakeup))
14538 goto free_msg;
14539
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014540 nla_nest_end(msg, reasons);
14541 }
14542
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014543 genlmsg_end(msg, hdr);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014544
Johannes Berg68eb5502013-11-19 15:19:38 +010014545 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014546 NL80211_MCGRP_MLME, gfp);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014547 return;
14548
14549 free_msg:
14550 nlmsg_free(msg);
14551}
14552EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
14553#endif
14554
Jouni Malinen3475b092012-11-16 22:49:57 +020014555void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
14556 enum nl80211_tdls_operation oper,
14557 u16 reason_code, gfp_t gfp)
14558{
14559 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014560 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Jouni Malinen3475b092012-11-16 22:49:57 +020014561 struct sk_buff *msg;
14562 void *hdr;
Jouni Malinen3475b092012-11-16 22:49:57 +020014563
14564 trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
14565 reason_code);
14566
14567 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14568 if (!msg)
14569 return;
14570
14571 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
14572 if (!hdr) {
14573 nlmsg_free(msg);
14574 return;
14575 }
14576
14577 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14578 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14579 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
14580 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
14581 (reason_code > 0 &&
14582 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
14583 goto nla_put_failure;
14584
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014585 genlmsg_end(msg, hdr);
Jouni Malinen3475b092012-11-16 22:49:57 +020014586
Johannes Berg68eb5502013-11-19 15:19:38 +010014587 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014588 NL80211_MCGRP_MLME, gfp);
Jouni Malinen3475b092012-11-16 22:49:57 +020014589 return;
14590
14591 nla_put_failure:
14592 genlmsg_cancel(msg, hdr);
14593 nlmsg_free(msg);
14594}
14595EXPORT_SYMBOL(cfg80211_tdls_oper_request);
14596
Jouni Malinen026331c2010-02-15 12:53:10 +020014597static int nl80211_netlink_notify(struct notifier_block * nb,
14598 unsigned long state,
14599 void *_notify)
14600{
14601 struct netlink_notify *notify = _notify;
14602 struct cfg80211_registered_device *rdev;
14603 struct wireless_dev *wdev;
Ben Greear37c73b52012-10-26 14:49:25 -070014604 struct cfg80211_beacon_registration *reg, *tmp;
Jouni Malinen026331c2010-02-15 12:53:10 +020014605
Dmitry Ivanov8f815cd2016-04-06 17:23:18 +030014606 if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
Jouni Malinen026331c2010-02-15 12:53:10 +020014607 return NOTIFY_DONE;
14608
14609 rcu_read_lock();
14610
Johannes Berg5e760232011-11-04 11:18:17 +010014611 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
Johannes Berg78f22b62014-03-24 17:57:27 +010014612 bool schedule_destroy_work = false;
Jukka Rissanen93a1e862014-12-15 13:25:39 +020014613 struct cfg80211_sched_scan_request *sched_scan_req =
14614 rcu_dereference(rdev->sched_scan_req);
14615
14616 if (sched_scan_req && notify->portid &&
Johannes Berg753aacf2017-01-05 10:57:14 +010014617 sched_scan_req->owner_nlportid == notify->portid) {
14618 sched_scan_req->owner_nlportid = 0;
14619
14620 if (rdev->ops->sched_scan_stop &&
14621 rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
14622 schedule_work(&rdev->sched_scan_stop_wk);
14623 }
Johannes Berg78f22b62014-03-24 17:57:27 +010014624
Johannes Berg53873f12016-05-03 16:52:04 +030014625 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000014626 cfg80211_mlme_unregister_socket(wdev, notify->portid);
Ben Greear37c73b52012-10-26 14:49:25 -070014627
Johannes Berg78f22b62014-03-24 17:57:27 +010014628 if (wdev->owner_nlportid == notify->portid)
14629 schedule_destroy_work = true;
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050014630 else if (wdev->conn_owner_nlportid == notify->portid)
14631 schedule_work(&wdev->disconnect_wk);
Johannes Berg78f22b62014-03-24 17:57:27 +010014632 }
14633
Ben Greear37c73b52012-10-26 14:49:25 -070014634 spin_lock_bh(&rdev->beacon_registrations_lock);
14635 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
14636 list) {
14637 if (reg->nlportid == notify->portid) {
14638 list_del(&reg->list);
14639 kfree(reg);
14640 break;
14641 }
14642 }
14643 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg78f22b62014-03-24 17:57:27 +010014644
14645 if (schedule_destroy_work) {
14646 struct cfg80211_iface_destroy *destroy;
14647
14648 destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC);
14649 if (destroy) {
14650 destroy->nlportid = notify->portid;
14651 spin_lock(&rdev->destroy_list_lock);
14652 list_add(&destroy->list, &rdev->destroy_list);
14653 spin_unlock(&rdev->destroy_list_lock);
14654 schedule_work(&rdev->destroy_work);
14655 }
14656 }
Johannes Berg5e760232011-11-04 11:18:17 +010014657 }
Jouni Malinen026331c2010-02-15 12:53:10 +020014658
14659 rcu_read_unlock();
14660
Ilan peer05050752015-03-04 00:32:06 -050014661 /*
14662 * It is possible that the user space process that is controlling the
14663 * indoor setting disappeared, so notify the regulatory core.
14664 */
14665 regulatory_netlink_notify(notify->portid);
Zhao, Gang6784c7d2014-04-21 12:53:04 +080014666 return NOTIFY_OK;
Jouni Malinen026331c2010-02-15 12:53:10 +020014667}
14668
14669static struct notifier_block nl80211_netlink_notifier = {
14670 .notifier_call = nl80211_netlink_notify,
14671};
14672
Jouni Malinen355199e2013-02-27 17:14:27 +020014673void cfg80211_ft_event(struct net_device *netdev,
14674 struct cfg80211_ft_event_params *ft_event)
14675{
14676 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014677 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinen355199e2013-02-27 17:14:27 +020014678 struct sk_buff *msg;
14679 void *hdr;
Jouni Malinen355199e2013-02-27 17:14:27 +020014680
14681 trace_cfg80211_ft_event(wiphy, netdev, ft_event);
14682
14683 if (!ft_event->target_ap)
14684 return;
14685
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014686 msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
Jouni Malinen355199e2013-02-27 17:14:27 +020014687 if (!msg)
14688 return;
14689
14690 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
Johannes Bergae917c92013-10-25 11:05:22 +020014691 if (!hdr)
14692 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020014693
Johannes Bergae917c92013-10-25 11:05:22 +020014694 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14695 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14696 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
14697 goto out;
14698
14699 if (ft_event->ies &&
14700 nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
14701 goto out;
14702 if (ft_event->ric_ies &&
14703 nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
14704 ft_event->ric_ies))
14705 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020014706
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014707 genlmsg_end(msg, hdr);
Jouni Malinen355199e2013-02-27 17:14:27 +020014708
Johannes Berg68eb5502013-11-19 15:19:38 +010014709 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014710 NL80211_MCGRP_MLME, GFP_KERNEL);
Johannes Bergae917c92013-10-25 11:05:22 +020014711 return;
14712 out:
14713 nlmsg_free(msg);
Jouni Malinen355199e2013-02-27 17:14:27 +020014714}
14715EXPORT_SYMBOL(cfg80211_ft_event);
14716
Arend van Spriel5de17982013-04-18 15:49:00 +020014717void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
14718{
14719 struct cfg80211_registered_device *rdev;
14720 struct sk_buff *msg;
14721 void *hdr;
14722 u32 nlportid;
14723
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014724 rdev = wiphy_to_rdev(wdev->wiphy);
Arend van Spriel5de17982013-04-18 15:49:00 +020014725 if (!rdev->crit_proto_nlportid)
14726 return;
14727
14728 nlportid = rdev->crit_proto_nlportid;
14729 rdev->crit_proto_nlportid = 0;
14730
14731 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14732 if (!msg)
14733 return;
14734
14735 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
14736 if (!hdr)
14737 goto nla_put_failure;
14738
14739 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014740 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14741 NL80211_ATTR_PAD))
Arend van Spriel5de17982013-04-18 15:49:00 +020014742 goto nla_put_failure;
14743
14744 genlmsg_end(msg, hdr);
14745
14746 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
14747 return;
14748
14749 nla_put_failure:
14750 if (hdr)
14751 genlmsg_cancel(msg, hdr);
14752 nlmsg_free(msg);
Arend van Spriel5de17982013-04-18 15:49:00 +020014753}
14754EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
14755
Johannes Berg348baf02014-01-24 14:06:29 +010014756void nl80211_send_ap_stopped(struct wireless_dev *wdev)
14757{
14758 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014759 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg348baf02014-01-24 14:06:29 +010014760 struct sk_buff *msg;
14761 void *hdr;
14762
14763 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14764 if (!msg)
14765 return;
14766
14767 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
14768 if (!hdr)
14769 goto out;
14770
14771 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14772 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014773 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14774 NL80211_ATTR_PAD))
Johannes Berg348baf02014-01-24 14:06:29 +010014775 goto out;
14776
14777 genlmsg_end(msg, hdr);
14778
14779 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
14780 NL80211_MCGRP_MLME, GFP_KERNEL);
14781 return;
14782 out:
14783 nlmsg_free(msg);
14784}
14785
Johannes Berg55682962007-09-20 13:09:35 -040014786/* initialisation/exit functions */
14787
Johannes Berg56989f62016-10-24 14:40:05 +020014788int __init nl80211_init(void)
Johannes Berg55682962007-09-20 13:09:35 -040014789{
Michał Mirosław0d63cbb2009-05-21 10:34:06 +000014790 int err;
Johannes Berg55682962007-09-20 13:09:35 -040014791
Johannes Berg489111e2016-10-24 14:40:03 +020014792 err = genl_register_family(&nl80211_fam);
Johannes Berg55682962007-09-20 13:09:35 -040014793 if (err)
14794 return err;
14795
Jouni Malinen026331c2010-02-15 12:53:10 +020014796 err = netlink_register_notifier(&nl80211_netlink_notifier);
14797 if (err)
14798 goto err_out;
14799
Johannes Berg55682962007-09-20 13:09:35 -040014800 return 0;
14801 err_out:
14802 genl_unregister_family(&nl80211_fam);
14803 return err;
14804}
14805
14806void nl80211_exit(void)
14807{
Jouni Malinen026331c2010-02-15 12:53:10 +020014808 netlink_unregister_notifier(&nl80211_netlink_notifier);
Johannes Berg55682962007-09-20 13:09:35 -040014809 genl_unregister_family(&nl80211_fam);
14810}