blob: b5f755b3ac5d93a297f3ea21141ed798e67841ad [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 },
Luca Coelho85859892017-02-08 15:00:34 +0200401 [NL80211_ATTR_BANDS] = { .type = NLA_U32 },
Ayala Bekera442b762016-09-20 17:31:15 +0300402 [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
Jouni Malinen348bd452016-10-27 00:42:03 +0300403 [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
404 .len = FILS_MAX_KEK_LEN },
405 [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
Michael Braunce0ce132016-10-10 19:12:22 +0200406 [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
Vamsi Krishna2fa436b2016-12-02 23:59:08 +0200407 [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
vamsi krishnabf95ecd2017-01-13 01:12:20 +0200408 [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
409 [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
410 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
411 },
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +0200412 [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
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
Luca Coelho85859892017-02-08 15:00:34 +02001889 if (nla_put_u32(msg, NL80211_ATTR_BANDS,
1890 rdev->wiphy.nan_supported_bands))
1891 goto nla_put_failure;
1892
Johannes Berg3713b4e2013-02-14 16:19:38 +01001893 /* done */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001894 state->split_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001895 break;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001896 }
Johannes Berg3bb20552014-05-26 13:52:25 +02001897 finish:
Johannes Berg053c0952015-01-16 22:09:00 +01001898 genlmsg_end(msg, hdr);
1899 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04001900
1901 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001902 genlmsg_cancel(msg, hdr);
1903 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04001904}
1905
Johannes Berg86e8cf92013-06-19 10:57:22 +02001906static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
1907 struct netlink_callback *cb,
1908 struct nl80211_dump_wiphy_state *state)
1909{
Johannes Bergc90c39d2016-10-24 14:40:01 +02001910 struct nlattr **tb = genl_family_attrbuf(&nl80211_fam);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001911 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
1912 tb, nl80211_fam.maxattr, nl80211_policy);
1913 /* ignore parse errors for backward compatibility */
1914 if (ret)
1915 return 0;
1916
1917 state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
1918 if (tb[NL80211_ATTR_WIPHY])
1919 state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
1920 if (tb[NL80211_ATTR_WDEV])
1921 state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
1922 if (tb[NL80211_ATTR_IFINDEX]) {
1923 struct net_device *netdev;
1924 struct cfg80211_registered_device *rdev;
1925 int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
1926
Ying Xue7f2b8562014-01-15 10:23:45 +08001927 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001928 if (!netdev)
1929 return -ENODEV;
1930 if (netdev->ieee80211_ptr) {
Zhao, Gangf26cbf42014-04-21 12:53:03 +08001931 rdev = wiphy_to_rdev(
Johannes Berg86e8cf92013-06-19 10:57:22 +02001932 netdev->ieee80211_ptr->wiphy);
1933 state->filter_wiphy = rdev->wiphy_idx;
1934 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001935 }
1936
1937 return 0;
1938}
1939
Johannes Berg55682962007-09-20 13:09:35 -04001940static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
1941{
Johannes Berg645e77d2013-03-01 14:03:49 +01001942 int idx = 0, ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001943 struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001944 struct cfg80211_registered_device *rdev;
Johannes Berg3a5a4232013-06-19 10:09:57 +02001945
Johannes Berg5fe231e2013-05-08 21:45:15 +02001946 rtnl_lock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02001947 if (!state) {
1948 state = kzalloc(sizeof(*state), GFP_KERNEL);
John W. Linville57ed5cd2013-06-28 13:18:21 -04001949 if (!state) {
1950 rtnl_unlock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02001951 return -ENOMEM;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001952 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001953 state->filter_wiphy = -1;
1954 ret = nl80211_dump_wiphy_parse(skb, cb, state);
1955 if (ret) {
1956 kfree(state);
1957 rtnl_unlock();
1958 return ret;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001959 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001960 cb->args[0] = (long)state;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001961 }
1962
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001963 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
1964 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02001965 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001966 if (++idx <= state->start)
Johannes Berg55682962007-09-20 13:09:35 -04001967 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001968 if (state->filter_wiphy != -1 &&
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001969 state->filter_wiphy != rdev->wiphy_idx)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001970 continue;
1971 /* attempt to fit multiple wiphy data chunks into the skb */
1972 do {
Johannes Berg3bb20552014-05-26 13:52:25 +02001973 ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
1974 skb,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001975 NETLINK_CB(cb->skb).portid,
1976 cb->nlh->nlmsg_seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001977 NLM_F_MULTI, state);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001978 if (ret < 0) {
1979 /*
1980 * If sending the wiphy data didn't fit (ENOBUFS
1981 * or EMSGSIZE returned), this SKB is still
1982 * empty (so it's not too big because another
1983 * wiphy dataset is already in the skb) and
1984 * we've not tried to adjust the dump allocation
1985 * yet ... then adjust the alloc size to be
1986 * bigger, and return 1 but with the empty skb.
1987 * This results in an empty message being RX'ed
1988 * in userspace, but that is ignored.
1989 *
1990 * We can then retry with the larger buffer.
1991 */
1992 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
Pontus Fuchsf12cb282014-01-16 15:00:40 +01001993 !skb->len && !state->split &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001994 cb->min_dump_alloc < 4096) {
1995 cb->min_dump_alloc = 4096;
Pontus Fuchsf12cb282014-01-16 15:00:40 +01001996 state->split_start = 0;
David S. Millerd98cae64e2013-06-19 16:49:39 -07001997 rtnl_unlock();
Johannes Berg3713b4e2013-02-14 16:19:38 +01001998 return 1;
1999 }
2000 idx--;
2001 break;
Johannes Berg645e77d2013-03-01 14:03:49 +01002002 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002003 } while (state->split_start > 0);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002004 break;
Johannes Berg55682962007-09-20 13:09:35 -04002005 }
Johannes Berg5fe231e2013-05-08 21:45:15 +02002006 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002007
Johannes Berg86e8cf92013-06-19 10:57:22 +02002008 state->start = idx;
Johannes Berg55682962007-09-20 13:09:35 -04002009
2010 return skb->len;
2011}
2012
Johannes Berg86e8cf92013-06-19 10:57:22 +02002013static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
2014{
2015 kfree((void *)cb->args[0]);
2016 return 0;
2017}
2018
Johannes Berg55682962007-09-20 13:09:35 -04002019static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
2020{
2021 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002022 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg86e8cf92013-06-19 10:57:22 +02002023 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -04002024
Johannes Berg645e77d2013-03-01 14:03:49 +01002025 msg = nlmsg_new(4096, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002026 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002027 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002028
Johannes Berg3bb20552014-05-26 13:52:25 +02002029 if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
2030 info->snd_portid, info->snd_seq, 0,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002031 &state) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002032 nlmsg_free(msg);
2033 return -ENOBUFS;
2034 }
Johannes Berg55682962007-09-20 13:09:35 -04002035
Johannes Berg134e6372009-07-10 09:51:34 +00002036 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002037}
2038
Jouni Malinen31888482008-10-30 16:59:24 +02002039static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
2040 [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 },
2041 [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 },
2042 [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 },
2043 [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 },
2044 [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 },
2045};
2046
2047static int parse_txq_params(struct nlattr *tb[],
2048 struct ieee80211_txq_params *txq_params)
2049{
Johannes Berga3304b02012-03-28 11:04:24 +02002050 if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
Jouni Malinen31888482008-10-30 16:59:24 +02002051 !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
2052 !tb[NL80211_TXQ_ATTR_AIFS])
2053 return -EINVAL;
2054
Johannes Berga3304b02012-03-28 11:04:24 +02002055 txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
Jouni Malinen31888482008-10-30 16:59:24 +02002056 txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
2057 txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
2058 txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
2059 txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
2060
Johannes Berga3304b02012-03-28 11:04:24 +02002061 if (txq_params->ac >= NL80211_NUM_ACS)
2062 return -EINVAL;
2063
Jouni Malinen31888482008-10-30 16:59:24 +02002064 return 0;
2065}
2066
Johannes Bergf444de02010-05-05 15:25:02 +02002067static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
2068{
2069 /*
Johannes Bergcc1d2802012-05-16 23:50:20 +02002070 * You can only set the channel explicitly for WDS interfaces,
2071 * all others have their channel managed via their respective
2072 * "establish a connection" command (connect, join, ...)
2073 *
2074 * For AP/GO and mesh mode, the channel can be set with the
2075 * channel userspace API, but is only stored and passed to the
2076 * low-level driver when the AP starts or the mesh is joined.
2077 * This is for backward compatibility, userspace can also give
2078 * the channel in the start-ap or join-mesh commands instead.
Johannes Bergf444de02010-05-05 15:25:02 +02002079 *
2080 * Monitors are special as they are normally slaved to
Johannes Berge8c9bd52012-06-06 08:18:22 +02002081 * whatever else is going on, so they have their own special
2082 * operation to set the monitor channel if possible.
Johannes Bergf444de02010-05-05 15:25:02 +02002083 */
2084 return !wdev ||
2085 wdev->iftype == NL80211_IFTYPE_AP ||
Johannes Bergf444de02010-05-05 15:25:02 +02002086 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
Johannes Berg074ac8d2010-09-16 14:58:22 +02002087 wdev->iftype == NL80211_IFTYPE_MONITOR ||
2088 wdev->iftype == NL80211_IFTYPE_P2P_GO;
Johannes Bergf444de02010-05-05 15:25:02 +02002089}
2090
Johannes Berg683b6d32012-11-08 21:25:48 +01002091static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
2092 struct genl_info *info,
2093 struct cfg80211_chan_def *chandef)
2094{
Mahesh Paliveladbeca2e2012-11-29 14:11:07 +05302095 u32 control_freq;
Johannes Berg683b6d32012-11-08 21:25:48 +01002096
2097 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
2098 return -EINVAL;
2099
2100 control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
2101
2102 chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002103 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
2104 chandef->center_freq1 = control_freq;
2105 chandef->center_freq2 = 0;
Johannes Berg683b6d32012-11-08 21:25:48 +01002106
2107 /* Primary channel not allowed */
2108 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
2109 return -EINVAL;
2110
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002111 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
2112 enum nl80211_channel_type chantype;
Johannes Berg683b6d32012-11-08 21:25:48 +01002113
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002114 chantype = nla_get_u32(
2115 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
2116
2117 switch (chantype) {
2118 case NL80211_CHAN_NO_HT:
2119 case NL80211_CHAN_HT20:
2120 case NL80211_CHAN_HT40PLUS:
2121 case NL80211_CHAN_HT40MINUS:
2122 cfg80211_chandef_create(chandef, chandef->chan,
2123 chantype);
2124 break;
2125 default:
Johannes Berg683b6d32012-11-08 21:25:48 +01002126 return -EINVAL;
Johannes Berg683b6d32012-11-08 21:25:48 +01002127 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002128 } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
2129 chandef->width =
2130 nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
2131 if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
2132 chandef->center_freq1 =
2133 nla_get_u32(
2134 info->attrs[NL80211_ATTR_CENTER_FREQ1]);
2135 if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
2136 chandef->center_freq2 =
2137 nla_get_u32(
2138 info->attrs[NL80211_ATTR_CENTER_FREQ2]);
2139 }
2140
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002141 if (!cfg80211_chandef_valid(chandef))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002142 return -EINVAL;
2143
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002144 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
2145 IEEE80211_CHAN_DISABLED))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002146 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002147
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002148 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
2149 chandef->width == NL80211_CHAN_WIDTH_10) &&
2150 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
2151 return -EINVAL;
2152
Johannes Berg683b6d32012-11-08 21:25:48 +01002153 return 0;
2154}
2155
Johannes Bergf444de02010-05-05 15:25:02 +02002156static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
Jouni Malinene16821b2014-04-28 11:22:08 +03002157 struct net_device *dev,
Johannes Bergf444de02010-05-05 15:25:02 +02002158 struct genl_info *info)
2159{
Johannes Berg683b6d32012-11-08 21:25:48 +01002160 struct cfg80211_chan_def chandef;
Johannes Bergf444de02010-05-05 15:25:02 +02002161 int result;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002162 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
Jouni Malinene16821b2014-04-28 11:22:08 +03002163 struct wireless_dev *wdev = NULL;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002164
Jouni Malinene16821b2014-04-28 11:22:08 +03002165 if (dev)
2166 wdev = dev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002167 if (!nl80211_can_set_dev_channel(wdev))
2168 return -EOPNOTSUPP;
Jouni Malinene16821b2014-04-28 11:22:08 +03002169 if (wdev)
2170 iftype = wdev->iftype;
Johannes Bergf444de02010-05-05 15:25:02 +02002171
Johannes Berg683b6d32012-11-08 21:25:48 +01002172 result = nl80211_parse_chandef(rdev, info, &chandef);
2173 if (result)
2174 return result;
Johannes Bergf444de02010-05-05 15:25:02 +02002175
Johannes Berge8c9bd52012-06-06 08:18:22 +02002176 switch (iftype) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002177 case NL80211_IFTYPE_AP:
2178 case NL80211_IFTYPE_P2P_GO:
Arik Nemtsov923b3522015-07-08 15:41:44 +03002179 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
2180 iftype)) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002181 result = -EINVAL;
2182 break;
2183 }
Jouni Malinene16821b2014-04-28 11:22:08 +03002184 if (wdev->beacon_interval) {
2185 if (!dev || !rdev->ops->set_ap_chanwidth ||
2186 !(rdev->wiphy.features &
2187 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
2188 result = -EBUSY;
2189 break;
2190 }
2191
2192 /* Only allow dynamic channel width changes */
2193 if (chandef.chan != wdev->preset_chandef.chan) {
2194 result = -EBUSY;
2195 break;
2196 }
2197 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
2198 if (result)
2199 break;
2200 }
Johannes Berg683b6d32012-11-08 21:25:48 +01002201 wdev->preset_chandef = chandef;
Johannes Bergaa430da2012-05-16 23:50:18 +02002202 result = 0;
2203 break;
Johannes Bergcc1d2802012-05-16 23:50:20 +02002204 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg683b6d32012-11-08 21:25:48 +01002205 result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
Johannes Bergcc1d2802012-05-16 23:50:20 +02002206 break;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002207 case NL80211_IFTYPE_MONITOR:
Johannes Berg683b6d32012-11-08 21:25:48 +01002208 result = cfg80211_set_monitor_channel(rdev, &chandef);
Johannes Berge8c9bd52012-06-06 08:18:22 +02002209 break;
Johannes Bergaa430da2012-05-16 23:50:18 +02002210 default:
Johannes Berge8c9bd52012-06-06 08:18:22 +02002211 result = -EINVAL;
Johannes Bergf444de02010-05-05 15:25:02 +02002212 }
Johannes Bergf444de02010-05-05 15:25:02 +02002213
2214 return result;
2215}
2216
2217static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
2218{
Johannes Berg4c476992010-10-04 21:36:35 +02002219 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2220 struct net_device *netdev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02002221
Jouni Malinene16821b2014-04-28 11:22:08 +03002222 return __nl80211_set_channel(rdev, netdev, info);
Johannes Bergf444de02010-05-05 15:25:02 +02002223}
2224
Bill Jordane8347eb2010-10-01 13:54:28 -04002225static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
2226{
Johannes Berg43b19952010-10-07 13:10:30 +02002227 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2228 struct net_device *dev = info->user_ptr[1];
2229 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg388ac772010-10-07 13:11:09 +02002230 const u8 *bssid;
Bill Jordane8347eb2010-10-01 13:54:28 -04002231
2232 if (!info->attrs[NL80211_ATTR_MAC])
2233 return -EINVAL;
2234
Johannes Berg43b19952010-10-07 13:10:30 +02002235 if (netif_running(dev))
2236 return -EBUSY;
Bill Jordane8347eb2010-10-01 13:54:28 -04002237
Johannes Berg43b19952010-10-07 13:10:30 +02002238 if (!rdev->ops->set_wds_peer)
2239 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002240
Johannes Berg43b19952010-10-07 13:10:30 +02002241 if (wdev->iftype != NL80211_IFTYPE_WDS)
2242 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002243
2244 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Hila Gonene35e4d22012-06-27 17:19:42 +03002245 return rdev_set_wds_peer(rdev, dev, bssid);
Bill Jordane8347eb2010-10-01 13:54:28 -04002246}
2247
Johannes Berg55682962007-09-20 13:09:35 -04002248static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
2249{
2250 struct cfg80211_registered_device *rdev;
Johannes Bergf444de02010-05-05 15:25:02 +02002251 struct net_device *netdev = NULL;
2252 struct wireless_dev *wdev;
Bill Jordana1e567c2010-09-10 11:22:32 -04002253 int result = 0, rem_txq_params = 0;
Jouni Malinen31888482008-10-30 16:59:24 +02002254 struct nlattr *nl_txq_params;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002255 u32 changed;
2256 u8 retry_short = 0, retry_long = 0;
2257 u32 frag_threshold = 0, rts_threshold = 0;
Lukáš Turek81077e82009-12-21 22:50:47 +01002258 u8 coverage_class = 0;
Johannes Berg55682962007-09-20 13:09:35 -04002259
Johannes Berg5fe231e2013-05-08 21:45:15 +02002260 ASSERT_RTNL();
2261
Johannes Bergf444de02010-05-05 15:25:02 +02002262 /*
2263 * Try to find the wiphy and netdev. Normally this
2264 * function shouldn't need the netdev, but this is
2265 * done for backward compatibility -- previously
2266 * setting the channel was done per wiphy, but now
2267 * it is per netdev. Previous userland like hostapd
2268 * also passed a netdev to set_wiphy, so that it is
2269 * possible to let that go to the right netdev!
2270 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002271
Johannes Bergf444de02010-05-05 15:25:02 +02002272 if (info->attrs[NL80211_ATTR_IFINDEX]) {
2273 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
2274
Ying Xue7f2b8562014-01-15 10:23:45 +08002275 netdev = __dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002276 if (netdev && netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002277 rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002278 else
Johannes Bergf444de02010-05-05 15:25:02 +02002279 netdev = NULL;
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002280 }
2281
Johannes Bergf444de02010-05-05 15:25:02 +02002282 if (!netdev) {
Johannes Berg878d9ec2012-06-15 14:18:32 +02002283 rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
2284 info->attrs);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002285 if (IS_ERR(rdev))
Johannes Berg4c476992010-10-04 21:36:35 +02002286 return PTR_ERR(rdev);
Johannes Bergf444de02010-05-05 15:25:02 +02002287 wdev = NULL;
2288 netdev = NULL;
2289 result = 0;
Johannes Berg71fe96b2012-10-24 10:04:58 +02002290 } else
Johannes Bergf444de02010-05-05 15:25:02 +02002291 wdev = netdev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002292
2293 /*
2294 * end workaround code, by now the rdev is available
2295 * and locked, and wdev may or may not be NULL.
2296 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002297
2298 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
Jouni Malinen31888482008-10-30 16:59:24 +02002299 result = cfg80211_dev_rename(
2300 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002301
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002302 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002303 return result;
Johannes Berg55682962007-09-20 13:09:35 -04002304
Jouni Malinen31888482008-10-30 16:59:24 +02002305 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
2306 struct ieee80211_txq_params txq_params;
2307 struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
2308
Ying Xue7f2b8562014-01-15 10:23:45 +08002309 if (!rdev->ops->set_txq_params)
2310 return -EOPNOTSUPP;
Jouni Malinen31888482008-10-30 16:59:24 +02002311
Ying Xue7f2b8562014-01-15 10:23:45 +08002312 if (!netdev)
2313 return -EINVAL;
Eliad Pellerf70f01c2011-09-25 20:06:53 +03002314
Johannes Berg133a3ff2011-11-03 14:50:13 +01002315 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002316 netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2317 return -EINVAL;
Johannes Berg133a3ff2011-11-03 14:50:13 +01002318
Ying Xue7f2b8562014-01-15 10:23:45 +08002319 if (!netif_running(netdev))
2320 return -ENETDOWN;
Johannes Berg2b5f8b02012-04-02 10:51:55 +02002321
Jouni Malinen31888482008-10-30 16:59:24 +02002322 nla_for_each_nested(nl_txq_params,
2323 info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
2324 rem_txq_params) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02002325 result = nla_parse_nested(tb, NL80211_TXQ_ATTR_MAX,
2326 nl_txq_params,
2327 txq_params_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01002328 if (result)
2329 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002330 result = parse_txq_params(tb, &txq_params);
2331 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002332 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002333
Hila Gonene35e4d22012-06-27 17:19:42 +03002334 result = rdev_set_txq_params(rdev, netdev,
2335 &txq_params);
Jouni Malinen31888482008-10-30 16:59:24 +02002336 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002337 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002338 }
2339 }
2340
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002341 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinene16821b2014-04-28 11:22:08 +03002342 result = __nl80211_set_channel(
2343 rdev,
2344 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
2345 info);
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002346 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002347 return result;
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002348 }
2349
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002350 if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
Johannes Bergc8442112012-10-24 10:17:18 +02002351 struct wireless_dev *txp_wdev = wdev;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002352 enum nl80211_tx_power_setting type;
2353 int idx, mbm = 0;
2354
Johannes Bergc8442112012-10-24 10:17:18 +02002355 if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
2356 txp_wdev = NULL;
2357
Ying Xue7f2b8562014-01-15 10:23:45 +08002358 if (!rdev->ops->set_tx_power)
2359 return -EOPNOTSUPP;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002360
2361 idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
2362 type = nla_get_u32(info->attrs[idx]);
2363
2364 if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002365 (type != NL80211_TX_POWER_AUTOMATIC))
2366 return -EINVAL;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002367
2368 if (type != NL80211_TX_POWER_AUTOMATIC) {
2369 idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
2370 mbm = nla_get_u32(info->attrs[idx]);
2371 }
2372
Johannes Bergc8442112012-10-24 10:17:18 +02002373 result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002374 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002375 return result;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002376 }
2377
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002378 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
2379 info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
2380 u32 tx_ant, rx_ant;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07002381
Bruno Randolf7f531e02010-12-16 11:30:22 +09002382 if ((!rdev->wiphy.available_antennas_tx &&
2383 !rdev->wiphy.available_antennas_rx) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002384 !rdev->ops->set_antenna)
2385 return -EOPNOTSUPP;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002386
2387 tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
2388 rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
2389
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002390 /* reject antenna configurations which don't match the
Bruno Randolf7f531e02010-12-16 11:30:22 +09002391 * available antenna masks, except for the "all" mask */
2392 if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002393 (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
2394 return -EINVAL;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002395
Bruno Randolf7f531e02010-12-16 11:30:22 +09002396 tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
2397 rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002398
Hila Gonene35e4d22012-06-27 17:19:42 +03002399 result = rdev_set_antenna(rdev, tx_ant, rx_ant);
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002400 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002401 return result;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002402 }
2403
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002404 changed = 0;
2405
2406 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
2407 retry_short = nla_get_u8(
2408 info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002409 if (retry_short == 0)
2410 return -EINVAL;
2411
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002412 changed |= WIPHY_PARAM_RETRY_SHORT;
2413 }
2414
2415 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
2416 retry_long = nla_get_u8(
2417 info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002418 if (retry_long == 0)
2419 return -EINVAL;
2420
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002421 changed |= WIPHY_PARAM_RETRY_LONG;
2422 }
2423
2424 if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
2425 frag_threshold = nla_get_u32(
2426 info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002427 if (frag_threshold < 256)
2428 return -EINVAL;
2429
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002430 if (frag_threshold != (u32) -1) {
2431 /*
2432 * Fragments (apart from the last one) are required to
2433 * have even length. Make the fragmentation code
2434 * simpler by stripping LSB should someone try to use
2435 * odd threshold value.
2436 */
2437 frag_threshold &= ~0x1;
2438 }
2439 changed |= WIPHY_PARAM_FRAG_THRESHOLD;
2440 }
2441
2442 if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
2443 rts_threshold = nla_get_u32(
2444 info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
2445 changed |= WIPHY_PARAM_RTS_THRESHOLD;
2446 }
2447
Lukáš Turek81077e82009-12-21 22:50:47 +01002448 if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002449 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
2450 return -EINVAL;
2451
Lukáš Turek81077e82009-12-21 22:50:47 +01002452 coverage_class = nla_get_u8(
2453 info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
2454 changed |= WIPHY_PARAM_COVERAGE_CLASS;
2455 }
2456
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002457 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
2458 if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
2459 return -EOPNOTSUPP;
2460
2461 changed |= WIPHY_PARAM_DYN_ACK;
2462 }
2463
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002464 if (changed) {
2465 u8 old_retry_short, old_retry_long;
2466 u32 old_frag_threshold, old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002467 u8 old_coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002468
Ying Xue7f2b8562014-01-15 10:23:45 +08002469 if (!rdev->ops->set_wiphy_params)
2470 return -EOPNOTSUPP;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002471
2472 old_retry_short = rdev->wiphy.retry_short;
2473 old_retry_long = rdev->wiphy.retry_long;
2474 old_frag_threshold = rdev->wiphy.frag_threshold;
2475 old_rts_threshold = rdev->wiphy.rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002476 old_coverage_class = rdev->wiphy.coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002477
2478 if (changed & WIPHY_PARAM_RETRY_SHORT)
2479 rdev->wiphy.retry_short = retry_short;
2480 if (changed & WIPHY_PARAM_RETRY_LONG)
2481 rdev->wiphy.retry_long = retry_long;
2482 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
2483 rdev->wiphy.frag_threshold = frag_threshold;
2484 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
2485 rdev->wiphy.rts_threshold = rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002486 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
2487 rdev->wiphy.coverage_class = coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002488
Hila Gonene35e4d22012-06-27 17:19:42 +03002489 result = rdev_set_wiphy_params(rdev, changed);
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002490 if (result) {
2491 rdev->wiphy.retry_short = old_retry_short;
2492 rdev->wiphy.retry_long = old_retry_long;
2493 rdev->wiphy.frag_threshold = old_frag_threshold;
2494 rdev->wiphy.rts_threshold = old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002495 rdev->wiphy.coverage_class = old_coverage_class;
Michal Kazior9189ee32015-08-03 10:55:24 +02002496 return result;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002497 }
2498 }
Ying Xue7f2b8562014-01-15 10:23:45 +08002499 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002500}
2501
Johannes Berg71bbc992012-06-15 15:30:18 +02002502static inline u64 wdev_id(struct wireless_dev *wdev)
2503{
2504 return (u64)wdev->identifier |
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002505 ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
Johannes Berg71bbc992012-06-15 15:30:18 +02002506}
Johannes Berg55682962007-09-20 13:09:35 -04002507
Johannes Berg683b6d32012-11-08 21:25:48 +01002508static int nl80211_send_chandef(struct sk_buff *msg,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01002509 const struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01002510{
Johannes Berg601555c2014-11-27 17:26:56 +01002511 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
2512 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002513
Johannes Berg683b6d32012-11-08 21:25:48 +01002514 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
2515 chandef->chan->center_freq))
2516 return -ENOBUFS;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002517 switch (chandef->width) {
2518 case NL80211_CHAN_WIDTH_20_NOHT:
2519 case NL80211_CHAN_WIDTH_20:
2520 case NL80211_CHAN_WIDTH_40:
2521 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
2522 cfg80211_get_chandef_type(chandef)))
2523 return -ENOBUFS;
2524 break;
2525 default:
2526 break;
2527 }
2528 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
2529 return -ENOBUFS;
2530 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
2531 return -ENOBUFS;
2532 if (chandef->center_freq2 &&
2533 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
Johannes Berg683b6d32012-11-08 21:25:48 +01002534 return -ENOBUFS;
2535 return 0;
2536}
2537
Eric W. Biederman15e47302012-09-07 20:12:54 +00002538static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
Johannes Bergd7264052009-04-19 16:23:20 +02002539 struct cfg80211_registered_device *rdev,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002540 struct wireless_dev *wdev, bool removal)
Johannes Berg55682962007-09-20 13:09:35 -04002541{
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002542 struct net_device *dev = wdev->netdev;
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002543 u8 cmd = NL80211_CMD_NEW_INTERFACE;
Johannes Berg55682962007-09-20 13:09:35 -04002544 void *hdr;
2545
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002546 if (removal)
2547 cmd = NL80211_CMD_DEL_INTERFACE;
2548
2549 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04002550 if (!hdr)
2551 return -1;
2552
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002553 if (dev &&
2554 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002555 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002556 goto nla_put_failure;
2557
2558 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
2559 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02002560 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
2561 NL80211_ATTR_PAD) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002562 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04002563 nla_put_u32(msg, NL80211_ATTR_GENERATION,
2564 rdev->devlist_generation ^
2565 (cfg80211_rdev_list_generation << 2)))
2566 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002567
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002568 if (rdev->ops->get_channel) {
Johannes Berg683b6d32012-11-08 21:25:48 +01002569 int ret;
2570 struct cfg80211_chan_def chandef;
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002571
Johannes Berg683b6d32012-11-08 21:25:48 +01002572 ret = rdev_get_channel(rdev, wdev, &chandef);
2573 if (ret == 0) {
2574 if (nl80211_send_chandef(msg, &chandef))
2575 goto nla_put_failure;
2576 }
Pontus Fuchsd91df0e2012-04-03 16:39:58 +02002577 }
2578
Rafał Miłeckid55d0d52015-08-31 22:59:38 +02002579 if (rdev->ops->get_tx_power) {
2580 int dbm, ret;
2581
2582 ret = rdev_get_tx_power(rdev, wdev, &dbm);
2583 if (ret == 0 &&
2584 nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
2585 DBM_TO_MBM(dbm)))
2586 goto nla_put_failure;
2587 }
2588
Antonio Quartullib84e7a02012-11-07 12:52:20 +01002589 if (wdev->ssid_len) {
2590 if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
2591 goto nla_put_failure;
2592 }
2593
Johannes Berg053c0952015-01-16 22:09:00 +01002594 genlmsg_end(msg, hdr);
2595 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002596
2597 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002598 genlmsg_cancel(msg, hdr);
2599 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04002600}
2601
2602static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
2603{
2604 int wp_idx = 0;
2605 int if_idx = 0;
2606 int wp_start = cb->args[0];
2607 int if_start = cb->args[1];
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002608 int filter_wiphy = -1;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002609 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -04002610 struct wireless_dev *wdev;
2611
Johannes Berg5fe231e2013-05-08 21:45:15 +02002612 rtnl_lock();
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002613 if (!cb->args[2]) {
2614 struct nl80211_dump_wiphy_state state = {
2615 .filter_wiphy = -1,
2616 };
2617 int ret;
2618
2619 ret = nl80211_dump_wiphy_parse(skb, cb, &state);
2620 if (ret)
2621 return ret;
2622
2623 filter_wiphy = state.filter_wiphy;
2624
2625 /*
2626 * if filtering, set cb->args[2] to +1 since 0 is the default
2627 * value needed to determine that parsing is necessary.
2628 */
2629 if (filter_wiphy >= 0)
2630 cb->args[2] = filter_wiphy + 1;
2631 else
2632 cb->args[2] = -1;
2633 } else if (cb->args[2] > 0) {
2634 filter_wiphy = cb->args[2] - 1;
2635 }
2636
Johannes Bergf5ea9122009-08-07 16:17:38 +02002637 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2638 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002639 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002640 if (wp_idx < wp_start) {
2641 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002642 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002643 }
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002644
2645 if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
2646 continue;
2647
Johannes Berg55682962007-09-20 13:09:35 -04002648 if_idx = 0;
2649
Johannes Berg53873f12016-05-03 16:52:04 +03002650 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002651 if (if_idx < if_start) {
2652 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002653 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002654 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002655 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
Johannes Berg55682962007-09-20 13:09:35 -04002656 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002657 rdev, wdev, false) < 0) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002658 goto out;
2659 }
2660 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002661 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002662
2663 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002664 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002665 out:
Johannes Berg5fe231e2013-05-08 21:45:15 +02002666 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002667
2668 cb->args[0] = wp_idx;
2669 cb->args[1] = if_idx;
2670
2671 return skb->len;
2672}
2673
2674static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
2675{
2676 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002677 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002678 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002679
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07002680 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002681 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002682 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002683
Eric W. Biederman15e47302012-09-07 20:12:54 +00002684 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002685 rdev, wdev, false) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002686 nlmsg_free(msg);
2687 return -ENOBUFS;
2688 }
Johannes Berg55682962007-09-20 13:09:35 -04002689
Johannes Berg134e6372009-07-10 09:51:34 +00002690 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002691}
2692
Michael Wu66f7ac52008-01-31 19:48:22 +01002693static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
2694 [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
2695 [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
2696 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
2697 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
2698 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002699 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
Michael Wu66f7ac52008-01-31 19:48:22 +01002700};
2701
2702static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
2703{
2704 struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
2705 int flag;
2706
2707 *mntrflags = 0;
2708
2709 if (!nla)
2710 return -EINVAL;
2711
2712 if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
2713 nla, mntr_flags_policy))
2714 return -EINVAL;
2715
2716 for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
2717 if (flags[flag])
2718 *mntrflags |= (1<<flag);
2719
2720 return 0;
2721}
2722
Johannes Berg9bc383d2009-11-19 11:55:19 +01002723static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002724 struct net_device *netdev, u8 use_4addr,
2725 enum nl80211_iftype iftype)
Johannes Berg9bc383d2009-11-19 11:55:19 +01002726{
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002727 if (!use_4addr) {
Jiri Pirkof350a0a82010-06-15 06:50:45 +00002728 if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002729 return -EBUSY;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002730 return 0;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002731 }
Johannes Berg9bc383d2009-11-19 11:55:19 +01002732
2733 switch (iftype) {
2734 case NL80211_IFTYPE_AP_VLAN:
2735 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
2736 return 0;
2737 break;
2738 case NL80211_IFTYPE_STATION:
2739 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
2740 return 0;
2741 break;
2742 default:
2743 break;
2744 }
2745
2746 return -EOPNOTSUPP;
2747}
2748
Johannes Berg55682962007-09-20 13:09:35 -04002749static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
2750{
Johannes Berg4c476992010-10-04 21:36:35 +02002751 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002752 struct vif_params params;
Johannes Berge36d56b2009-06-09 21:04:43 +02002753 int err;
Johannes Berg04a773a2009-04-19 21:24:32 +02002754 enum nl80211_iftype otype, ntype;
Johannes Berg4c476992010-10-04 21:36:35 +02002755 struct net_device *dev = info->user_ptr[1];
Johannes Berg92ffe052008-09-16 20:39:36 +02002756 u32 _flags, *flags = NULL;
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002757 bool change = false;
Johannes Berg55682962007-09-20 13:09:35 -04002758
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002759 memset(&params, 0, sizeof(params));
2760
Johannes Berg04a773a2009-04-19 21:24:32 +02002761 otype = ntype = dev->ieee80211_ptr->iftype;
Johannes Berg55682962007-09-20 13:09:35 -04002762
Johannes Berg723b0382008-09-16 20:22:09 +02002763 if (info->attrs[NL80211_ATTR_IFTYPE]) {
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002764 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg04a773a2009-04-19 21:24:32 +02002765 if (otype != ntype)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002766 change = true;
Johannes Berg4c476992010-10-04 21:36:35 +02002767 if (ntype > NL80211_IFTYPE_MAX)
2768 return -EINVAL;
Johannes Berg723b0382008-09-16 20:22:09 +02002769 }
2770
Johannes Berg92ffe052008-09-16 20:39:36 +02002771 if (info->attrs[NL80211_ATTR_MESH_ID]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01002772 struct wireless_dev *wdev = dev->ieee80211_ptr;
2773
Johannes Berg4c476992010-10-04 21:36:35 +02002774 if (ntype != NL80211_IFTYPE_MESH_POINT)
2775 return -EINVAL;
Johannes Berg29cbe682010-12-03 09:20:44 +01002776 if (netif_running(dev))
2777 return -EBUSY;
2778
2779 wdev_lock(wdev);
2780 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2781 IEEE80211_MAX_MESH_ID_LEN);
2782 wdev->mesh_id_up_len =
2783 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2784 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2785 wdev->mesh_id_up_len);
2786 wdev_unlock(wdev);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002787 }
2788
Felix Fietkau8b787642009-11-10 18:53:10 +01002789 if (info->attrs[NL80211_ATTR_4ADDR]) {
2790 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
2791 change = true;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002792 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002793 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002794 return err;
Felix Fietkau8b787642009-11-10 18:53:10 +01002795 } else {
2796 params.use_4addr = -1;
2797 }
2798
Johannes Berg92ffe052008-09-16 20:39:36 +02002799 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
Johannes Berg4c476992010-10-04 21:36:35 +02002800 if (ntype != NL80211_IFTYPE_MONITOR)
2801 return -EINVAL;
Johannes Berg92ffe052008-09-16 20:39:36 +02002802 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
2803 &_flags);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002804 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002805 return err;
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002806
2807 flags = &_flags;
2808 change = true;
Johannes Berg92ffe052008-09-16 20:39:36 +02002809 }
Johannes Berg3b858752009-03-12 09:55:09 +01002810
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +03002811 if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
2812 const u8 *mumimo_groups;
2813 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2814
2815 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2816 return -EOPNOTSUPP;
2817
2818 mumimo_groups =
2819 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
2820
2821 /* bits 0 and 63 are reserved and must be zero */
2822 if ((mumimo_groups[0] & BIT(7)) ||
2823 (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
2824 return -EINVAL;
2825
2826 memcpy(params.vht_mumimo_groups, mumimo_groups,
2827 VHT_MUMIMO_GROUPS_DATA_LEN);
2828 change = true;
2829 }
2830
2831 if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
2832 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2833
2834 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2835 return -EOPNOTSUPP;
2836
2837 nla_memcpy(params.macaddr,
2838 info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR],
2839 ETH_ALEN);
2840 change = true;
2841 }
2842
Luciano Coelho18003292013-08-29 13:26:57 +03002843 if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002844 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2845 return -EOPNOTSUPP;
2846
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002847 if (change)
Johannes Berg3d54d252009-08-21 14:51:05 +02002848 err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002849 else
2850 err = 0;
Johannes Berg60719ff2008-09-16 14:55:09 +02002851
Johannes Berg9bc383d2009-11-19 11:55:19 +01002852 if (!err && params.use_4addr != -1)
2853 dev->ieee80211_ptr->use_4addr = params.use_4addr;
2854
Johannes Berg55682962007-09-20 13:09:35 -04002855 return err;
2856}
2857
2858static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2859{
Johannes Berg4c476992010-10-04 21:36:35 +02002860 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002861 struct vif_params params;
Johannes Berg84efbb82012-06-16 00:00:26 +02002862 struct wireless_dev *wdev;
Denis Kenzior896ff062016-08-03 16:58:33 -05002863 struct sk_buff *msg;
Johannes Berg55682962007-09-20 13:09:35 -04002864 int err;
2865 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
Michael Wu66f7ac52008-01-31 19:48:22 +01002866 u32 flags;
Johannes Berg55682962007-09-20 13:09:35 -04002867
Johannes Berg78f22b62014-03-24 17:57:27 +01002868 /* to avoid failing a new interface creation due to pending removal */
2869 cfg80211_destroy_ifaces(rdev);
2870
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002871 memset(&params, 0, sizeof(params));
2872
Johannes Berg55682962007-09-20 13:09:35 -04002873 if (!info->attrs[NL80211_ATTR_IFNAME])
2874 return -EINVAL;
2875
2876 if (info->attrs[NL80211_ATTR_IFTYPE]) {
2877 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
2878 if (type > NL80211_IFTYPE_MAX)
2879 return -EINVAL;
2880 }
2881
Johannes Berg79c97e92009-07-07 03:56:12 +02002882 if (!rdev->ops->add_virtual_intf ||
Johannes Berg4c476992010-10-04 21:36:35 +02002883 !(rdev->wiphy.interface_modes & (1 << type)))
2884 return -EOPNOTSUPP;
Johannes Berg55682962007-09-20 13:09:35 -04002885
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002886 if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
Ben Greeare8f479b2014-10-22 12:23:05 -07002887 rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
2888 info->attrs[NL80211_ATTR_MAC]) {
Arend van Spriel1c18f142013-01-08 10:17:27 +01002889 nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
2890 ETH_ALEN);
2891 if (!is_valid_ether_addr(params.macaddr))
2892 return -EADDRNOTAVAIL;
2893 }
2894
Johannes Berg9bc383d2009-11-19 11:55:19 +01002895 if (info->attrs[NL80211_ATTR_4ADDR]) {
Felix Fietkau8b787642009-11-10 18:53:10 +01002896 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002897 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002898 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002899 return err;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002900 }
Felix Fietkau8b787642009-11-10 18:53:10 +01002901
Michael Wu66f7ac52008-01-31 19:48:22 +01002902 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
2903 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
2904 &flags);
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002905
Luciano Coelho18003292013-08-29 13:26:57 +03002906 if (!err && (flags & MONITOR_FLAG_ACTIVE) &&
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002907 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2908 return -EOPNOTSUPP;
2909
Johannes Berga18c7192015-02-24 10:56:42 +01002910 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2911 if (!msg)
2912 return -ENOMEM;
2913
Hila Gonene35e4d22012-06-27 17:19:42 +03002914 wdev = rdev_add_virtual_intf(rdev,
2915 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
Tom Gundersen6bab2e192015-03-18 11:13:39 +01002916 NET_NAME_USER, type, err ? NULL : &flags,
2917 &params);
Rafał Miłeckid687cbb2014-11-14 18:43:28 +01002918 if (WARN_ON(!wdev)) {
2919 nlmsg_free(msg);
2920 return -EPROTO;
2921 } else if (IS_ERR(wdev)) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002922 nlmsg_free(msg);
Johannes Berg84efbb82012-06-16 00:00:26 +02002923 return PTR_ERR(wdev);
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002924 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002925
Jukka Rissanen18e5ca62014-11-13 17:25:14 +02002926 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
Johannes Berg78f22b62014-03-24 17:57:27 +01002927 wdev->owner_nlportid = info->snd_portid;
2928
Johannes Berg98104fde2012-06-16 00:19:54 +02002929 switch (type) {
2930 case NL80211_IFTYPE_MESH_POINT:
2931 if (!info->attrs[NL80211_ATTR_MESH_ID])
2932 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002933 wdev_lock(wdev);
2934 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2935 IEEE80211_MAX_MESH_ID_LEN);
2936 wdev->mesh_id_up_len =
2937 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2938 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2939 wdev->mesh_id_up_len);
2940 wdev_unlock(wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02002941 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002942 case NL80211_IFTYPE_NAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02002943 case NL80211_IFTYPE_P2P_DEVICE:
2944 /*
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002945 * P2P Device and NAN do not have a netdev, so don't go
Johannes Berg98104fde2012-06-16 00:19:54 +02002946 * through the netdev notifier and must be added here
2947 */
2948 mutex_init(&wdev->mtx);
2949 INIT_LIST_HEAD(&wdev->event_list);
2950 spin_lock_init(&wdev->event_lock);
2951 INIT_LIST_HEAD(&wdev->mgmt_registrations);
2952 spin_lock_init(&wdev->mgmt_registrations_lock);
2953
Johannes Berg98104fde2012-06-16 00:19:54 +02002954 wdev->identifier = ++rdev->wdev_id;
Johannes Berg53873f12016-05-03 16:52:04 +03002955 list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
Johannes Berg98104fde2012-06-16 00:19:54 +02002956 rdev->devlist_generation++;
Johannes Berg98104fde2012-06-16 00:19:54 +02002957 break;
2958 default:
2959 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002960 }
2961
Eric W. Biederman15e47302012-09-07 20:12:54 +00002962 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002963 rdev, wdev, false) < 0) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002964 nlmsg_free(msg);
2965 return -ENOBUFS;
2966 }
2967
Denis Kenzior896ff062016-08-03 16:58:33 -05002968 /*
2969 * For wdevs which have no associated netdev object (e.g. of type
2970 * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
2971 * For all other types, the event will be generated from the
2972 * netdev notifier
2973 */
2974 if (!wdev->netdev)
2975 nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002976
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002977 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002978}
2979
2980static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
2981{
Johannes Berg4c476992010-10-04 21:36:35 +02002982 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg84efbb82012-06-16 00:00:26 +02002983 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002984
Johannes Berg4c476992010-10-04 21:36:35 +02002985 if (!rdev->ops->del_virtual_intf)
2986 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01002987
Johannes Berg84efbb82012-06-16 00:00:26 +02002988 /*
2989 * If we remove a wireless device without a netdev then clear
2990 * user_ptr[1] so that nl80211_post_doit won't dereference it
2991 * to check if it needs to do dev_put(). Otherwise it crashes
2992 * since the wdev has been freed, unlike with a netdev where
2993 * we need the dev_put() for the netdev to really be freed.
2994 */
2995 if (!wdev->netdev)
2996 info->user_ptr[1] = NULL;
2997
Denis Kenzior7f8ed012016-08-03 16:58:35 -05002998 return rdev_del_virtual_intf(rdev, wdev);
Johannes Berg55682962007-09-20 13:09:35 -04002999}
3000
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003001static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
3002{
3003 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3004 struct net_device *dev = info->user_ptr[1];
3005 u16 noack_map;
3006
3007 if (!info->attrs[NL80211_ATTR_NOACK_MAP])
3008 return -EINVAL;
3009
3010 if (!rdev->ops->set_noack_map)
3011 return -EOPNOTSUPP;
3012
3013 noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
3014
Hila Gonene35e4d22012-06-27 17:19:42 +03003015 return rdev_set_noack_map(rdev, dev, noack_map);
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003016}
3017
Johannes Berg41ade002007-12-19 02:03:29 +01003018struct get_key_cookie {
3019 struct sk_buff *msg;
3020 int error;
Johannes Bergb9454e82009-07-08 13:29:08 +02003021 int idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003022};
3023
3024static void get_key_callback(void *c, struct key_params *params)
3025{
Johannes Bergb9454e82009-07-08 13:29:08 +02003026 struct nlattr *key;
Johannes Berg41ade002007-12-19 02:03:29 +01003027 struct get_key_cookie *cookie = c;
3028
David S. Miller9360ffd2012-03-29 04:41:26 -04003029 if ((params->key &&
3030 nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
3031 params->key_len, params->key)) ||
3032 (params->seq &&
3033 nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
3034 params->seq_len, params->seq)) ||
3035 (params->cipher &&
3036 nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
3037 params->cipher)))
3038 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003039
Johannes Bergb9454e82009-07-08 13:29:08 +02003040 key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
3041 if (!key)
3042 goto nla_put_failure;
3043
David S. Miller9360ffd2012-03-29 04:41:26 -04003044 if ((params->key &&
3045 nla_put(cookie->msg, NL80211_KEY_DATA,
3046 params->key_len, params->key)) ||
3047 (params->seq &&
3048 nla_put(cookie->msg, NL80211_KEY_SEQ,
3049 params->seq_len, params->seq)) ||
3050 (params->cipher &&
3051 nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
3052 params->cipher)))
3053 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003054
David S. Miller9360ffd2012-03-29 04:41:26 -04003055 if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx))
3056 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003057
3058 nla_nest_end(cookie->msg, key);
3059
Johannes Berg41ade002007-12-19 02:03:29 +01003060 return;
3061 nla_put_failure:
3062 cookie->error = 1;
3063}
3064
3065static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
3066{
Johannes Berg4c476992010-10-04 21:36:35 +02003067 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003068 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003069 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003070 u8 key_idx = 0;
Johannes Berge31b8212010-10-05 19:39:30 +02003071 const u8 *mac_addr = NULL;
3072 bool pairwise;
Johannes Berg41ade002007-12-19 02:03:29 +01003073 struct get_key_cookie cookie = {
3074 .error = 0,
3075 };
3076 void *hdr;
3077 struct sk_buff *msg;
3078
3079 if (info->attrs[NL80211_ATTR_KEY_IDX])
3080 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
3081
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +02003082 if (key_idx > 5)
Johannes Berg41ade002007-12-19 02:03:29 +01003083 return -EINVAL;
3084
3085 if (info->attrs[NL80211_ATTR_MAC])
3086 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3087
Johannes Berge31b8212010-10-05 19:39:30 +02003088 pairwise = !!mac_addr;
3089 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
3090 u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003091
Johannes Berge31b8212010-10-05 19:39:30 +02003092 if (kt >= NUM_NL80211_KEYTYPES)
3093 return -EINVAL;
3094 if (kt != NL80211_KEYTYPE_GROUP &&
3095 kt != NL80211_KEYTYPE_PAIRWISE)
3096 return -EINVAL;
3097 pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
3098 }
3099
Johannes Berg4c476992010-10-04 21:36:35 +02003100 if (!rdev->ops->get_key)
3101 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003102
Johannes Berg0fa7b392015-01-23 11:10:12 +01003103 if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3104 return -ENOENT;
3105
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003106 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02003107 if (!msg)
3108 return -ENOMEM;
Johannes Berg41ade002007-12-19 02:03:29 +01003109
Eric W. Biederman15e47302012-09-07 20:12:54 +00003110 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg41ade002007-12-19 02:03:29 +01003111 NL80211_CMD_NEW_KEY);
Dan Carpentercb35fba2013-08-14 14:50:01 +03003112 if (!hdr)
Johannes Berg9fe271a2013-10-25 11:15:12 +02003113 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003114
3115 cookie.msg = msg;
Johannes Bergb9454e82009-07-08 13:29:08 +02003116 cookie.idx = key_idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003117
David S. Miller9360ffd2012-03-29 04:41:26 -04003118 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3119 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
3120 goto nla_put_failure;
3121 if (mac_addr &&
3122 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
3123 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003124
Hila Gonene35e4d22012-06-27 17:19:42 +03003125 err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
3126 get_key_callback);
Johannes Berg41ade002007-12-19 02:03:29 +01003127
3128 if (err)
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003129 goto free_msg;
Johannes Berg41ade002007-12-19 02:03:29 +01003130
3131 if (cookie.error)
3132 goto nla_put_failure;
3133
3134 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02003135 return genlmsg_reply(msg, info);
Johannes Berg41ade002007-12-19 02:03:29 +01003136
3137 nla_put_failure:
3138 err = -ENOBUFS;
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003139 free_msg:
Johannes Berg41ade002007-12-19 02:03:29 +01003140 nlmsg_free(msg);
Johannes Berg41ade002007-12-19 02:03:29 +01003141 return err;
3142}
3143
3144static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
3145{
Johannes Berg4c476992010-10-04 21:36:35 +02003146 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergb9454e82009-07-08 13:29:08 +02003147 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003148 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003149 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003150
Johannes Bergb9454e82009-07-08 13:29:08 +02003151 err = nl80211_parse_key(info, &key);
3152 if (err)
3153 return err;
3154
3155 if (key.idx < 0)
Johannes Berg41ade002007-12-19 02:03:29 +01003156 return -EINVAL;
3157
Johannes Bergb9454e82009-07-08 13:29:08 +02003158 /* only support setting default key */
3159 if (!key.def && !key.defmgmt)
Johannes Berg41ade002007-12-19 02:03:29 +01003160 return -EINVAL;
3161
Johannes Bergfffd0932009-07-08 14:22:54 +02003162 wdev_lock(dev->ieee80211_ptr);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003163
3164 if (key.def) {
3165 if (!rdev->ops->set_default_key) {
3166 err = -EOPNOTSUPP;
3167 goto out;
3168 }
3169
3170 err = nl80211_key_allowed(dev->ieee80211_ptr);
3171 if (err)
3172 goto out;
3173
Hila Gonene35e4d22012-06-27 17:19:42 +03003174 err = rdev_set_default_key(rdev, dev, key.idx,
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003175 key.def_uni, key.def_multi);
3176
3177 if (err)
3178 goto out;
Johannes Bergfffd0932009-07-08 14:22:54 +02003179
Johannes Berg3d23e342009-09-29 23:27:28 +02003180#ifdef CONFIG_CFG80211_WEXT
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003181 dev->ieee80211_ptr->wext.default_key = key.idx;
Johannes Berg08645122009-05-11 13:54:58 +02003182#endif
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003183 } else {
3184 if (key.def_uni || !key.def_multi) {
3185 err = -EINVAL;
3186 goto out;
3187 }
3188
3189 if (!rdev->ops->set_default_mgmt_key) {
3190 err = -EOPNOTSUPP;
3191 goto out;
3192 }
3193
3194 err = nl80211_key_allowed(dev->ieee80211_ptr);
3195 if (err)
3196 goto out;
3197
Hila Gonene35e4d22012-06-27 17:19:42 +03003198 err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003199 if (err)
3200 goto out;
3201
3202#ifdef CONFIG_CFG80211_WEXT
3203 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
3204#endif
3205 }
3206
3207 out:
Johannes Bergfffd0932009-07-08 14:22:54 +02003208 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003209
Johannes Berg41ade002007-12-19 02:03:29 +01003210 return err;
3211}
3212
3213static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
3214{
Johannes Berg4c476992010-10-04 21:36:35 +02003215 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfffd0932009-07-08 14:22:54 +02003216 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003217 struct net_device *dev = info->user_ptr[1];
Johannes Bergb9454e82009-07-08 13:29:08 +02003218 struct key_parse key;
Johannes Berge31b8212010-10-05 19:39:30 +02003219 const u8 *mac_addr = NULL;
Johannes Berg41ade002007-12-19 02:03:29 +01003220
Johannes Bergb9454e82009-07-08 13:29:08 +02003221 err = nl80211_parse_key(info, &key);
3222 if (err)
3223 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003224
Johannes Bergb9454e82009-07-08 13:29:08 +02003225 if (!key.p.key)
Johannes Berg41ade002007-12-19 02:03:29 +01003226 return -EINVAL;
3227
Johannes Berg41ade002007-12-19 02:03:29 +01003228 if (info->attrs[NL80211_ATTR_MAC])
3229 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3230
Johannes Berge31b8212010-10-05 19:39:30 +02003231 if (key.type == -1) {
3232 if (mac_addr)
3233 key.type = NL80211_KEYTYPE_PAIRWISE;
3234 else
3235 key.type = NL80211_KEYTYPE_GROUP;
3236 }
3237
3238 /* for now */
3239 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3240 key.type != NL80211_KEYTYPE_GROUP)
3241 return -EINVAL;
3242
Johannes Berg4c476992010-10-04 21:36:35 +02003243 if (!rdev->ops->add_key)
3244 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003245
Johannes Berge31b8212010-10-05 19:39:30 +02003246 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
3247 key.type == NL80211_KEYTYPE_PAIRWISE,
3248 mac_addr))
Johannes Berg4c476992010-10-04 21:36:35 +02003249 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02003250
3251 wdev_lock(dev->ieee80211_ptr);
3252 err = nl80211_key_allowed(dev->ieee80211_ptr);
3253 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003254 err = rdev_add_key(rdev, dev, key.idx,
3255 key.type == NL80211_KEYTYPE_PAIRWISE,
3256 mac_addr, &key.p);
Johannes Bergfffd0932009-07-08 14:22:54 +02003257 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003258
Johannes Berg41ade002007-12-19 02:03:29 +01003259 return err;
3260}
3261
3262static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
3263{
Johannes Berg4c476992010-10-04 21:36:35 +02003264 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003265 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003266 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003267 u8 *mac_addr = NULL;
Johannes Bergb9454e82009-07-08 13:29:08 +02003268 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003269
Johannes Bergb9454e82009-07-08 13:29:08 +02003270 err = nl80211_parse_key(info, &key);
3271 if (err)
3272 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003273
3274 if (info->attrs[NL80211_ATTR_MAC])
3275 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3276
Johannes Berge31b8212010-10-05 19:39:30 +02003277 if (key.type == -1) {
3278 if (mac_addr)
3279 key.type = NL80211_KEYTYPE_PAIRWISE;
3280 else
3281 key.type = NL80211_KEYTYPE_GROUP;
3282 }
3283
3284 /* for now */
3285 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3286 key.type != NL80211_KEYTYPE_GROUP)
3287 return -EINVAL;
3288
Johannes Berg4c476992010-10-04 21:36:35 +02003289 if (!rdev->ops->del_key)
3290 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003291
Johannes Bergfffd0932009-07-08 14:22:54 +02003292 wdev_lock(dev->ieee80211_ptr);
3293 err = nl80211_key_allowed(dev->ieee80211_ptr);
Johannes Berge31b8212010-10-05 19:39:30 +02003294
Johannes Berg0fa7b392015-01-23 11:10:12 +01003295 if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
Johannes Berge31b8212010-10-05 19:39:30 +02003296 !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3297 err = -ENOENT;
3298
Johannes Bergfffd0932009-07-08 14:22:54 +02003299 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003300 err = rdev_del_key(rdev, dev, key.idx,
3301 key.type == NL80211_KEYTYPE_PAIRWISE,
3302 mac_addr);
Johannes Berg41ade002007-12-19 02:03:29 +01003303
Johannes Berg3d23e342009-09-29 23:27:28 +02003304#ifdef CONFIG_CFG80211_WEXT
Johannes Berg08645122009-05-11 13:54:58 +02003305 if (!err) {
Johannes Bergb9454e82009-07-08 13:29:08 +02003306 if (key.idx == dev->ieee80211_ptr->wext.default_key)
Johannes Berg08645122009-05-11 13:54:58 +02003307 dev->ieee80211_ptr->wext.default_key = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02003308 else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
Johannes Berg08645122009-05-11 13:54:58 +02003309 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
3310 }
3311#endif
Johannes Bergfffd0932009-07-08 14:22:54 +02003312 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg08645122009-05-11 13:54:58 +02003313
Johannes Berg41ade002007-12-19 02:03:29 +01003314 return err;
3315}
3316
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05303317/* This function returns an error or the number of nested attributes */
3318static int validate_acl_mac_addrs(struct nlattr *nl_attr)
3319{
3320 struct nlattr *attr;
3321 int n_entries = 0, tmp;
3322
3323 nla_for_each_nested(attr, nl_attr, tmp) {
3324 if (nla_len(attr) != ETH_ALEN)
3325 return -EINVAL;
3326
3327 n_entries++;
3328 }
3329
3330 return n_entries;
3331}
3332
3333/*
3334 * This function parses ACL information and allocates memory for ACL data.
3335 * On successful return, the calling function is responsible to free the
3336 * ACL buffer returned by this function.
3337 */
3338static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
3339 struct genl_info *info)
3340{
3341 enum nl80211_acl_policy acl_policy;
3342 struct nlattr *attr;
3343 struct cfg80211_acl_data *acl;
3344 int i = 0, n_entries, tmp;
3345
3346 if (!wiphy->max_acl_mac_addrs)
3347 return ERR_PTR(-EOPNOTSUPP);
3348
3349 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
3350 return ERR_PTR(-EINVAL);
3351
3352 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
3353 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
3354 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
3355 return ERR_PTR(-EINVAL);
3356
3357 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
3358 return ERR_PTR(-EINVAL);
3359
3360 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
3361 if (n_entries < 0)
3362 return ERR_PTR(n_entries);
3363
3364 if (n_entries > wiphy->max_acl_mac_addrs)
3365 return ERR_PTR(-ENOTSUPP);
3366
3367 acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
3368 GFP_KERNEL);
3369 if (!acl)
3370 return ERR_PTR(-ENOMEM);
3371
3372 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
3373 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
3374 i++;
3375 }
3376
3377 acl->n_acl_entries = n_entries;
3378 acl->acl_policy = acl_policy;
3379
3380 return acl;
3381}
3382
3383static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
3384{
3385 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3386 struct net_device *dev = info->user_ptr[1];
3387 struct cfg80211_acl_data *acl;
3388 int err;
3389
3390 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3391 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3392 return -EOPNOTSUPP;
3393
3394 if (!dev->ieee80211_ptr->beacon_interval)
3395 return -EINVAL;
3396
3397 acl = parse_acl_data(&rdev->wiphy, info);
3398 if (IS_ERR(acl))
3399 return PTR_ERR(acl);
3400
3401 err = rdev_set_mac_acl(rdev, dev, acl);
3402
3403 kfree(acl);
3404
3405 return err;
3406}
3407
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303408static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
3409 u8 *rates, u8 rates_len)
3410{
3411 u8 i;
3412 u32 mask = 0;
3413
3414 for (i = 0; i < rates_len; i++) {
3415 int rate = (rates[i] & 0x7f) * 5;
3416 int ridx;
3417
3418 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
3419 struct ieee80211_rate *srate =
3420 &sband->bitrates[ridx];
3421 if (rate == srate->bitrate) {
3422 mask |= 1 << ridx;
3423 break;
3424 }
3425 }
3426 if (ridx == sband->n_bitrates)
3427 return 0; /* rate not found */
3428 }
3429
3430 return mask;
3431}
3432
3433static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
3434 u8 *rates, u8 rates_len,
3435 u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
3436{
3437 u8 i;
3438
3439 memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
3440
3441 for (i = 0; i < rates_len; i++) {
3442 int ridx, rbit;
3443
3444 ridx = rates[i] / 8;
3445 rbit = BIT(rates[i] % 8);
3446
3447 /* check validity */
3448 if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
3449 return false;
3450
3451 /* check availability */
3452 if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
3453 mcs[ridx] |= rbit;
3454 else
3455 return false;
3456 }
3457
3458 return true;
3459}
3460
3461static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
3462{
3463 u16 mcs_mask = 0;
3464
3465 switch (vht_mcs_map) {
3466 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
3467 break;
3468 case IEEE80211_VHT_MCS_SUPPORT_0_7:
3469 mcs_mask = 0x00FF;
3470 break;
3471 case IEEE80211_VHT_MCS_SUPPORT_0_8:
3472 mcs_mask = 0x01FF;
3473 break;
3474 case IEEE80211_VHT_MCS_SUPPORT_0_9:
3475 mcs_mask = 0x03FF;
3476 break;
3477 default:
3478 break;
3479 }
3480
3481 return mcs_mask;
3482}
3483
3484static void vht_build_mcs_mask(u16 vht_mcs_map,
3485 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
3486{
3487 u8 nss;
3488
3489 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
3490 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
3491 vht_mcs_map >>= 2;
3492 }
3493}
3494
3495static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
3496 struct nl80211_txrate_vht *txrate,
3497 u16 mcs[NL80211_VHT_NSS_MAX])
3498{
3499 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3500 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
3501 u8 i;
3502
3503 if (!sband->vht_cap.vht_supported)
3504 return false;
3505
3506 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
3507
3508 /* Build vht_mcs_mask from VHT capabilities */
3509 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
3510
3511 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
3512 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
3513 mcs[i] = txrate->mcs[i];
3514 else
3515 return false;
3516 }
3517
3518 return true;
3519}
3520
3521static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
3522 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
3523 .len = NL80211_MAX_SUPP_RATES },
3524 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
3525 .len = NL80211_MAX_SUPP_HT_RATES },
3526 [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
3527 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
3528};
3529
3530static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
3531 struct cfg80211_bitrate_mask *mask)
3532{
3533 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
3534 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3535 int rem, i;
3536 struct nlattr *tx_rates;
3537 struct ieee80211_supported_band *sband;
3538 u16 vht_tx_mcs_map;
3539
3540 memset(mask, 0, sizeof(*mask));
3541 /* Default to all rates enabled */
3542 for (i = 0; i < NUM_NL80211_BANDS; i++) {
3543 sband = rdev->wiphy.bands[i];
3544
3545 if (!sband)
3546 continue;
3547
3548 mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
3549 memcpy(mask->control[i].ht_mcs,
3550 sband->ht_cap.mcs.rx_mask,
3551 sizeof(mask->control[i].ht_mcs));
3552
3553 if (!sband->vht_cap.vht_supported)
3554 continue;
3555
3556 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3557 vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
3558 }
3559
3560 /* if no rates are given set it back to the defaults */
3561 if (!info->attrs[NL80211_ATTR_TX_RATES])
3562 goto out;
3563
3564 /* The nested attribute uses enum nl80211_band as the index. This maps
3565 * directly to the enum nl80211_band values used in cfg80211.
3566 */
3567 BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
3568 nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
3569 enum nl80211_band band = nla_type(tx_rates);
3570 int err;
3571
3572 if (band < 0 || band >= NUM_NL80211_BANDS)
3573 return -EINVAL;
3574 sband = rdev->wiphy.bands[band];
3575 if (sband == NULL)
3576 return -EINVAL;
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02003577 err = nla_parse_nested(tb, NL80211_TXRATE_MAX, tx_rates,
3578 nl80211_txattr_policy);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303579 if (err)
3580 return err;
3581 if (tb[NL80211_TXRATE_LEGACY]) {
3582 mask->control[band].legacy = rateset_to_mask(
3583 sband,
3584 nla_data(tb[NL80211_TXRATE_LEGACY]),
3585 nla_len(tb[NL80211_TXRATE_LEGACY]));
3586 if ((mask->control[band].legacy == 0) &&
3587 nla_len(tb[NL80211_TXRATE_LEGACY]))
3588 return -EINVAL;
3589 }
3590 if (tb[NL80211_TXRATE_HT]) {
3591 if (!ht_rateset_to_mask(
3592 sband,
3593 nla_data(tb[NL80211_TXRATE_HT]),
3594 nla_len(tb[NL80211_TXRATE_HT]),
3595 mask->control[band].ht_mcs))
3596 return -EINVAL;
3597 }
3598 if (tb[NL80211_TXRATE_VHT]) {
3599 if (!vht_set_mcs_mask(
3600 sband,
3601 nla_data(tb[NL80211_TXRATE_VHT]),
3602 mask->control[band].vht_mcs))
3603 return -EINVAL;
3604 }
3605 if (tb[NL80211_TXRATE_GI]) {
3606 mask->control[band].gi =
3607 nla_get_u8(tb[NL80211_TXRATE_GI]);
3608 if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
3609 return -EINVAL;
3610 }
3611
3612 if (mask->control[band].legacy == 0) {
3613 /* don't allow empty legacy rates if HT or VHT
3614 * are not even supported.
3615 */
3616 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
3617 rdev->wiphy.bands[band]->vht_cap.vht_supported))
3618 return -EINVAL;
3619
3620 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
3621 if (mask->control[band].ht_mcs[i])
3622 goto out;
3623
3624 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
3625 if (mask->control[band].vht_mcs[i])
3626 goto out;
3627
3628 /* legacy and mcs rates may not be both empty */
3629 return -EINVAL;
3630 }
3631 }
3632
3633out:
3634 return 0;
3635}
3636
Johannes Berg8564e382016-09-19 09:44:44 +02003637static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
3638 enum nl80211_band band,
3639 struct cfg80211_bitrate_mask *beacon_rate)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303640{
Johannes Berg8564e382016-09-19 09:44:44 +02003641 u32 count_ht, count_vht, i;
3642 u32 rate = beacon_rate->control[band].legacy;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303643
3644 /* Allow only one rate */
3645 if (hweight32(rate) > 1)
3646 return -EINVAL;
3647
3648 count_ht = 0;
3649 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003650 if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303651 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003652 } else if (beacon_rate->control[band].ht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303653 count_ht++;
3654 if (count_ht > 1)
3655 return -EINVAL;
3656 }
3657 if (count_ht && rate)
3658 return -EINVAL;
3659 }
3660
3661 count_vht = 0;
3662 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003663 if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303664 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003665 } else if (beacon_rate->control[band].vht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303666 count_vht++;
3667 if (count_vht > 1)
3668 return -EINVAL;
3669 }
3670 if (count_vht && rate)
3671 return -EINVAL;
3672 }
3673
3674 if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
3675 return -EINVAL;
3676
Johannes Berg8564e382016-09-19 09:44:44 +02003677 if (rate &&
3678 !wiphy_ext_feature_isset(&rdev->wiphy,
3679 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
3680 return -EINVAL;
3681 if (count_ht &&
3682 !wiphy_ext_feature_isset(&rdev->wiphy,
3683 NL80211_EXT_FEATURE_BEACON_RATE_HT))
3684 return -EINVAL;
3685 if (count_vht &&
3686 !wiphy_ext_feature_isset(&rdev->wiphy,
3687 NL80211_EXT_FEATURE_BEACON_RATE_VHT))
3688 return -EINVAL;
3689
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303690 return 0;
3691}
3692
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003693static int nl80211_parse_beacon(struct nlattr *attrs[],
Johannes Berg88600202012-02-13 15:17:18 +01003694 struct cfg80211_beacon_data *bcn)
Johannes Berged1b6cc2007-12-19 02:03:32 +01003695{
Johannes Berg88600202012-02-13 15:17:18 +01003696 bool haveinfo = false;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003697
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003698 if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
3699 !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
3700 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
3701 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
Johannes Bergf4a11bb2009-03-27 12:40:28 +01003702 return -EINVAL;
3703
Johannes Berg88600202012-02-13 15:17:18 +01003704 memset(bcn, 0, sizeof(*bcn));
Johannes Berged1b6cc2007-12-19 02:03:32 +01003705
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003706 if (attrs[NL80211_ATTR_BEACON_HEAD]) {
3707 bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
3708 bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
Johannes Berg88600202012-02-13 15:17:18 +01003709 if (!bcn->head_len)
3710 return -EINVAL;
3711 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003712 }
3713
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003714 if (attrs[NL80211_ATTR_BEACON_TAIL]) {
3715 bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
3716 bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
Johannes Berg88600202012-02-13 15:17:18 +01003717 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003718 }
3719
Johannes Berg4c476992010-10-04 21:36:35 +02003720 if (!haveinfo)
3721 return -EINVAL;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003722
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003723 if (attrs[NL80211_ATTR_IE]) {
3724 bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
3725 bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003726 }
3727
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003728 if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003729 bcn->proberesp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003730 nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003731 bcn->proberesp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003732 nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003733 }
3734
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003735 if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003736 bcn->assocresp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003737 nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003738 bcn->assocresp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003739 nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003740 }
3741
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003742 if (attrs[NL80211_ATTR_PROBE_RESP]) {
3743 bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
3744 bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
Arik Nemtsov00f740e2011-11-10 11:28:56 +02003745 }
3746
Johannes Berg88600202012-02-13 15:17:18 +01003747 return 0;
3748}
3749
Johannes Berg66cd7942017-02-07 22:40:44 +02003750static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
3751 const u8 *rates)
3752{
3753 int i;
3754
3755 if (!rates)
3756 return;
3757
3758 for (i = 0; i < rates[1]; i++) {
3759 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
3760 params->ht_required = true;
3761 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
3762 params->vht_required = true;
3763 }
3764}
3765
3766/*
3767 * Since the nl80211 API didn't include, from the beginning, attributes about
3768 * HT/VHT requirements/capabilities, we parse them out of the IEs for the
3769 * benefit of drivers that rebuild IEs in the firmware.
3770 */
3771static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
3772{
3773 const struct cfg80211_beacon_data *bcn = &params->beacon;
3774 size_t ies_len = bcn->beacon_ies_len;
3775 const u8 *ies = bcn->beacon_ies;
3776 const u8 *rates;
3777 const u8 *cap;
3778
3779 rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
3780 nl80211_check_ap_rate_selectors(params, rates);
3781
3782 rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
3783 nl80211_check_ap_rate_selectors(params, rates);
3784
3785 cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
3786 if (cap && cap[1] >= sizeof(*params->ht_cap))
3787 params->ht_cap = (void *)(cap + 2);
3788 cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
3789 if (cap && cap[1] >= sizeof(*params->vht_cap))
3790 params->vht_cap = (void *)(cap + 2);
3791}
3792
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003793static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
3794 struct cfg80211_ap_settings *params)
3795{
3796 struct wireless_dev *wdev;
3797 bool ret = false;
3798
Johannes Berg53873f12016-05-03 16:52:04 +03003799 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003800 if (wdev->iftype != NL80211_IFTYPE_AP &&
3801 wdev->iftype != NL80211_IFTYPE_P2P_GO)
3802 continue;
3803
Johannes Berg683b6d32012-11-08 21:25:48 +01003804 if (!wdev->preset_chandef.chan)
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003805 continue;
3806
Johannes Berg683b6d32012-11-08 21:25:48 +01003807 params->chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003808 ret = true;
3809 break;
3810 }
3811
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003812 return ret;
3813}
3814
Jouni Malinene39e5b52012-09-30 19:29:39 +03003815static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
3816 enum nl80211_auth_type auth_type,
3817 enum nl80211_commands cmd)
3818{
3819 if (auth_type > NL80211_AUTHTYPE_MAX)
3820 return false;
3821
3822 switch (cmd) {
3823 case NL80211_CMD_AUTHENTICATE:
3824 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
3825 auth_type == NL80211_AUTHTYPE_SAE)
3826 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003827 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3828 NL80211_EXT_FEATURE_FILS_STA) &&
3829 (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3830 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3831 auth_type == NL80211_AUTHTYPE_FILS_PK))
3832 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003833 return true;
3834 case NL80211_CMD_CONNECT:
3835 case NL80211_CMD_START_AP:
3836 /* SAE not supported yet */
3837 if (auth_type == NL80211_AUTHTYPE_SAE)
3838 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003839 /* FILS not supported yet */
3840 if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3841 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3842 auth_type == NL80211_AUTHTYPE_FILS_PK)
3843 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003844 return true;
3845 default:
3846 return false;
3847 }
3848}
3849
Johannes Berg88600202012-02-13 15:17:18 +01003850static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
3851{
3852 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3853 struct net_device *dev = info->user_ptr[1];
3854 struct wireless_dev *wdev = dev->ieee80211_ptr;
3855 struct cfg80211_ap_settings params;
3856 int err;
3857
3858 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3859 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3860 return -EOPNOTSUPP;
3861
3862 if (!rdev->ops->start_ap)
3863 return -EOPNOTSUPP;
3864
3865 if (wdev->beacon_interval)
3866 return -EALREADY;
3867
3868 memset(&params, 0, sizeof(params));
3869
3870 /* these are required for START_AP */
3871 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
3872 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
3873 !info->attrs[NL80211_ATTR_BEACON_HEAD])
3874 return -EINVAL;
3875
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003876 err = nl80211_parse_beacon(info->attrs, &params.beacon);
Johannes Berg88600202012-02-13 15:17:18 +01003877 if (err)
3878 return err;
3879
3880 params.beacon_interval =
3881 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
3882 params.dtim_period =
3883 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
3884
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05303885 err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
3886 params.beacon_interval);
Johannes Berg88600202012-02-13 15:17:18 +01003887 if (err)
3888 return err;
3889
3890 /*
3891 * In theory, some of these attributes should be required here
3892 * but since they were not used when the command was originally
3893 * added, keep them optional for old user space programs to let
3894 * them continue to work with drivers that do not need the
3895 * additional information -- drivers must check!
3896 */
3897 if (info->attrs[NL80211_ATTR_SSID]) {
3898 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3899 params.ssid_len =
3900 nla_len(info->attrs[NL80211_ATTR_SSID]);
3901 if (params.ssid_len == 0 ||
3902 params.ssid_len > IEEE80211_MAX_SSID_LEN)
3903 return -EINVAL;
3904 }
3905
3906 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
3907 params.hidden_ssid = nla_get_u32(
3908 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
3909 if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
3910 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
3911 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
3912 return -EINVAL;
3913 }
3914
3915 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
3916
3917 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
3918 params.auth_type = nla_get_u32(
3919 info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03003920 if (!nl80211_valid_auth_type(rdev, params.auth_type,
3921 NL80211_CMD_START_AP))
Johannes Berg88600202012-02-13 15:17:18 +01003922 return -EINVAL;
3923 } else
3924 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
3925
3926 err = nl80211_crypto_settings(rdev, info, &params.crypto,
3927 NL80211_MAX_NR_CIPHER_SUITES);
3928 if (err)
3929 return err;
3930
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05303931 if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
3932 if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
3933 return -EOPNOTSUPP;
3934 params.inactivity_timeout = nla_get_u16(
3935 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
3936 }
3937
Johannes Berg53cabad2012-11-14 15:17:28 +01003938 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
3939 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3940 return -EINVAL;
3941 params.p2p_ctwindow =
3942 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
3943 if (params.p2p_ctwindow > 127)
3944 return -EINVAL;
3945 if (params.p2p_ctwindow != 0 &&
3946 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
3947 return -EINVAL;
3948 }
3949
3950 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
3951 u8 tmp;
3952
3953 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3954 return -EINVAL;
3955 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
3956 if (tmp > 1)
3957 return -EINVAL;
3958 params.p2p_opp_ps = tmp;
3959 if (params.p2p_opp_ps != 0 &&
3960 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
3961 return -EINVAL;
3962 }
3963
Johannes Bergaa430da2012-05-16 23:50:18 +02003964 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01003965 err = nl80211_parse_chandef(rdev, info, &params.chandef);
3966 if (err)
3967 return err;
3968 } else if (wdev->preset_chandef.chan) {
3969 params.chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003970 } else if (!nl80211_get_ap_channel(rdev, &params))
Johannes Bergaa430da2012-05-16 23:50:18 +02003971 return -EINVAL;
3972
Arik Nemtsov923b3522015-07-08 15:41:44 +03003973 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
3974 wdev->iftype))
Johannes Bergaa430da2012-05-16 23:50:18 +02003975 return -EINVAL;
3976
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303977 if (info->attrs[NL80211_ATTR_TX_RATES]) {
3978 err = nl80211_parse_tx_bitrate_mask(info, &params.beacon_rate);
3979 if (err)
3980 return err;
3981
Johannes Berg8564e382016-09-19 09:44:44 +02003982 err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
3983 &params.beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303984 if (err)
3985 return err;
3986 }
3987
Eliad Peller18998c32014-09-10 14:07:34 +03003988 if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
3989 params.smps_mode =
3990 nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
3991 switch (params.smps_mode) {
3992 case NL80211_SMPS_OFF:
3993 break;
3994 case NL80211_SMPS_STATIC:
3995 if (!(rdev->wiphy.features &
3996 NL80211_FEATURE_STATIC_SMPS))
3997 return -EINVAL;
3998 break;
3999 case NL80211_SMPS_DYNAMIC:
4000 if (!(rdev->wiphy.features &
4001 NL80211_FEATURE_DYNAMIC_SMPS))
4002 return -EINVAL;
4003 break;
4004 default:
4005 return -EINVAL;
4006 }
4007 } else {
4008 params.smps_mode = NL80211_SMPS_OFF;
4009 }
4010
Purushottam Kushwaha6e8ef842016-07-05 13:44:51 +05304011 params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
4012 if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
4013 return -EOPNOTSUPP;
4014
Ola Olsson4baf6be2015-10-29 07:04:58 +01004015 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
4016 params.acl = parse_acl_data(&rdev->wiphy, info);
4017 if (IS_ERR(params.acl))
4018 return PTR_ERR(params.acl);
4019 }
4020
Johannes Berg66cd7942017-02-07 22:40:44 +02004021 nl80211_calculate_ap_params(&params);
4022
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004023 wdev_lock(wdev);
Hila Gonene35e4d22012-06-27 17:19:42 +03004024 err = rdev_start_ap(rdev, dev, &params);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004025 if (!err) {
Johannes Berg683b6d32012-11-08 21:25:48 +01004026 wdev->preset_chandef = params.chandef;
Johannes Berg88600202012-02-13 15:17:18 +01004027 wdev->beacon_interval = params.beacon_interval;
Michal Kazior9e0e2962014-01-29 14:22:27 +01004028 wdev->chandef = params.chandef;
Antonio Quartulli06e191e2012-11-07 12:52:19 +01004029 wdev->ssid_len = params.ssid_len;
4030 memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004031 }
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004032 wdev_unlock(wdev);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304033
4034 kfree(params.acl);
4035
Johannes Berg56d18932011-05-09 18:41:15 +02004036 return err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004037}
4038
Johannes Berg88600202012-02-13 15:17:18 +01004039static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
4040{
4041 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4042 struct net_device *dev = info->user_ptr[1];
4043 struct wireless_dev *wdev = dev->ieee80211_ptr;
4044 struct cfg80211_beacon_data params;
4045 int err;
4046
4047 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4048 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4049 return -EOPNOTSUPP;
4050
4051 if (!rdev->ops->change_beacon)
4052 return -EOPNOTSUPP;
4053
4054 if (!wdev->beacon_interval)
4055 return -EINVAL;
4056
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004057 err = nl80211_parse_beacon(info->attrs, &params);
Johannes Berg88600202012-02-13 15:17:18 +01004058 if (err)
4059 return err;
4060
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004061 wdev_lock(wdev);
4062 err = rdev_change_beacon(rdev, dev, &params);
4063 wdev_unlock(wdev);
4064
4065 return err;
Johannes Berg88600202012-02-13 15:17:18 +01004066}
4067
4068static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
Johannes Berged1b6cc2007-12-19 02:03:32 +01004069{
Johannes Berg4c476992010-10-04 21:36:35 +02004070 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4071 struct net_device *dev = info->user_ptr[1];
Johannes Berged1b6cc2007-12-19 02:03:32 +01004072
Ilan Peer7c8d5e02014-02-25 15:33:38 +02004073 return cfg80211_stop_ap(rdev, dev, false);
Johannes Berged1b6cc2007-12-19 02:03:32 +01004074}
4075
Johannes Berg5727ef12007-12-19 02:03:34 +01004076static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
4077 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
4078 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
4079 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
Jouni Malinen0e467242009-05-11 21:57:55 +03004080 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
Javier Cardonab39c48f2011-04-07 15:08:30 -07004081 [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
Johannes Bergd83023d2011-12-14 09:29:15 +01004082 [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
Johannes Berg5727ef12007-12-19 02:03:34 +01004083};
4084
Johannes Bergeccb8e82009-05-11 21:57:56 +03004085static int parse_station_flags(struct genl_info *info,
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004086 enum nl80211_iftype iftype,
Johannes Bergeccb8e82009-05-11 21:57:56 +03004087 struct station_parameters *params)
Johannes Berg5727ef12007-12-19 02:03:34 +01004088{
4089 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
Johannes Bergeccb8e82009-05-11 21:57:56 +03004090 struct nlattr *nla;
Johannes Berg5727ef12007-12-19 02:03:34 +01004091 int flag;
4092
Johannes Bergeccb8e82009-05-11 21:57:56 +03004093 /*
4094 * Try parsing the new attribute first so userspace
4095 * can specify both for older kernels.
4096 */
4097 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
4098 if (nla) {
4099 struct nl80211_sta_flag_update *sta_flags;
Johannes Berg5727ef12007-12-19 02:03:34 +01004100
Johannes Bergeccb8e82009-05-11 21:57:56 +03004101 sta_flags = nla_data(nla);
4102 params->sta_flags_mask = sta_flags->mask;
4103 params->sta_flags_set = sta_flags->set;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004104 params->sta_flags_set &= params->sta_flags_mask;
Johannes Bergeccb8e82009-05-11 21:57:56 +03004105 if ((params->sta_flags_mask |
4106 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
4107 return -EINVAL;
4108 return 0;
4109 }
4110
4111 /* if present, parse the old attribute */
4112
4113 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
Johannes Berg5727ef12007-12-19 02:03:34 +01004114 if (!nla)
4115 return 0;
4116
4117 if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
4118 nla, sta_flags_policy))
4119 return -EINVAL;
4120
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004121 /*
4122 * Only allow certain flags for interface types so that
4123 * other attributes are silently ignored. Remember that
4124 * this is backward compatibility code with old userspace
4125 * and shouldn't be hit in other cases anyway.
4126 */
4127 switch (iftype) {
4128 case NL80211_IFTYPE_AP:
4129 case NL80211_IFTYPE_AP_VLAN:
4130 case NL80211_IFTYPE_P2P_GO:
4131 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4132 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4133 BIT(NL80211_STA_FLAG_WME) |
4134 BIT(NL80211_STA_FLAG_MFP);
4135 break;
4136 case NL80211_IFTYPE_P2P_CLIENT:
4137 case NL80211_IFTYPE_STATION:
4138 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4139 BIT(NL80211_STA_FLAG_TDLS_PEER);
4140 break;
4141 case NL80211_IFTYPE_MESH_POINT:
4142 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4143 BIT(NL80211_STA_FLAG_MFP) |
4144 BIT(NL80211_STA_FLAG_AUTHORIZED);
4145 default:
4146 return -EINVAL;
4147 }
Johannes Berg5727ef12007-12-19 02:03:34 +01004148
Johannes Berg3383b5a2012-05-10 20:14:43 +02004149 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
4150 if (flags[flag]) {
Johannes Bergeccb8e82009-05-11 21:57:56 +03004151 params->sta_flags_set |= (1<<flag);
Johannes Berg5727ef12007-12-19 02:03:34 +01004152
Johannes Berg3383b5a2012-05-10 20:14:43 +02004153 /* no longer support new API additions in old API */
4154 if (flag > NL80211_STA_FLAG_MAX_OLD_API)
4155 return -EINVAL;
4156 }
4157 }
4158
Johannes Berg5727ef12007-12-19 02:03:34 +01004159 return 0;
4160}
4161
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004162static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
4163 int attr)
4164{
4165 struct nlattr *rate;
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004166 u32 bitrate;
4167 u16 bitrate_compat;
Johannes Bergb51f3be2015-01-15 16:14:02 +01004168 enum nl80211_attrs rate_flg;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004169
4170 rate = nla_nest_start(msg, attr);
4171 if (!rate)
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004172 return false;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004173
4174 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
4175 bitrate = cfg80211_calculate_bitrate(info);
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004176 /* report 16-bit bitrate only if we can */
4177 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004178 if (bitrate > 0 &&
4179 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
4180 return false;
4181 if (bitrate_compat > 0 &&
4182 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
4183 return false;
4184
Johannes Bergb51f3be2015-01-15 16:14:02 +01004185 switch (info->bw) {
4186 case RATE_INFO_BW_5:
4187 rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
4188 break;
4189 case RATE_INFO_BW_10:
4190 rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
4191 break;
4192 default:
4193 WARN_ON(1);
4194 /* fall through */
4195 case RATE_INFO_BW_20:
4196 rate_flg = 0;
4197 break;
4198 case RATE_INFO_BW_40:
4199 rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
4200 break;
4201 case RATE_INFO_BW_80:
4202 rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
4203 break;
4204 case RATE_INFO_BW_160:
4205 rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
4206 break;
4207 }
4208
4209 if (rate_flg && nla_put_flag(msg, rate_flg))
4210 return false;
4211
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004212 if (info->flags & RATE_INFO_FLAGS_MCS) {
4213 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
4214 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004215 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4216 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4217 return false;
4218 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
4219 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
4220 return false;
4221 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
4222 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004223 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4224 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4225 return false;
4226 }
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004227
4228 nla_nest_end(msg, rate);
4229 return true;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004230}
4231
Felix Fietkau119363c2013-04-22 16:29:30 +02004232static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
4233 int id)
4234{
4235 void *attr;
4236 int i = 0;
4237
4238 if (!mask)
4239 return true;
4240
4241 attr = nla_nest_start(msg, id);
4242 if (!attr)
4243 return false;
4244
4245 for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
4246 if (!(mask & BIT(i)))
4247 continue;
4248
4249 if (nla_put_u8(msg, i, signal[i]))
4250 return false;
4251 }
4252
4253 nla_nest_end(msg, attr);
4254
4255 return true;
4256}
4257
Johannes Bergcf5ead82014-11-14 17:14:00 +01004258static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
4259 u32 seq, int flags,
John W. Linville66266b32012-03-15 13:25:41 -04004260 struct cfg80211_registered_device *rdev,
4261 struct net_device *dev,
Johannes Berg98b62182009-12-23 13:15:44 +01004262 const u8 *mac_addr, struct station_info *sinfo)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004263{
4264 void *hdr;
Paul Stewartf4263c92011-03-31 09:25:41 -07004265 struct nlattr *sinfoattr, *bss_param;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004266
Johannes Bergcf5ead82014-11-14 17:14:00 +01004267 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004268 if (!hdr)
4269 return -1;
4270
David S. Miller9360ffd2012-03-29 04:41:26 -04004271 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
4272 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
4273 nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
4274 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02004275
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004276 sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
4277 if (!sinfoattr)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004278 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004279
4280#define PUT_SINFO(attr, memb, type) do { \
Johannes Bergd686b922016-04-26 09:54:11 +02004281 BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
Mohammed Shafi Shajakhan739960f2016-04-07 19:59:34 +05304282 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
Johannes Berg319090b2014-11-17 14:08:11 +01004283 nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
4284 sinfo->memb)) \
4285 goto nla_put_failure; \
4286 } while (0)
Johannes Bergd686b922016-04-26 09:54:11 +02004287#define PUT_SINFO_U64(attr, memb) do { \
4288 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
4289 nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
4290 sinfo->memb, NL80211_STA_INFO_PAD)) \
4291 goto nla_put_failure; \
4292 } while (0)
Johannes Berg319090b2014-11-17 14:08:11 +01004293
4294 PUT_SINFO(CONNECTED_TIME, connected_time, u32);
4295 PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
4296
4297 if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
4298 BIT(NL80211_STA_INFO_RX_BYTES64)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004299 nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004300 (u32)sinfo->rx_bytes))
4301 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004302
4303 if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
4304 BIT(NL80211_STA_INFO_TX_BYTES64)) &&
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004305 nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
4306 (u32)sinfo->tx_bytes))
4307 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004308
Johannes Bergd686b922016-04-26 09:54:11 +02004309 PUT_SINFO_U64(RX_BYTES64, rx_bytes);
4310 PUT_SINFO_U64(TX_BYTES64, tx_bytes);
Johannes Berg319090b2014-11-17 14:08:11 +01004311 PUT_SINFO(LLID, llid, u16);
4312 PUT_SINFO(PLID, plid, u16);
4313 PUT_SINFO(PLINK_STATE, plink_state, u8);
Johannes Bergd686b922016-04-26 09:54:11 +02004314 PUT_SINFO_U64(RX_DURATION, rx_duration);
Johannes Berg319090b2014-11-17 14:08:11 +01004315
John W. Linville66266b32012-03-15 13:25:41 -04004316 switch (rdev->wiphy.signal_type) {
4317 case CFG80211_SIGNAL_TYPE_MBM:
Johannes Berg319090b2014-11-17 14:08:11 +01004318 PUT_SINFO(SIGNAL, signal, u8);
4319 PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
John W. Linville66266b32012-03-15 13:25:41 -04004320 break;
4321 default:
4322 break;
4323 }
Johannes Berg319090b2014-11-17 14:08:11 +01004324 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004325 if (!nl80211_put_signal(msg, sinfo->chains,
4326 sinfo->chain_signal,
4327 NL80211_STA_INFO_CHAIN_SIGNAL))
4328 goto nla_put_failure;
4329 }
Johannes Berg319090b2014-11-17 14:08:11 +01004330 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004331 if (!nl80211_put_signal(msg, sinfo->chains,
4332 sinfo->chain_signal_avg,
4333 NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
4334 goto nla_put_failure;
4335 }
Johannes Berg319090b2014-11-17 14:08:11 +01004336 if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004337 if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
4338 NL80211_STA_INFO_TX_BITRATE))
Henning Rogge420e7fa2008-12-11 22:04:19 +01004339 goto nla_put_failure;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004340 }
Johannes Berg319090b2014-11-17 14:08:11 +01004341 if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004342 if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
4343 NL80211_STA_INFO_RX_BITRATE))
4344 goto nla_put_failure;
Henning Rogge420e7fa2008-12-11 22:04:19 +01004345 }
Johannes Berg319090b2014-11-17 14:08:11 +01004346
4347 PUT_SINFO(RX_PACKETS, rx_packets, u32);
4348 PUT_SINFO(TX_PACKETS, tx_packets, u32);
4349 PUT_SINFO(TX_RETRIES, tx_retries, u32);
4350 PUT_SINFO(TX_FAILED, tx_failed, u32);
4351 PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
4352 PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
4353 PUT_SINFO(LOCAL_PM, local_pm, u32);
4354 PUT_SINFO(PEER_PM, peer_pm, u32);
4355 PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
4356
4357 if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
Paul Stewartf4263c92011-03-31 09:25:41 -07004358 bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
4359 if (!bss_param)
4360 goto nla_put_failure;
4361
David S. Miller9360ffd2012-03-29 04:41:26 -04004362 if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
4363 nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
4364 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
4365 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
4366 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
4367 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
4368 nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
4369 sinfo->bss_param.dtim_period) ||
4370 nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
4371 sinfo->bss_param.beacon_interval))
4372 goto nla_put_failure;
Paul Stewartf4263c92011-03-31 09:25:41 -07004373
4374 nla_nest_end(msg, bss_param);
4375 }
Johannes Berg319090b2014-11-17 14:08:11 +01004376 if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004377 nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
4378 sizeof(struct nl80211_sta_flag_update),
4379 &sinfo->sta_flags))
4380 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004381
Johannes Bergd686b922016-04-26 09:54:11 +02004382 PUT_SINFO_U64(T_OFFSET, t_offset);
4383 PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
4384 PUT_SINFO_U64(BEACON_RX, rx_beacon);
Johannes Berga76b1942014-11-17 14:12:22 +01004385 PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
Johannes Berg319090b2014-11-17 14:08:11 +01004386
4387#undef PUT_SINFO
Johannes Bergd686b922016-04-26 09:54:11 +02004388#undef PUT_SINFO_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004389
4390 if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
4391 struct nlattr *tidsattr;
4392 int tid;
4393
4394 tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS);
4395 if (!tidsattr)
4396 goto nla_put_failure;
4397
4398 for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
4399 struct cfg80211_tid_stats *tidstats;
4400 struct nlattr *tidattr;
4401
4402 tidstats = &sinfo->pertid[tid];
4403
4404 if (!tidstats->filled)
4405 continue;
4406
4407 tidattr = nla_nest_start(msg, tid + 1);
4408 if (!tidattr)
4409 goto nla_put_failure;
4410
Johannes Bergd686b922016-04-26 09:54:11 +02004411#define PUT_TIDVAL_U64(attr, memb) do { \
Johannes Berg6de39802014-12-19 12:34:00 +01004412 if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02004413 nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
4414 tidstats->memb, NL80211_TID_STATS_PAD)) \
Johannes Berg6de39802014-12-19 12:34:00 +01004415 goto nla_put_failure; \
4416 } while (0)
4417
Johannes Bergd686b922016-04-26 09:54:11 +02004418 PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
4419 PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
4420 PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
4421 PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
Johannes Berg6de39802014-12-19 12:34:00 +01004422
Johannes Bergd686b922016-04-26 09:54:11 +02004423#undef PUT_TIDVAL_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004424 nla_nest_end(msg, tidattr);
4425 }
4426
4427 nla_nest_end(msg, tidsattr);
4428 }
4429
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004430 nla_nest_end(msg, sinfoattr);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004431
Johannes Berg319090b2014-11-17 14:08:11 +01004432 if (sinfo->assoc_req_ies_len &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004433 nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
4434 sinfo->assoc_req_ies))
4435 goto nla_put_failure;
Jouni Malinen50d3dfb2011-08-08 12:11:52 +03004436
Johannes Berg053c0952015-01-16 22:09:00 +01004437 genlmsg_end(msg, hdr);
4438 return 0;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004439
4440 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07004441 genlmsg_cancel(msg, hdr);
4442 return -EMSGSIZE;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004443}
4444
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004445static int nl80211_dump_station(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004446 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004447{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004448 struct station_info sinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004449 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02004450 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004451 u8 mac_addr[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02004452 int sta_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004453 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004454
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004455 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02004456 if (err)
4457 return err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004458
Johannes Berg97990a02013-04-19 01:02:55 +02004459 if (!wdev->netdev) {
4460 err = -EINVAL;
4461 goto out_err;
4462 }
4463
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004464 if (!rdev->ops->dump_station) {
Jouni Malineneec60b02009-03-20 21:21:19 +02004465 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004466 goto out_err;
4467 }
4468
Johannes Bergbba95fe2008-07-29 13:22:51 +02004469 while (1) {
Jouni Malinenf612ced2011-08-11 11:46:22 +03004470 memset(&sinfo, 0, sizeof(sinfo));
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004471 err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
Hila Gonene35e4d22012-06-27 17:19:42 +03004472 mac_addr, &sinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004473 if (err == -ENOENT)
4474 break;
4475 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01004476 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004477
Johannes Bergcf5ead82014-11-14 17:14:00 +01004478 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004479 NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004480 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004481 rdev, wdev->netdev, mac_addr,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004482 &sinfo) < 0)
4483 goto out;
4484
4485 sta_idx++;
4486 }
4487
Johannes Bergbba95fe2008-07-29 13:22:51 +02004488 out:
Johannes Berg97990a02013-04-19 01:02:55 +02004489 cb->args[2] = sta_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004490 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004491 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004492 nl80211_finish_wdev_dump(rdev);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004493
4494 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004495}
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004496
Johannes Berg5727ef12007-12-19 02:03:34 +01004497static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
4498{
Johannes Berg4c476992010-10-04 21:36:35 +02004499 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4500 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004501 struct station_info sinfo;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004502 struct sk_buff *msg;
4503 u8 *mac_addr = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02004504 int err;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004505
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004506 memset(&sinfo, 0, sizeof(sinfo));
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004507
4508 if (!info->attrs[NL80211_ATTR_MAC])
4509 return -EINVAL;
4510
4511 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4512
Johannes Berg4c476992010-10-04 21:36:35 +02004513 if (!rdev->ops->get_station)
4514 return -EOPNOTSUPP;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004515
Hila Gonene35e4d22012-06-27 17:19:42 +03004516 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004517 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02004518 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004519
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07004520 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004521 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02004522 return -ENOMEM;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004523
Johannes Bergcf5ead82014-11-14 17:14:00 +01004524 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
4525 info->snd_portid, info->snd_seq, 0,
John W. Linville66266b32012-03-15 13:25:41 -04004526 rdev, dev, mac_addr, &sinfo) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02004527 nlmsg_free(msg);
4528 return -ENOBUFS;
4529 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004530
Johannes Berg4c476992010-10-04 21:36:35 +02004531 return genlmsg_reply(msg, info);
Johannes Berg5727ef12007-12-19 02:03:34 +01004532}
4533
Johannes Berg77ee7c82013-02-15 00:48:33 +01004534int cfg80211_check_station_change(struct wiphy *wiphy,
4535 struct station_parameters *params,
4536 enum cfg80211_station_type statype)
4537{
Ayala Bekere4208422015-10-23 11:20:06 +03004538 if (params->listen_interval != -1 &&
4539 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004540 return -EINVAL;
Ayala Bekere4208422015-10-23 11:20:06 +03004541
Ayala Beker17b94242016-03-17 15:41:38 +02004542 if (params->support_p2p_ps != -1 &&
4543 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
4544 return -EINVAL;
4545
Arik Nemtsovc72e1142014-07-17 17:14:29 +03004546 if (params->aid &&
Ayala Bekere4208422015-10-23 11:20:06 +03004547 !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
4548 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004549 return -EINVAL;
4550
4551 /* When you run into this, adjust the code below for the new flag */
4552 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
4553
4554 switch (statype) {
Thomas Pederseneef941e2013-03-04 13:06:11 -08004555 case CFG80211_STA_MESH_PEER_KERNEL:
4556 case CFG80211_STA_MESH_PEER_USER:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004557 /*
4558 * No ignoring the TDLS flag here -- the userspace mesh
4559 * code doesn't have the bug of including TDLS in the
4560 * mask everywhere.
4561 */
4562 if (params->sta_flags_mask &
4563 ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4564 BIT(NL80211_STA_FLAG_MFP) |
4565 BIT(NL80211_STA_FLAG_AUTHORIZED)))
4566 return -EINVAL;
4567 break;
4568 case CFG80211_STA_TDLS_PEER_SETUP:
4569 case CFG80211_STA_TDLS_PEER_ACTIVE:
4570 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
4571 return -EINVAL;
4572 /* ignore since it can't change */
4573 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4574 break;
4575 default:
4576 /* disallow mesh-specific things */
4577 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
4578 return -EINVAL;
4579 if (params->local_pm)
4580 return -EINVAL;
4581 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4582 return -EINVAL;
4583 }
4584
4585 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4586 statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
4587 /* TDLS can't be set, ... */
4588 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
4589 return -EINVAL;
4590 /*
4591 * ... but don't bother the driver with it. This works around
4592 * a hostapd/wpa_supplicant issue -- it always includes the
4593 * TLDS_PEER flag in the mask even for AP mode.
4594 */
4595 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4596 }
4597
Ayala Beker47edb112015-09-21 15:49:53 +03004598 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4599 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004600 /* reject other things that can't change */
4601 if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
4602 return -EINVAL;
4603 if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
4604 return -EINVAL;
4605 if (params->supported_rates)
4606 return -EINVAL;
4607 if (params->ext_capab || params->ht_capa || params->vht_capa)
4608 return -EINVAL;
4609 }
4610
Ayala Beker47edb112015-09-21 15:49:53 +03004611 if (statype != CFG80211_STA_AP_CLIENT &&
4612 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004613 if (params->vlan)
4614 return -EINVAL;
4615 }
4616
4617 switch (statype) {
4618 case CFG80211_STA_AP_MLME_CLIENT:
4619 /* Use this only for authorizing/unauthorizing a station */
4620 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4621 return -EOPNOTSUPP;
4622 break;
4623 case CFG80211_STA_AP_CLIENT:
Ayala Beker47edb112015-09-21 15:49:53 +03004624 case CFG80211_STA_AP_CLIENT_UNASSOC:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004625 /* accept only the listed bits */
4626 if (params->sta_flags_mask &
4627 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4628 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4629 BIT(NL80211_STA_FLAG_ASSOCIATED) |
4630 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4631 BIT(NL80211_STA_FLAG_WME) |
4632 BIT(NL80211_STA_FLAG_MFP)))
4633 return -EINVAL;
4634
4635 /* but authenticated/associated only if driver handles it */
4636 if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
4637 params->sta_flags_mask &
4638 (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4639 BIT(NL80211_STA_FLAG_ASSOCIATED)))
4640 return -EINVAL;
4641 break;
4642 case CFG80211_STA_IBSS:
4643 case CFG80211_STA_AP_STA:
4644 /* reject any changes other than AUTHORIZED */
4645 if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
4646 return -EINVAL;
4647 break;
4648 case CFG80211_STA_TDLS_PEER_SETUP:
4649 /* reject any changes other than AUTHORIZED or WME */
4650 if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4651 BIT(NL80211_STA_FLAG_WME)))
4652 return -EINVAL;
4653 /* force (at least) rates when authorizing */
4654 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
4655 !params->supported_rates)
4656 return -EINVAL;
4657 break;
4658 case CFG80211_STA_TDLS_PEER_ACTIVE:
4659 /* reject any changes */
4660 return -EINVAL;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004661 case CFG80211_STA_MESH_PEER_KERNEL:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004662 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4663 return -EINVAL;
4664 break;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004665 case CFG80211_STA_MESH_PEER_USER:
Chun-Yeow Yeoh42925042015-04-18 01:30:02 +08004666 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
4667 params->plink_action != NL80211_PLINK_ACTION_BLOCK)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004668 return -EINVAL;
4669 break;
4670 }
4671
Beni Lev06f7c882016-07-19 19:28:56 +03004672 /*
4673 * Older kernel versions ignored this attribute entirely, so don't
4674 * reject attempts to update it but mark it as unused instead so the
4675 * driver won't look at the data.
4676 */
4677 if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
4678 statype != CFG80211_STA_TDLS_PEER_SETUP)
4679 params->opmode_notif_used = false;
4680
Johannes Berg77ee7c82013-02-15 00:48:33 +01004681 return 0;
4682}
4683EXPORT_SYMBOL(cfg80211_check_station_change);
4684
Johannes Berg5727ef12007-12-19 02:03:34 +01004685/*
Felix Fietkauc258d2d2009-11-11 17:23:31 +01004686 * Get vlan interface making sure it is running and on the right wiphy.
Johannes Berg5727ef12007-12-19 02:03:34 +01004687 */
Johannes Berg80b99892011-11-18 16:23:01 +01004688static struct net_device *get_vlan(struct genl_info *info,
4689 struct cfg80211_registered_device *rdev)
Johannes Berg5727ef12007-12-19 02:03:34 +01004690{
Johannes Berg463d0182009-07-14 00:33:35 +02004691 struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
Johannes Berg80b99892011-11-18 16:23:01 +01004692 struct net_device *v;
4693 int ret;
Johannes Berg5727ef12007-12-19 02:03:34 +01004694
Johannes Berg80b99892011-11-18 16:23:01 +01004695 if (!vlanattr)
4696 return NULL;
4697
4698 v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
4699 if (!v)
4700 return ERR_PTR(-ENODEV);
4701
4702 if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
4703 ret = -EINVAL;
4704 goto error;
Johannes Berg5727ef12007-12-19 02:03:34 +01004705 }
Johannes Berg80b99892011-11-18 16:23:01 +01004706
Johannes Berg77ee7c82013-02-15 00:48:33 +01004707 if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
4708 v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4709 v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
4710 ret = -EINVAL;
4711 goto error;
4712 }
4713
Johannes Berg80b99892011-11-18 16:23:01 +01004714 if (!netif_running(v)) {
4715 ret = -ENETDOWN;
4716 goto error;
4717 }
4718
4719 return v;
4720 error:
4721 dev_put(v);
4722 return ERR_PTR(ret);
Johannes Berg5727ef12007-12-19 02:03:34 +01004723}
4724
Johannes Berg94e860f2014-01-20 23:58:15 +01004725static const struct nla_policy
4726nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
Jouni Malinendf881292013-02-14 21:10:54 +02004727 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
4728 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
4729};
4730
Johannes Bergff276692013-02-15 00:09:01 +01004731static int nl80211_parse_sta_wme(struct genl_info *info,
4732 struct station_parameters *params)
Jouni Malinendf881292013-02-14 21:10:54 +02004733{
Jouni Malinendf881292013-02-14 21:10:54 +02004734 struct nlattr *tb[NL80211_STA_WME_MAX + 1];
4735 struct nlattr *nla;
4736 int err;
4737
Jouni Malinendf881292013-02-14 21:10:54 +02004738 /* parse WME attributes if present */
4739 if (!info->attrs[NL80211_ATTR_STA_WME])
4740 return 0;
4741
4742 nla = info->attrs[NL80211_ATTR_STA_WME];
4743 err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
4744 nl80211_sta_wme_policy);
4745 if (err)
4746 return err;
4747
4748 if (tb[NL80211_STA_WME_UAPSD_QUEUES])
4749 params->uapsd_queues = nla_get_u8(
4750 tb[NL80211_STA_WME_UAPSD_QUEUES]);
4751 if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
4752 return -EINVAL;
4753
4754 if (tb[NL80211_STA_WME_MAX_SP])
4755 params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
4756
4757 if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
4758 return -EINVAL;
4759
4760 params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
4761
4762 return 0;
4763}
4764
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304765static int nl80211_parse_sta_channel_info(struct genl_info *info,
4766 struct station_parameters *params)
4767{
4768 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
4769 params->supported_channels =
4770 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4771 params->supported_channels_len =
4772 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4773 /*
4774 * Need to include at least one (first channel, number of
4775 * channels) tuple for each subband, and must have proper
4776 * tuples for the rest of the data as well.
4777 */
4778 if (params->supported_channels_len < 2)
4779 return -EINVAL;
4780 if (params->supported_channels_len % 2)
4781 return -EINVAL;
4782 }
4783
4784 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
4785 params->supported_oper_classes =
4786 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4787 params->supported_oper_classes_len =
4788 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4789 /*
4790 * The value of the Length field of the Supported Operating
4791 * Classes element is between 2 and 253.
4792 */
4793 if (params->supported_oper_classes_len < 2 ||
4794 params->supported_oper_classes_len > 253)
4795 return -EINVAL;
4796 }
4797 return 0;
4798}
4799
Johannes Bergff276692013-02-15 00:09:01 +01004800static int nl80211_set_station_tdls(struct genl_info *info,
4801 struct station_parameters *params)
4802{
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304803 int err;
Johannes Bergff276692013-02-15 00:09:01 +01004804 /* Dummy STA entry gets updated once the peer capabilities are known */
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004805 if (info->attrs[NL80211_ATTR_PEER_AID])
4806 params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Johannes Bergff276692013-02-15 00:09:01 +01004807 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
4808 params->ht_capa =
4809 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
4810 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
4811 params->vht_capa =
4812 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
4813
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304814 err = nl80211_parse_sta_channel_info(info, params);
4815 if (err)
4816 return err;
4817
Johannes Bergff276692013-02-15 00:09:01 +01004818 return nl80211_parse_sta_wme(info, params);
4819}
4820
Johannes Berg5727ef12007-12-19 02:03:34 +01004821static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
4822{
Johannes Berg4c476992010-10-04 21:36:35 +02004823 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02004824 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004825 struct station_parameters params;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004826 u8 *mac_addr;
4827 int err;
Johannes Berg5727ef12007-12-19 02:03:34 +01004828
4829 memset(&params, 0, sizeof(params));
4830
Johannes Berg77ee7c82013-02-15 00:48:33 +01004831 if (!rdev->ops->change_station)
4832 return -EOPNOTSUPP;
4833
Ayala Bekere4208422015-10-23 11:20:06 +03004834 /*
4835 * AID and listen_interval properties can be set only for unassociated
4836 * station. Include these parameters here and will check them in
4837 * cfg80211_check_station_change().
4838 */
Ayala Bekera9bc31e2015-11-26 16:26:12 +01004839 if (info->attrs[NL80211_ATTR_STA_AID])
4840 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Ayala Bekere4208422015-10-23 11:20:06 +03004841
4842 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4843 params.listen_interval =
4844 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
4845 else
4846 params.listen_interval = -1;
Johannes Berg5727ef12007-12-19 02:03:34 +01004847
Ayala Beker17b94242016-03-17 15:41:38 +02004848 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
4849 u8 tmp;
4850
4851 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
4852 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
4853 return -EINVAL;
4854
4855 params.support_p2p_ps = tmp;
4856 } else {
4857 params.support_p2p_ps = -1;
4858 }
4859
Johannes Berg5727ef12007-12-19 02:03:34 +01004860 if (!info->attrs[NL80211_ATTR_MAC])
4861 return -EINVAL;
4862
4863 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4864
4865 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
4866 params.supported_rates =
4867 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4868 params.supported_rates_len =
4869 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4870 }
4871
Jouni Malinen9d62a982013-02-14 21:10:13 +02004872 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
4873 params.capability =
4874 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
4875 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
4876 }
4877
4878 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
4879 params.ext_capab =
4880 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4881 params.ext_capab_len =
4882 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4883 }
4884
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004885 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01004886 return -EINVAL;
4887
Johannes Bergf8bacc22013-02-14 23:27:01 +01004888 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004889 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004890 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
4891 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
4892 return -EINVAL;
4893 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004894
Johannes Bergf8bacc22013-02-14 23:27:01 +01004895 if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
Javier Cardona9c3990a2011-05-03 16:57:11 -07004896 params.plink_state =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004897 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
4898 if (params.plink_state >= NUM_NL80211_PLINK_STATES)
4899 return -EINVAL;
Masashi Honma7d27a0b2016-07-01 10:19:34 +09004900 if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) {
4901 params.peer_aid = nla_get_u16(
4902 info->attrs[NL80211_ATTR_MESH_PEER_AID]);
4903 if (params.peer_aid > IEEE80211_MAX_AID)
4904 return -EINVAL;
4905 }
Johannes Bergf8bacc22013-02-14 23:27:01 +01004906 params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
4907 }
Javier Cardona9c3990a2011-05-03 16:57:11 -07004908
Marco Porsch3b1c5a52013-01-07 16:04:52 +01004909 if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
4910 enum nl80211_mesh_power_mode pm = nla_get_u32(
4911 info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
4912
4913 if (pm <= NL80211_MESH_POWER_UNKNOWN ||
4914 pm > NL80211_MESH_POWER_MAX)
4915 return -EINVAL;
4916
4917 params.local_pm = pm;
4918 }
4919
Beni Lev06f7c882016-07-19 19:28:56 +03004920 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
4921 params.opmode_notif_used = true;
4922 params.opmode_notif =
4923 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
4924 }
4925
Johannes Berg77ee7c82013-02-15 00:48:33 +01004926 /* Include parameters for TDLS peer (will check later) */
4927 err = nl80211_set_station_tdls(info, &params);
4928 if (err)
4929 return err;
4930
4931 params.vlan = get_vlan(info, rdev);
4932 if (IS_ERR(params.vlan))
4933 return PTR_ERR(params.vlan);
4934
Johannes Berga97f4422009-06-18 17:23:43 +02004935 switch (dev->ieee80211_ptr->iftype) {
4936 case NL80211_IFTYPE_AP:
4937 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02004938 case NL80211_IFTYPE_P2P_GO:
Johannes Berg074ac8d2010-09-16 14:58:22 +02004939 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berga97f4422009-06-18 17:23:43 +02004940 case NL80211_IFTYPE_STATION:
Antonio Quartulli267335d2012-01-31 20:25:47 +01004941 case NL80211_IFTYPE_ADHOC:
Johannes Berga97f4422009-06-18 17:23:43 +02004942 case NL80211_IFTYPE_MESH_POINT:
Johannes Berga97f4422009-06-18 17:23:43 +02004943 break;
4944 default:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004945 err = -EOPNOTSUPP;
4946 goto out_put_vlan;
Johannes Berg034d6552009-05-27 10:35:29 +02004947 }
4948
Johannes Berg77ee7c82013-02-15 00:48:33 +01004949 /* driver will call cfg80211_check_station_change() */
Hila Gonene35e4d22012-06-27 17:19:42 +03004950 err = rdev_change_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01004951
Johannes Berg77ee7c82013-02-15 00:48:33 +01004952 out_put_vlan:
Johannes Berg5727ef12007-12-19 02:03:34 +01004953 if (params.vlan)
4954 dev_put(params.vlan);
Johannes Berg3b858752009-03-12 09:55:09 +01004955
Johannes Berg5727ef12007-12-19 02:03:34 +01004956 return err;
4957}
4958
4959static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
4960{
Johannes Berg4c476992010-10-04 21:36:35 +02004961 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg5727ef12007-12-19 02:03:34 +01004962 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004963 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004964 struct station_parameters params;
4965 u8 *mac_addr = NULL;
Johannes Bergbda95eb2015-11-26 16:26:13 +01004966 u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4967 BIT(NL80211_STA_FLAG_ASSOCIATED);
Johannes Berg5727ef12007-12-19 02:03:34 +01004968
4969 memset(&params, 0, sizeof(params));
4970
Johannes Berg984c3112013-02-14 23:43:25 +01004971 if (!rdev->ops->add_station)
4972 return -EOPNOTSUPP;
4973
Johannes Berg5727ef12007-12-19 02:03:34 +01004974 if (!info->attrs[NL80211_ATTR_MAC])
4975 return -EINVAL;
4976
Johannes Berg5727ef12007-12-19 02:03:34 +01004977 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4978 return -EINVAL;
4979
4980 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
4981 return -EINVAL;
4982
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004983 if (!info->attrs[NL80211_ATTR_STA_AID] &&
4984 !info->attrs[NL80211_ATTR_PEER_AID])
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02004985 return -EINVAL;
4986
Johannes Berg5727ef12007-12-19 02:03:34 +01004987 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4988 params.supported_rates =
4989 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4990 params.supported_rates_len =
4991 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4992 params.listen_interval =
4993 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02004994
Ayala Beker17b94242016-03-17 15:41:38 +02004995 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
4996 u8 tmp;
4997
4998 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
4999 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
5000 return -EINVAL;
5001
5002 params.support_p2p_ps = tmp;
5003 } else {
5004 /*
5005 * if not specified, assume it's supported for P2P GO interface,
5006 * and is NOT supported for AP interface
5007 */
5008 params.support_p2p_ps =
5009 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
5010 }
5011
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005012 if (info->attrs[NL80211_ATTR_PEER_AID])
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005013 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005014 else
5015 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02005016 if (!params.aid || params.aid > IEEE80211_MAX_AID)
5017 return -EINVAL;
Johannes Berg51b50fb2009-05-24 16:42:30 +02005018
Jouni Malinen9d62a982013-02-14 21:10:13 +02005019 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5020 params.capability =
5021 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5022 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5023 }
5024
5025 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5026 params.ext_capab =
5027 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5028 params.ext_capab_len =
5029 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5030 }
5031
Jouni Malinen36aedc92008-08-25 11:58:58 +03005032 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
5033 params.ht_capa =
5034 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005035
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +00005036 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
5037 params.vht_capa =
5038 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
5039
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +01005040 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
5041 params.opmode_notif_used = true;
5042 params.opmode_notif =
5043 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
5044 }
5045
Johannes Bergf8bacc22013-02-14 23:27:01 +01005046 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Javier Cardona96b78df2011-04-07 15:08:33 -07005047 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005048 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5049 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
5050 return -EINVAL;
5051 }
Javier Cardona96b78df2011-04-07 15:08:33 -07005052
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305053 err = nl80211_parse_sta_channel_info(info, &params);
5054 if (err)
5055 return err;
5056
Johannes Bergff276692013-02-15 00:09:01 +01005057 err = nl80211_parse_sta_wme(info, &params);
5058 if (err)
5059 return err;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005060
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005061 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01005062 return -EINVAL;
5063
Johannes Berg496fcc22015-03-12 08:53:27 +02005064 /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
5065 * as userspace might just pass through the capabilities from the IEs
5066 * directly, rather than enforcing this restriction and returning an
5067 * error in this case.
5068 */
5069 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
5070 params.ht_capa = NULL;
5071 params.vht_capa = NULL;
5072 }
5073
Johannes Berg77ee7c82013-02-15 00:48:33 +01005074 /* When you run into this, adjust the code below for the new flag */
5075 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5076
Johannes Bergbdd90d52011-12-14 12:20:27 +01005077 switch (dev->ieee80211_ptr->iftype) {
5078 case NL80211_IFTYPE_AP:
5079 case NL80211_IFTYPE_AP_VLAN:
5080 case NL80211_IFTYPE_P2P_GO:
Johannes Berg984c3112013-02-14 23:43:25 +01005081 /* ignore WME attributes if iface/sta is not capable */
5082 if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
5083 !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
5084 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005085
Johannes Bergbdd90d52011-12-14 12:20:27 +01005086 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005087 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5088 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005089 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005090 /* but don't bother the driver with it */
5091 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
Eliad Pellerc75786c2011-08-23 14:37:46 +03005092
Johannes Bergd582cff2012-10-26 17:53:44 +02005093 /* allow authenticated/associated only if driver handles it */
5094 if (!(rdev->wiphy.features &
5095 NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
Johannes Bergbda95eb2015-11-26 16:26:13 +01005096 params.sta_flags_mask & auth_assoc)
Johannes Bergd582cff2012-10-26 17:53:44 +02005097 return -EINVAL;
5098
Johannes Bergbda95eb2015-11-26 16:26:13 +01005099 /* Older userspace, or userspace wanting to be compatible with
5100 * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
5101 * and assoc flags in the mask, but assumes the station will be
5102 * added as associated anyway since this was the required driver
5103 * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
5104 * introduced.
5105 * In order to not bother drivers with this quirk in the API
5106 * set the flags in both the mask and set for new stations in
5107 * this case.
5108 */
5109 if (!(params.sta_flags_mask & auth_assoc)) {
5110 params.sta_flags_mask |= auth_assoc;
5111 params.sta_flags_set |= auth_assoc;
5112 }
5113
Johannes Bergbdd90d52011-12-14 12:20:27 +01005114 /* must be last in here for error handling */
5115 params.vlan = get_vlan(info, rdev);
5116 if (IS_ERR(params.vlan))
5117 return PTR_ERR(params.vlan);
5118 break;
5119 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg984c3112013-02-14 23:43:25 +01005120 /* ignore uAPSD data */
5121 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5122
Johannes Bergd582cff2012-10-26 17:53:44 +02005123 /* associated is disallowed */
5124 if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
5125 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005126 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005127 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5128 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005129 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005130 break;
5131 case NL80211_IFTYPE_STATION:
Johannes Berg93d08f02013-03-04 09:29:46 +01005132 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg984c3112013-02-14 23:43:25 +01005133 /* ignore uAPSD data */
5134 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5135
Johannes Berg77ee7c82013-02-15 00:48:33 +01005136 /* these are disallowed */
5137 if (params.sta_flags_mask &
5138 (BIT(NL80211_STA_FLAG_ASSOCIATED) |
5139 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
Johannes Bergd582cff2012-10-26 17:53:44 +02005140 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005141 /* Only TDLS peers can be added */
5142 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
5143 return -EINVAL;
5144 /* Can only add if TDLS ... */
5145 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
5146 return -EOPNOTSUPP;
5147 /* ... with external setup is supported */
5148 if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
5149 return -EOPNOTSUPP;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005150 /*
5151 * Older wpa_supplicant versions always mark the TDLS peer
5152 * as authorized, but it shouldn't yet be.
5153 */
5154 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
Johannes Bergbdd90d52011-12-14 12:20:27 +01005155 break;
5156 default:
5157 return -EOPNOTSUPP;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005158 }
5159
Johannes Bergbdd90d52011-12-14 12:20:27 +01005160 /* be aware of params.vlan when changing code here */
Johannes Berg5727ef12007-12-19 02:03:34 +01005161
Hila Gonene35e4d22012-06-27 17:19:42 +03005162 err = rdev_add_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005163
Johannes Berg5727ef12007-12-19 02:03:34 +01005164 if (params.vlan)
5165 dev_put(params.vlan);
Johannes Berg5727ef12007-12-19 02:03:34 +01005166 return err;
5167}
5168
5169static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
5170{
Johannes Berg4c476992010-10-04 21:36:35 +02005171 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5172 struct net_device *dev = info->user_ptr[1];
Jouni Malinen89c771e2014-10-10 20:52:40 +03005173 struct station_del_parameters params;
5174
5175 memset(&params, 0, sizeof(params));
Johannes Berg5727ef12007-12-19 02:03:34 +01005176
5177 if (info->attrs[NL80211_ATTR_MAC])
Jouni Malinen89c771e2014-10-10 20:52:40 +03005178 params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005179
Johannes Berge80cf852009-05-11 14:43:13 +02005180 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Marco Porschd5d9de02010-03-30 10:00:16 +02005181 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
Johannes Berg074ac8d2010-09-16 14:58:22 +02005182 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
Johannes Berg4c476992010-10-04 21:36:35 +02005183 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5184 return -EINVAL;
Johannes Berge80cf852009-05-11 14:43:13 +02005185
Johannes Berg4c476992010-10-04 21:36:35 +02005186 if (!rdev->ops->del_station)
5187 return -EOPNOTSUPP;
Johannes Berg5727ef12007-12-19 02:03:34 +01005188
Jouni Malinen98856862014-10-20 13:20:45 +03005189 if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
5190 params.subtype =
5191 nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
5192 if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
5193 params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
5194 return -EINVAL;
5195 } else {
5196 /* Default to Deauthentication frame */
5197 params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
5198 }
5199
5200 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
5201 params.reason_code =
5202 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
5203 if (params.reason_code == 0)
5204 return -EINVAL; /* 0 is reserved */
5205 } else {
5206 /* Default to reason code 2 */
5207 params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
5208 }
5209
Jouni Malinen89c771e2014-10-10 20:52:40 +03005210 return rdev_del_station(rdev, dev, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005211}
5212
Eric W. Biederman15e47302012-09-07 20:12:54 +00005213static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005214 int flags, struct net_device *dev,
5215 u8 *dst, u8 *next_hop,
5216 struct mpath_info *pinfo)
5217{
5218 void *hdr;
5219 struct nlattr *pinfoattr;
5220
Henning Rogge1ef4c852014-11-04 16:14:58 +01005221 hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005222 if (!hdr)
5223 return -1;
5224
David S. Miller9360ffd2012-03-29 04:41:26 -04005225 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5226 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
5227 nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
5228 nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
5229 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02005230
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005231 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
5232 if (!pinfoattr)
5233 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005234 if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
5235 nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
5236 pinfo->frame_qlen))
5237 goto nla_put_failure;
5238 if (((pinfo->filled & MPATH_INFO_SN) &&
5239 nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
5240 ((pinfo->filled & MPATH_INFO_METRIC) &&
5241 nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
5242 pinfo->metric)) ||
5243 ((pinfo->filled & MPATH_INFO_EXPTIME) &&
5244 nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
5245 pinfo->exptime)) ||
5246 ((pinfo->filled & MPATH_INFO_FLAGS) &&
5247 nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
5248 pinfo->flags)) ||
5249 ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
5250 nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
5251 pinfo->discovery_timeout)) ||
5252 ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
5253 nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
5254 pinfo->discovery_retries)))
5255 goto nla_put_failure;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005256
5257 nla_nest_end(msg, pinfoattr);
5258
Johannes Berg053c0952015-01-16 22:09:00 +01005259 genlmsg_end(msg, hdr);
5260 return 0;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005261
5262 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07005263 genlmsg_cancel(msg, hdr);
5264 return -EMSGSIZE;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005265}
5266
5267static int nl80211_dump_mpath(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005268 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005269{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005270 struct mpath_info pinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005271 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02005272 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005273 u8 dst[ETH_ALEN];
5274 u8 next_hop[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02005275 int path_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005276 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005277
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005278 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02005279 if (err)
5280 return err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005281
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005282 if (!rdev->ops->dump_mpath) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005283 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005284 goto out_err;
5285 }
5286
Johannes Berg97990a02013-04-19 01:02:55 +02005287 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005288 err = -EOPNOTSUPP;
Roel Kluin0448b5f2009-08-22 21:15:49 +02005289 goto out_err;
Jouni Malineneec60b02009-03-20 21:21:19 +02005290 }
5291
Johannes Bergbba95fe2008-07-29 13:22:51 +02005292 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005293 err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
Johannes Berg97990a02013-04-19 01:02:55 +02005294 next_hop, &pinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005295 if (err == -ENOENT)
5296 break;
5297 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01005298 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005299
Eric W. Biederman15e47302012-09-07 20:12:54 +00005300 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005301 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg97990a02013-04-19 01:02:55 +02005302 wdev->netdev, dst, next_hop,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005303 &pinfo) < 0)
5304 goto out;
5305
5306 path_idx++;
5307 }
5308
Johannes Bergbba95fe2008-07-29 13:22:51 +02005309 out:
Johannes Berg97990a02013-04-19 01:02:55 +02005310 cb->args[2] = path_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005311 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005312 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005313 nl80211_finish_wdev_dump(rdev);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005314 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005315}
5316
5317static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
5318{
Johannes Berg4c476992010-10-04 21:36:35 +02005319 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005320 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02005321 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005322 struct mpath_info pinfo;
5323 struct sk_buff *msg;
5324 u8 *dst = NULL;
5325 u8 next_hop[ETH_ALEN];
5326
5327 memset(&pinfo, 0, sizeof(pinfo));
5328
5329 if (!info->attrs[NL80211_ATTR_MAC])
5330 return -EINVAL;
5331
5332 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5333
Johannes Berg4c476992010-10-04 21:36:35 +02005334 if (!rdev->ops->get_mpath)
5335 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005336
Johannes Berg4c476992010-10-04 21:36:35 +02005337 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5338 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005339
Hila Gonene35e4d22012-06-27 17:19:42 +03005340 err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005341 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005342 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005343
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005344 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005345 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02005346 return -ENOMEM;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005347
Eric W. Biederman15e47302012-09-07 20:12:54 +00005348 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg4c476992010-10-04 21:36:35 +02005349 dev, dst, next_hop, &pinfo) < 0) {
5350 nlmsg_free(msg);
5351 return -ENOBUFS;
5352 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005353
Johannes Berg4c476992010-10-04 21:36:35 +02005354 return genlmsg_reply(msg, info);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005355}
5356
5357static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
5358{
Johannes Berg4c476992010-10-04 21:36:35 +02005359 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5360 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005361 u8 *dst = NULL;
5362 u8 *next_hop = NULL;
5363
5364 if (!info->attrs[NL80211_ATTR_MAC])
5365 return -EINVAL;
5366
5367 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5368 return -EINVAL;
5369
5370 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5371 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5372
Johannes Berg4c476992010-10-04 21:36:35 +02005373 if (!rdev->ops->change_mpath)
5374 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005375
Johannes Berg4c476992010-10-04 21:36:35 +02005376 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5377 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005378
Hila Gonene35e4d22012-06-27 17:19:42 +03005379 return rdev_change_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005380}
Johannes Berg4c476992010-10-04 21:36:35 +02005381
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005382static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
5383{
Johannes Berg4c476992010-10-04 21:36:35 +02005384 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5385 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005386 u8 *dst = NULL;
5387 u8 *next_hop = NULL;
5388
5389 if (!info->attrs[NL80211_ATTR_MAC])
5390 return -EINVAL;
5391
5392 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5393 return -EINVAL;
5394
5395 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5396 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5397
Johannes Berg4c476992010-10-04 21:36:35 +02005398 if (!rdev->ops->add_mpath)
5399 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005400
Johannes Berg4c476992010-10-04 21:36:35 +02005401 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5402 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005403
Hila Gonene35e4d22012-06-27 17:19:42 +03005404 return rdev_add_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005405}
5406
5407static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
5408{
Johannes Berg4c476992010-10-04 21:36:35 +02005409 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5410 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005411 u8 *dst = NULL;
5412
5413 if (info->attrs[NL80211_ATTR_MAC])
5414 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5415
Johannes Berg4c476992010-10-04 21:36:35 +02005416 if (!rdev->ops->del_mpath)
5417 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005418
Hila Gonene35e4d22012-06-27 17:19:42 +03005419 return rdev_del_mpath(rdev, dev, dst);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005420}
5421
Henning Rogge66be7d22014-09-12 08:58:49 +02005422static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
5423{
5424 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5425 int err;
5426 struct net_device *dev = info->user_ptr[1];
5427 struct mpath_info pinfo;
5428 struct sk_buff *msg;
5429 u8 *dst = NULL;
5430 u8 mpp[ETH_ALEN];
5431
5432 memset(&pinfo, 0, sizeof(pinfo));
5433
5434 if (!info->attrs[NL80211_ATTR_MAC])
5435 return -EINVAL;
5436
5437 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5438
5439 if (!rdev->ops->get_mpp)
5440 return -EOPNOTSUPP;
5441
5442 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5443 return -EOPNOTSUPP;
5444
5445 err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
5446 if (err)
5447 return err;
5448
5449 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5450 if (!msg)
5451 return -ENOMEM;
5452
5453 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
5454 dev, dst, mpp, &pinfo) < 0) {
5455 nlmsg_free(msg);
5456 return -ENOBUFS;
5457 }
5458
5459 return genlmsg_reply(msg, info);
5460}
5461
5462static int nl80211_dump_mpp(struct sk_buff *skb,
5463 struct netlink_callback *cb)
5464{
5465 struct mpath_info pinfo;
5466 struct cfg80211_registered_device *rdev;
5467 struct wireless_dev *wdev;
5468 u8 dst[ETH_ALEN];
5469 u8 mpp[ETH_ALEN];
5470 int path_idx = cb->args[2];
5471 int err;
5472
5473 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
5474 if (err)
5475 return err;
5476
5477 if (!rdev->ops->dump_mpp) {
5478 err = -EOPNOTSUPP;
5479 goto out_err;
5480 }
5481
5482 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
5483 err = -EOPNOTSUPP;
5484 goto out_err;
5485 }
5486
5487 while (1) {
5488 err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
5489 mpp, &pinfo);
5490 if (err == -ENOENT)
5491 break;
5492 if (err)
5493 goto out_err;
5494
5495 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
5496 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5497 wdev->netdev, dst, mpp,
5498 &pinfo) < 0)
5499 goto out;
5500
5501 path_idx++;
5502 }
5503
5504 out:
5505 cb->args[2] = path_idx;
5506 err = skb->len;
5507 out_err:
5508 nl80211_finish_wdev_dump(rdev);
5509 return err;
5510}
5511
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005512static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
5513{
Johannes Berg4c476992010-10-04 21:36:35 +02005514 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5515 struct net_device *dev = info->user_ptr[1];
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005516 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005517 struct bss_parameters params;
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005518 int err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005519
5520 memset(&params, 0, sizeof(params));
5521 /* default to not changing parameters */
5522 params.use_cts_prot = -1;
5523 params.use_short_preamble = -1;
5524 params.use_short_slot_time = -1;
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005525 params.ap_isolate = -1;
Helmut Schaa50b12f52010-11-19 12:40:25 +01005526 params.ht_opmode = -1;
Johannes Berg53cabad2012-11-14 15:17:28 +01005527 params.p2p_ctwindow = -1;
5528 params.p2p_opp_ps = -1;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005529
5530 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
5531 params.use_cts_prot =
5532 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
5533 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
5534 params.use_short_preamble =
5535 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
5536 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
5537 params.use_short_slot_time =
5538 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
Jouni Malinen90c97a02008-10-30 16:59:22 +02005539 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
5540 params.basic_rates =
5541 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5542 params.basic_rates_len =
5543 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5544 }
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005545 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
5546 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
Helmut Schaa50b12f52010-11-19 12:40:25 +01005547 if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
5548 params.ht_opmode =
5549 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005550
Johannes Berg53cabad2012-11-14 15:17:28 +01005551 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
5552 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5553 return -EINVAL;
5554 params.p2p_ctwindow =
5555 nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
5556 if (params.p2p_ctwindow < 0)
5557 return -EINVAL;
5558 if (params.p2p_ctwindow != 0 &&
5559 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
5560 return -EINVAL;
5561 }
5562
5563 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
5564 u8 tmp;
5565
5566 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5567 return -EINVAL;
5568 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
5569 if (tmp > 1)
5570 return -EINVAL;
5571 params.p2p_opp_ps = tmp;
5572 if (params.p2p_opp_ps &&
5573 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
5574 return -EINVAL;
5575 }
5576
Johannes Berg4c476992010-10-04 21:36:35 +02005577 if (!rdev->ops->change_bss)
5578 return -EOPNOTSUPP;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005579
Johannes Berg074ac8d2010-09-16 14:58:22 +02005580 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berg4c476992010-10-04 21:36:35 +02005581 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5582 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005583
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005584 wdev_lock(wdev);
5585 err = rdev_change_bss(rdev, dev, &params);
5586 wdev_unlock(wdev);
5587
5588 return err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005589}
5590
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005591static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
5592{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005593 char *data = NULL;
Ilan peer05050752015-03-04 00:32:06 -05005594 bool is_indoor;
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005595 enum nl80211_user_reg_hint_type user_reg_hint_type;
Ilan peer05050752015-03-04 00:32:06 -05005596 u32 owner_nlportid;
5597
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005598 /*
5599 * You should only get this when cfg80211 hasn't yet initialized
5600 * completely when built-in to the kernel right between the time
5601 * window between nl80211_init() and regulatory_init(), if that is
5602 * even possible.
5603 */
Johannes Berg458f4f92012-12-06 15:47:38 +01005604 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
Luis R. Rodriguezfe33eb32009-02-21 00:04:30 -05005605 return -EINPROGRESS;
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005606
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005607 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
5608 user_reg_hint_type =
5609 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
5610 else
5611 user_reg_hint_type = NL80211_USER_REG_HINT_USER;
5612
5613 switch (user_reg_hint_type) {
5614 case NL80211_USER_REG_HINT_USER:
5615 case NL80211_USER_REG_HINT_CELL_BASE:
Ilan Peer52616f22014-02-25 16:26:00 +02005616 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
5617 return -EINVAL;
5618
5619 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
5620 return regulatory_hint_user(data, user_reg_hint_type);
5621 case NL80211_USER_REG_HINT_INDOOR:
Ilan peer05050752015-03-04 00:32:06 -05005622 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
5623 owner_nlportid = info->snd_portid;
5624 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
5625 } else {
5626 owner_nlportid = 0;
5627 is_indoor = true;
5628 }
5629
5630 return regulatory_hint_indoor(is_indoor, owner_nlportid);
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005631 default:
5632 return -EINVAL;
5633 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005634}
5635
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005636static int nl80211_get_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01005637 struct genl_info *info)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005638{
Johannes Berg4c476992010-10-04 21:36:35 +02005639 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02005640 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01005641 struct wireless_dev *wdev = dev->ieee80211_ptr;
5642 struct mesh_config cur_params;
5643 int err = 0;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005644 void *hdr;
5645 struct nlattr *pinfoattr;
5646 struct sk_buff *msg;
5647
Johannes Berg29cbe682010-12-03 09:20:44 +01005648 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
5649 return -EOPNOTSUPP;
5650
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005651 if (!rdev->ops->get_mesh_config)
Johannes Berg4c476992010-10-04 21:36:35 +02005652 return -EOPNOTSUPP;
Jouni Malinenf3f92582009-03-20 17:57:36 +02005653
Johannes Berg29cbe682010-12-03 09:20:44 +01005654 wdev_lock(wdev);
5655 /* If not connected, get default parameters */
5656 if (!wdev->mesh_id_len)
5657 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
5658 else
Hila Gonene35e4d22012-06-27 17:19:42 +03005659 err = rdev_get_mesh_config(rdev, dev, &cur_params);
Johannes Berg29cbe682010-12-03 09:20:44 +01005660 wdev_unlock(wdev);
5661
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005662 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005663 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005664
5665 /* Draw up a netlink message to send back */
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005666 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02005667 if (!msg)
5668 return -ENOMEM;
Eric W. Biederman15e47302012-09-07 20:12:54 +00005669 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005670 NL80211_CMD_GET_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005671 if (!hdr)
Julia Lawallefe1cf02011-01-28 15:17:11 +01005672 goto out;
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005673 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005674 if (!pinfoattr)
5675 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005676 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5677 nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
5678 cur_params.dot11MeshRetryTimeout) ||
5679 nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
5680 cur_params.dot11MeshConfirmTimeout) ||
5681 nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
5682 cur_params.dot11MeshHoldingTimeout) ||
5683 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
5684 cur_params.dot11MeshMaxPeerLinks) ||
5685 nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
5686 cur_params.dot11MeshMaxRetries) ||
5687 nla_put_u8(msg, NL80211_MESHCONF_TTL,
5688 cur_params.dot11MeshTTL) ||
5689 nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
5690 cur_params.element_ttl) ||
5691 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
5692 cur_params.auto_open_plinks) ||
John W. Linville7eab0f62012-04-12 14:25:14 -04005693 nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
5694 cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04005695 nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
5696 cur_params.dot11MeshHWMPmaxPREQretries) ||
5697 nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
5698 cur_params.path_refresh_time) ||
5699 nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
5700 cur_params.min_discovery_timeout) ||
5701 nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
5702 cur_params.dot11MeshHWMPactivePathTimeout) ||
5703 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
5704 cur_params.dot11MeshHWMPpreqMinInterval) ||
5705 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
5706 cur_params.dot11MeshHWMPperrMinInterval) ||
5707 nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
5708 cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
5709 nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
5710 cur_params.dot11MeshHWMPRootMode) ||
5711 nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
5712 cur_params.dot11MeshHWMPRannInterval) ||
5713 nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
5714 cur_params.dot11MeshGateAnnouncementProtocol) ||
5715 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
5716 cur_params.dot11MeshForwarding) ||
5717 nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
Ashok Nagarajan70c33ea2012-04-30 14:20:32 -07005718 cur_params.rssi_threshold) ||
5719 nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005720 cur_params.ht_opmode) ||
5721 nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
5722 cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
5723 nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005724 cur_params.dot11MeshHWMProotInterval) ||
5725 nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005726 cur_params.dot11MeshHWMPconfirmationInterval) ||
5727 nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
5728 cur_params.power_mode) ||
5729 nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005730 cur_params.dot11MeshAwakeWindowDuration) ||
5731 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
5732 cur_params.plink_timeout))
David S. Miller9360ffd2012-03-29 04:41:26 -04005733 goto nla_put_failure;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005734 nla_nest_end(msg, pinfoattr);
5735 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02005736 return genlmsg_reply(msg, info);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005737
Johannes Berg3b858752009-03-12 09:55:09 +01005738 nla_put_failure:
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005739 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01005740 out:
Yuri Ershovd080e272010-06-29 15:08:07 +04005741 nlmsg_free(msg);
Johannes Berg4c476992010-10-04 21:36:35 +02005742 return -ENOBUFS;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005743}
5744
Alexey Dobriyanb54452b2010-02-18 08:14:31 +00005745static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005746 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
5747 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
5748 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
5749 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
5750 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
5751 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
Javier Cardona45904f22010-12-03 09:20:40 +01005752 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005753 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
Javier Cardonad299a1f2012-03-31 11:31:33 -07005754 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005755 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
5756 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
5757 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
5758 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
5759 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
Thomas Pedersendca7e942011-11-24 17:15:24 -08005760 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005761 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
Javier Cardona699403d2011-08-09 16:45:09 -07005762 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
Javier Cardona0507e152011-08-09 16:45:10 -07005763 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
Javier Cardona16dd7262011-08-09 16:45:11 -07005764 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
Chun-Yeow Yeoh94f90652012-01-21 01:02:16 +08005765 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005766 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
5767 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005768 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
5769 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005770 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005771 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
5772 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005773 [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005774};
5775
Javier Cardonac80d5452010-12-16 17:37:49 -08005776static const struct nla_policy
5777 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
Javier Cardonad299a1f2012-03-31 11:31:33 -07005778 [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
Javier Cardonac80d5452010-12-16 17:37:49 -08005779 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
5780 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
Javier Cardona15d5dda2011-04-07 15:08:28 -07005781 [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
Colleen Twitty6e16d902013-05-08 11:45:59 -07005782 [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08005783 [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
Javier Cardona581a8b02011-04-07 15:08:27 -07005784 [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005785 .len = IEEE80211_MAX_DATA_LEN },
Javier Cardonab130e5c2011-05-03 16:57:07 -07005786 [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
Javier Cardonac80d5452010-12-16 17:37:49 -08005787};
5788
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005789static int nl80211_check_bool(const struct nlattr *nla, u8 min, u8 max, bool *out)
5790{
5791 u8 val = nla_get_u8(nla);
5792 if (val < min || val > max)
5793 return -EINVAL;
5794 *out = val;
5795 return 0;
5796}
5797
5798static int nl80211_check_u8(const struct nlattr *nla, u8 min, u8 max, u8 *out)
5799{
5800 u8 val = nla_get_u8(nla);
5801 if (val < min || val > max)
5802 return -EINVAL;
5803 *out = val;
5804 return 0;
5805}
5806
5807static int nl80211_check_u16(const struct nlattr *nla, u16 min, u16 max, u16 *out)
5808{
5809 u16 val = nla_get_u16(nla);
5810 if (val < min || val > max)
5811 return -EINVAL;
5812 *out = val;
5813 return 0;
5814}
5815
5816static int nl80211_check_u32(const struct nlattr *nla, u32 min, u32 max, u32 *out)
5817{
5818 u32 val = nla_get_u32(nla);
5819 if (val < min || val > max)
5820 return -EINVAL;
5821 *out = val;
5822 return 0;
5823}
5824
5825static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *out)
5826{
5827 s32 val = nla_get_s32(nla);
5828 if (val < min || val > max)
5829 return -EINVAL;
5830 *out = val;
5831 return 0;
5832}
5833
Johannes Bergff9a71a2016-08-11 14:59:53 +02005834static int nl80211_check_power_mode(const struct nlattr *nla,
5835 enum nl80211_mesh_power_mode min,
5836 enum nl80211_mesh_power_mode max,
5837 enum nl80211_mesh_power_mode *out)
5838{
5839 u32 val = nla_get_u32(nla);
5840 if (val < min || val > max)
5841 return -EINVAL;
5842 *out = val;
5843 return 0;
5844}
5845
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005846static int nl80211_parse_mesh_config(struct genl_info *info,
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005847 struct mesh_config *cfg,
5848 u32 *mask_out)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005849{
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005850 struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005851 u32 mask = 0;
Masashi Honma97572352016-08-03 10:07:44 +09005852 u16 ht_opmode;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005853
Marco Porschea54fba2013-01-07 16:04:48 +01005854#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
5855do { \
5856 if (tb[attr]) { \
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005857 if (fn(tb[attr], min, max, &cfg->param)) \
Marco Porschea54fba2013-01-07 16:04:48 +01005858 return -EINVAL; \
Marco Porschea54fba2013-01-07 16:04:48 +01005859 mask |= (1 << (attr - 1)); \
5860 } \
5861} while (0)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005862
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005863 if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005864 return -EINVAL;
5865 if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005866 info->attrs[NL80211_ATTR_MESH_CONFIG],
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005867 nl80211_meshconf_params_policy))
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005868 return -EINVAL;
5869
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005870 /* This makes sure that there aren't more than 32 mesh config
5871 * parameters (otherwise our bitfield scheme would not work.) */
5872 BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
5873
5874 /* Fill in the params struct */
Marco Porschea54fba2013-01-07 16:04:48 +01005875 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005876 mask, NL80211_MESHCONF_RETRY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005877 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005878 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005879 mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005880 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005881 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005882 mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005883 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005884 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005885 mask, NL80211_MESHCONF_MAX_PEER_LINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005886 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005887 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005888 mask, NL80211_MESHCONF_MAX_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005889 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005890 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005891 mask, NL80211_MESHCONF_TTL, nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005892 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005893 mask, NL80211_MESHCONF_ELEMENT_TTL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005894 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005895 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005896 mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005897 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005898 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
5899 1, 255, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005900 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005901 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005902 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005903 mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005904 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005905 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005906 mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005907 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005908 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005909 mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005910 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005911 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
5912 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005913 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005914 nl80211_check_u32);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005915 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005916 1, 65535, mask,
5917 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005918 nl80211_check_u16);
Thomas Pedersendca7e942011-11-24 17:15:24 -08005919 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005920 1, 65535, mask,
5921 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005922 nl80211_check_u16);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005923 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005924 dot11MeshHWMPnetDiameterTraversalTime,
5925 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005926 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005927 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005928 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
5929 mask, NL80211_MESHCONF_HWMP_ROOTMODE,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005930 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005931 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
5932 mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005933 nl80211_check_u16);
Rui Paulo63c57232009-11-09 23:46:57 +00005934 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005935 dot11MeshGateAnnouncementProtocol, 0, 1,
5936 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005937 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005938 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005939 mask, NL80211_MESHCONF_FORWARDING,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005940 nl80211_check_bool);
Chun-Yeow Yeoh83374fe2013-07-11 18:24:03 +08005941 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005942 mask, NL80211_MESHCONF_RSSI_THRESHOLD,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005943 nl80211_check_s32);
Masashi Honma97572352016-08-03 10:07:44 +09005944 /*
5945 * Check HT operation mode based on
5946 * IEEE 802.11 2012 8.4.2.59 HT Operation element.
5947 */
5948 if (tb[NL80211_MESHCONF_HT_OPMODE]) {
5949 ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
5950
5951 if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
5952 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
5953 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5954 return -EINVAL;
5955
5956 if ((ht_opmode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) &&
5957 (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5958 return -EINVAL;
5959
5960 switch (ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION) {
5961 case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
5962 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
5963 if (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT)
5964 return -EINVAL;
5965 break;
5966 case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
5967 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
5968 if (!(ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5969 return -EINVAL;
5970 break;
5971 }
5972 cfg->ht_opmode = ht_opmode;
5973 }
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005974 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
Marco Porschea54fba2013-01-07 16:04:48 +01005975 1, 65535, mask,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005976 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005977 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005978 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005979 mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005980 nl80211_check_u16);
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005981 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005982 dot11MeshHWMPconfirmationInterval,
5983 1, 65535, mask,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005984 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005985 nl80211_check_u16);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005986 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
5987 NL80211_MESH_POWER_ACTIVE,
5988 NL80211_MESH_POWER_MAX,
5989 mask, NL80211_MESHCONF_POWER_MODE,
Johannes Bergff9a71a2016-08-11 14:59:53 +02005990 nl80211_check_power_mode);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005991 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
5992 0, 65535, mask,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005993 NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
Masashi Honma31f909a2015-02-24 22:42:16 +09005994 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005995 mask, NL80211_MESHCONF_PLINK_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005996 nl80211_check_u32);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005997 if (mask_out)
5998 *mask_out = mask;
Javier Cardonac80d5452010-12-16 17:37:49 -08005999
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006000 return 0;
6001
6002#undef FILL_IN_MESH_PARAM_IF_SET
6003}
6004
Javier Cardonac80d5452010-12-16 17:37:49 -08006005static int nl80211_parse_mesh_setup(struct genl_info *info,
6006 struct mesh_setup *setup)
6007{
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006008 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Javier Cardonac80d5452010-12-16 17:37:49 -08006009 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
6010
6011 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
6012 return -EINVAL;
6013 if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX,
6014 info->attrs[NL80211_ATTR_MESH_SETUP],
6015 nl80211_mesh_setup_params_policy))
6016 return -EINVAL;
6017
Javier Cardonad299a1f2012-03-31 11:31:33 -07006018 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
6019 setup->sync_method =
6020 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
6021 IEEE80211_SYNC_METHOD_VENDOR :
6022 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
6023
Javier Cardonac80d5452010-12-16 17:37:49 -08006024 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
6025 setup->path_sel_proto =
6026 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
6027 IEEE80211_PATH_PROTOCOL_VENDOR :
6028 IEEE80211_PATH_PROTOCOL_HWMP;
6029
6030 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
6031 setup->path_metric =
6032 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
6033 IEEE80211_PATH_METRIC_VENDOR :
6034 IEEE80211_PATH_METRIC_AIRTIME;
6035
Javier Cardona581a8b02011-04-07 15:08:27 -07006036 if (tb[NL80211_MESH_SETUP_IE]) {
Javier Cardonac80d5452010-12-16 17:37:49 -08006037 struct nlattr *ieattr =
Javier Cardona581a8b02011-04-07 15:08:27 -07006038 tb[NL80211_MESH_SETUP_IE];
Javier Cardonac80d5452010-12-16 17:37:49 -08006039 if (!is_valid_ie_attr(ieattr))
6040 return -EINVAL;
Javier Cardona581a8b02011-04-07 15:08:27 -07006041 setup->ie = nla_data(ieattr);
6042 setup->ie_len = nla_len(ieattr);
Javier Cardonac80d5452010-12-16 17:37:49 -08006043 }
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006044 if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
6045 !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
6046 return -EINVAL;
6047 setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
Javier Cardonab130e5c2011-05-03 16:57:07 -07006048 setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
6049 setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006050 if (setup->is_secure)
6051 setup->user_mpm = true;
Javier Cardonac80d5452010-12-16 17:37:49 -08006052
Colleen Twitty6e16d902013-05-08 11:45:59 -07006053 if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
6054 if (!setup->user_mpm)
6055 return -EINVAL;
6056 setup->auth_id =
6057 nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
6058 }
6059
Javier Cardonac80d5452010-12-16 17:37:49 -08006060 return 0;
6061}
6062
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006063static int nl80211_update_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01006064 struct genl_info *info)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006065{
6066 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6067 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01006068 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006069 struct mesh_config cfg;
6070 u32 mask;
6071 int err;
6072
Johannes Berg29cbe682010-12-03 09:20:44 +01006073 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6074 return -EOPNOTSUPP;
6075
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006076 if (!rdev->ops->update_mesh_config)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006077 return -EOPNOTSUPP;
6078
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006079 err = nl80211_parse_mesh_config(info, &cfg, &mask);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006080 if (err)
6081 return err;
6082
Johannes Berg29cbe682010-12-03 09:20:44 +01006083 wdev_lock(wdev);
6084 if (!wdev->mesh_id_len)
6085 err = -ENOLINK;
6086
6087 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03006088 err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01006089
6090 wdev_unlock(wdev);
6091
6092 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006093}
6094
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006095static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
6096 struct sk_buff *msg)
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006097{
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006098 struct nlattr *nl_reg_rules;
6099 unsigned int i;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006100
Johannes Berg458f4f92012-12-06 15:47:38 +01006101 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
6102 (regdom->dfs_region &&
6103 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006104 goto nla_put_failure;
Johannes Berg458f4f92012-12-06 15:47:38 +01006105
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006106 nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
6107 if (!nl_reg_rules)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006108 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006109
Johannes Berg458f4f92012-12-06 15:47:38 +01006110 for (i = 0; i < regdom->n_reg_rules; i++) {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006111 struct nlattr *nl_reg_rule;
6112 const struct ieee80211_reg_rule *reg_rule;
6113 const struct ieee80211_freq_range *freq_range;
6114 const struct ieee80211_power_rule *power_rule;
Janusz Dziedzic97524822014-01-30 09:52:20 +01006115 unsigned int max_bandwidth_khz;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006116
Johannes Berg458f4f92012-12-06 15:47:38 +01006117 reg_rule = &regdom->reg_rules[i];
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006118 freq_range = &reg_rule->freq_range;
6119 power_rule = &reg_rule->power_rule;
6120
6121 nl_reg_rule = nla_nest_start(msg, i);
6122 if (!nl_reg_rule)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006123 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006124
Janusz Dziedzic97524822014-01-30 09:52:20 +01006125 max_bandwidth_khz = freq_range->max_bandwidth_khz;
6126 if (!max_bandwidth_khz)
6127 max_bandwidth_khz = reg_get_max_bandwidth(regdom,
6128 reg_rule);
6129
David S. Miller9360ffd2012-03-29 04:41:26 -04006130 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
6131 reg_rule->flags) ||
6132 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
6133 freq_range->start_freq_khz) ||
6134 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
6135 freq_range->end_freq_khz) ||
6136 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
Janusz Dziedzic97524822014-01-30 09:52:20 +01006137 max_bandwidth_khz) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04006138 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
6139 power_rule->max_antenna_gain) ||
6140 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
Janusz Dziedzic089027e2014-02-21 19:46:12 +01006141 power_rule->max_eirp) ||
6142 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
6143 reg_rule->dfs_cac_ms))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006144 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006145
6146 nla_nest_end(msg, nl_reg_rule);
6147 }
6148
6149 nla_nest_end(msg, nl_reg_rules);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006150 return 0;
6151
6152nla_put_failure:
6153 return -EMSGSIZE;
6154}
6155
6156static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
6157{
6158 const struct ieee80211_regdomain *regdom = NULL;
6159 struct cfg80211_registered_device *rdev;
6160 struct wiphy *wiphy = NULL;
6161 struct sk_buff *msg;
6162 void *hdr;
6163
6164 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6165 if (!msg)
6166 return -ENOBUFS;
6167
6168 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
6169 NL80211_CMD_GET_REG);
6170 if (!hdr)
6171 goto put_failure;
6172
6173 if (info->attrs[NL80211_ATTR_WIPHY]) {
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006174 bool self_managed;
6175
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006176 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
6177 if (IS_ERR(rdev)) {
6178 nlmsg_free(msg);
6179 return PTR_ERR(rdev);
6180 }
6181
6182 wiphy = &rdev->wiphy;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006183 self_managed = wiphy->regulatory_flags &
6184 REGULATORY_WIPHY_SELF_MANAGED;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006185 regdom = get_wiphy_regdom(wiphy);
6186
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006187 /* a self-managed-reg device must have a private regdom */
6188 if (WARN_ON(!regdom && self_managed)) {
6189 nlmsg_free(msg);
6190 return -EINVAL;
6191 }
6192
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006193 if (regdom &&
6194 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6195 goto nla_put_failure;
6196 }
6197
6198 if (!wiphy && reg_last_request_cell_base() &&
6199 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6200 NL80211_USER_REG_HINT_CELL_BASE))
6201 goto nla_put_failure;
6202
6203 rcu_read_lock();
6204
6205 if (!regdom)
6206 regdom = rcu_dereference(cfg80211_regdomain);
6207
6208 if (nl80211_put_regdom(regdom, msg))
6209 goto nla_put_failure_rcu;
6210
6211 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006212
6213 genlmsg_end(msg, hdr);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006214 return genlmsg_reply(msg, info);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006215
Johannes Berg458f4f92012-12-06 15:47:38 +01006216nla_put_failure_rcu:
6217 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006218nla_put_failure:
6219 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01006220put_failure:
Yuri Ershovd080e272010-06-29 15:08:07 +04006221 nlmsg_free(msg);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006222 return -EMSGSIZE;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006223}
6224
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006225static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
6226 u32 seq, int flags, struct wiphy *wiphy,
6227 const struct ieee80211_regdomain *regdom)
6228{
6229 void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
6230 NL80211_CMD_GET_REG);
6231
6232 if (!hdr)
6233 return -1;
6234
6235 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
6236
6237 if (nl80211_put_regdom(regdom, msg))
6238 goto nla_put_failure;
6239
6240 if (!wiphy && reg_last_request_cell_base() &&
6241 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6242 NL80211_USER_REG_HINT_CELL_BASE))
6243 goto nla_put_failure;
6244
6245 if (wiphy &&
6246 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6247 goto nla_put_failure;
6248
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006249 if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
6250 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
6251 goto nla_put_failure;
6252
Johannes Berg053c0952015-01-16 22:09:00 +01006253 genlmsg_end(msg, hdr);
6254 return 0;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006255
6256nla_put_failure:
6257 genlmsg_cancel(msg, hdr);
6258 return -EMSGSIZE;
6259}
6260
6261static int nl80211_get_reg_dump(struct sk_buff *skb,
6262 struct netlink_callback *cb)
6263{
6264 const struct ieee80211_regdomain *regdom = NULL;
6265 struct cfg80211_registered_device *rdev;
6266 int err, reg_idx, start = cb->args[2];
6267
6268 rtnl_lock();
6269
6270 if (cfg80211_regdomain && start == 0) {
6271 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6272 NLM_F_MULTI, NULL,
6273 rtnl_dereference(cfg80211_regdomain));
6274 if (err < 0)
6275 goto out_err;
6276 }
6277
6278 /* the global regdom is idx 0 */
6279 reg_idx = 1;
6280 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
6281 regdom = get_wiphy_regdom(&rdev->wiphy);
6282 if (!regdom)
6283 continue;
6284
6285 if (++reg_idx <= start)
6286 continue;
6287
6288 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6289 NLM_F_MULTI, &rdev->wiphy, regdom);
6290 if (err < 0) {
6291 reg_idx--;
6292 break;
6293 }
6294 }
6295
6296 cb->args[2] = reg_idx;
6297 err = skb->len;
6298out_err:
6299 rtnl_unlock();
6300 return err;
6301}
6302
Johannes Bergb6863032015-10-15 09:25:18 +02006303#ifdef CONFIG_CFG80211_CRDA_SUPPORT
6304static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
6305 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
6306 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
6307 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
6308 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
6309 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
6310 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
6311 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
6312};
6313
6314static int parse_reg_rule(struct nlattr *tb[],
6315 struct ieee80211_reg_rule *reg_rule)
6316{
6317 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
6318 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
6319
6320 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
6321 return -EINVAL;
6322 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
6323 return -EINVAL;
6324 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
6325 return -EINVAL;
6326 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
6327 return -EINVAL;
6328 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
6329 return -EINVAL;
6330
6331 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
6332
6333 freq_range->start_freq_khz =
6334 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
6335 freq_range->end_freq_khz =
6336 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
6337 freq_range->max_bandwidth_khz =
6338 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
6339
6340 power_rule->max_eirp =
6341 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
6342
6343 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
6344 power_rule->max_antenna_gain =
6345 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
6346
6347 if (tb[NL80211_ATTR_DFS_CAC_TIME])
6348 reg_rule->dfs_cac_ms =
6349 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
6350
6351 return 0;
6352}
6353
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006354static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
6355{
6356 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
6357 struct nlattr *nl_reg_rule;
Johannes Bergea372c52014-11-28 14:54:31 +01006358 char *alpha2;
6359 int rem_reg_rules, r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006360 u32 num_rules = 0, rule_idx = 0, size_of_regd;
Luis R. Rodriguez4c7d3982013-11-13 18:54:02 +01006361 enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
Johannes Bergea372c52014-11-28 14:54:31 +01006362 struct ieee80211_regdomain *rd;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006363
6364 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
6365 return -EINVAL;
6366
6367 if (!info->attrs[NL80211_ATTR_REG_RULES])
6368 return -EINVAL;
6369
6370 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
6371
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006372 if (info->attrs[NL80211_ATTR_DFS_REGION])
6373 dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
6374
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006375 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006376 rem_reg_rules) {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006377 num_rules++;
6378 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
Luis R. Rodriguez4776c6e2009-05-13 17:04:39 -04006379 return -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006380 }
6381
Luis R. Rodrigueze4387682013-11-05 09:18:01 -08006382 if (!reg_is_valid_request(alpha2))
6383 return -EINVAL;
6384
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006385 size_of_regd = sizeof(struct ieee80211_regdomain) +
Johannes Berg1a919312012-12-03 17:21:11 +01006386 num_rules * sizeof(struct ieee80211_reg_rule);
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006387
6388 rd = kzalloc(size_of_regd, GFP_KERNEL);
Johannes Berg6913b492012-12-04 00:48:59 +01006389 if (!rd)
6390 return -ENOMEM;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006391
6392 rd->n_reg_rules = num_rules;
6393 rd->alpha2[0] = alpha2[0];
6394 rd->alpha2[1] = alpha2[1];
6395
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006396 /*
6397 * Disable DFS master mode if the DFS region was
6398 * not supported or known on this kernel.
6399 */
6400 if (reg_supported_dfs_region(dfs_region))
6401 rd->dfs_region = dfs_region;
6402
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006403 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006404 rem_reg_rules) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006405 r = nla_parse_nested(tb, NL80211_REG_RULE_ATTR_MAX,
6406 nl_reg_rule, reg_rule_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01006407 if (r)
6408 goto bad_reg;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006409 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
6410 if (r)
6411 goto bad_reg;
6412
6413 rule_idx++;
6414
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006415 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
6416 r = -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006417 goto bad_reg;
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006418 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006419 }
6420
Johannes Berg06627992016-06-09 10:40:09 +02006421 /* set_regdom takes ownership of rd */
6422 return set_regdom(rd, REGD_SOURCE_CRDA);
Johannes Bergd2372b32008-10-24 20:32:20 +02006423 bad_reg:
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006424 kfree(rd);
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006425 return r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006426}
Johannes Bergb6863032015-10-15 09:25:18 +02006427#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006428
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006429static int validate_scan_freqs(struct nlattr *freqs)
6430{
6431 struct nlattr *attr1, *attr2;
6432 int n_channels = 0, tmp1, tmp2;
6433
6434 nla_for_each_nested(attr1, freqs, tmp1) {
6435 n_channels++;
6436 /*
6437 * Some hardware has a limited channel list for
6438 * scanning, and it is pretty much nonsensical
6439 * to scan for a channel twice, so disallow that
6440 * and don't require drivers to check that the
6441 * channel list they get isn't longer than what
6442 * they can scan, as long as they can scan all
6443 * the channels they registered at once.
6444 */
6445 nla_for_each_nested(attr2, freqs, tmp2)
6446 if (attr1 != attr2 &&
6447 nla_get_u32(attr1) == nla_get_u32(attr2))
6448 return 0;
6449 }
6450
6451 return n_channels;
6452}
6453
Johannes Berg57fbcce2016-04-12 15:56:15 +02006454static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
Arend van Spriel38de03d2016-03-02 20:37:18 +01006455{
Johannes Berg57fbcce2016-04-12 15:56:15 +02006456 return b < NUM_NL80211_BANDS && wiphy->bands[b];
Arend van Spriel38de03d2016-03-02 20:37:18 +01006457}
6458
6459static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
6460 struct cfg80211_bss_selection *bss_select)
6461{
6462 struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
6463 struct nlattr *nest;
6464 int err;
6465 bool found = false;
6466 int i;
6467
6468 /* only process one nested attribute */
6469 nest = nla_data(nla);
6470 if (!nla_ok(nest, nla_len(nest)))
6471 return -EINVAL;
6472
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006473 err = nla_parse_nested(attr, NL80211_BSS_SELECT_ATTR_MAX, nest,
6474 nl80211_bss_select_policy);
Arend van Spriel38de03d2016-03-02 20:37:18 +01006475 if (err)
6476 return err;
6477
6478 /* only one attribute may be given */
6479 for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
6480 if (attr[i]) {
6481 if (found)
6482 return -EINVAL;
6483 found = true;
6484 }
6485 }
6486
6487 bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
6488
6489 if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
6490 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
6491
6492 if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
6493 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
6494 bss_select->param.band_pref =
6495 nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
6496 if (!is_band_valid(wiphy, bss_select->param.band_pref))
6497 return -EINVAL;
6498 }
6499
6500 if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
6501 struct nl80211_bss_select_rssi_adjust *adj_param;
6502
6503 adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
6504 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
6505 bss_select->param.adjust.band = adj_param->band;
6506 bss_select->param.adjust.delta = adj_param->delta;
6507 if (!is_band_valid(wiphy, bss_select->param.adjust.band))
6508 return -EINVAL;
6509 }
6510
6511 /* user-space did not provide behaviour attribute */
6512 if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
6513 return -EINVAL;
6514
6515 if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
6516 return -EINVAL;
6517
6518 return 0;
6519}
6520
Johannes Bergad2b26a2014-06-12 21:39:05 +02006521static int nl80211_parse_random_mac(struct nlattr **attrs,
6522 u8 *mac_addr, u8 *mac_addr_mask)
6523{
6524 int i;
6525
6526 if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
Joe Perchesd2beae12015-03-02 19:54:58 -08006527 eth_zero_addr(mac_addr);
6528 eth_zero_addr(mac_addr_mask);
Johannes Bergad2b26a2014-06-12 21:39:05 +02006529 mac_addr[0] = 0x2;
6530 mac_addr_mask[0] = 0x3;
6531
6532 return 0;
6533 }
6534
6535 /* need both or none */
6536 if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
6537 return -EINVAL;
6538
6539 memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
6540 memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
6541
6542 /* don't allow or configure an mcast address */
6543 if (!is_multicast_ether_addr(mac_addr_mask) ||
6544 is_multicast_ether_addr(mac_addr))
6545 return -EINVAL;
6546
6547 /*
6548 * allow users to pass a MAC address that has bits set outside
6549 * of the mask, but don't bother drivers with having to deal
6550 * with such bits
6551 */
6552 for (i = 0; i < ETH_ALEN; i++)
6553 mac_addr[i] &= mac_addr_mask[i];
6554
6555 return 0;
6556}
6557
Johannes Berg2a519312009-02-10 21:25:55 +01006558static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
6559{
Johannes Berg4c476992010-10-04 21:36:35 +02006560 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfd014282012-06-18 19:17:03 +02006561 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2a519312009-02-10 21:25:55 +01006562 struct cfg80211_scan_request *request;
Johannes Berg2a519312009-02-10 21:25:55 +01006563 struct nlattr *attr;
6564 struct wiphy *wiphy;
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006565 int err, tmp, n_ssids = 0, n_channels, i;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006566 size_t ie_len;
Johannes Berg2a519312009-02-10 21:25:55 +01006567
Johannes Bergf4a11bb2009-03-27 12:40:28 +01006568 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
6569 return -EINVAL;
6570
Johannes Berg79c97e92009-07-07 03:56:12 +02006571 wiphy = &rdev->wiphy;
Johannes Berg2a519312009-02-10 21:25:55 +01006572
Ayala Bekercb3b7d82016-09-20 17:31:13 +03006573 if (wdev->iftype == NL80211_IFTYPE_NAN)
6574 return -EOPNOTSUPP;
6575
Johannes Berg4c476992010-10-04 21:36:35 +02006576 if (!rdev->ops->scan)
6577 return -EOPNOTSUPP;
Johannes Berg2a519312009-02-10 21:25:55 +01006578
Johannes Bergf9d15d12014-01-22 11:14:19 +02006579 if (rdev->scan_req || rdev->scan_msg) {
Johannes Bergf9f47522013-03-19 15:04:07 +01006580 err = -EBUSY;
6581 goto unlock;
6582 }
Johannes Berg2a519312009-02-10 21:25:55 +01006583
6584 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006585 n_channels = validate_scan_freqs(
6586 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Johannes Bergf9f47522013-03-19 15:04:07 +01006587 if (!n_channels) {
6588 err = -EINVAL;
6589 goto unlock;
6590 }
Johannes Berg2a519312009-02-10 21:25:55 +01006591 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006592 n_channels = ieee80211_get_num_supported_channels(wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01006593 }
6594
6595 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
6596 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
6597 n_ssids++;
6598
Johannes Bergf9f47522013-03-19 15:04:07 +01006599 if (n_ssids > wiphy->max_scan_ssids) {
6600 err = -EINVAL;
6601 goto unlock;
6602 }
Johannes Berg2a519312009-02-10 21:25:55 +01006603
Jouni Malinen70692ad2009-02-16 19:39:13 +02006604 if (info->attrs[NL80211_ATTR_IE])
6605 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6606 else
6607 ie_len = 0;
6608
Johannes Bergf9f47522013-03-19 15:04:07 +01006609 if (ie_len > wiphy->max_scan_ie_len) {
6610 err = -EINVAL;
6611 goto unlock;
6612 }
Johannes Berg18a83652009-03-31 12:12:05 +02006613
Johannes Berg2a519312009-02-10 21:25:55 +01006614 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03006615 + sizeof(*request->ssids) * n_ssids
6616 + sizeof(*request->channels) * n_channels
Jouni Malinen70692ad2009-02-16 19:39:13 +02006617 + ie_len, GFP_KERNEL);
Johannes Bergf9f47522013-03-19 15:04:07 +01006618 if (!request) {
6619 err = -ENOMEM;
6620 goto unlock;
6621 }
Johannes Berg2a519312009-02-10 21:25:55 +01006622
Johannes Berg2a519312009-02-10 21:25:55 +01006623 if (n_ssids)
Johannes Berg5ba63532009-08-07 17:54:07 +02006624 request->ssids = (void *)&request->channels[n_channels];
Johannes Berg2a519312009-02-10 21:25:55 +01006625 request->n_ssids = n_ssids;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006626 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01006627 if (n_ssids)
Jouni Malinen70692ad2009-02-16 19:39:13 +02006628 request->ie = (void *)(request->ssids + n_ssids);
6629 else
6630 request->ie = (void *)(request->channels + n_channels);
6631 }
Johannes Berg2a519312009-02-10 21:25:55 +01006632
Johannes Berg584991d2009-11-02 13:32:03 +01006633 i = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01006634 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
6635 /* user specified, bail out if channel not found */
Johannes Berg2a519312009-02-10 21:25:55 +01006636 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
Johannes Berg584991d2009-11-02 13:32:03 +01006637 struct ieee80211_channel *chan;
6638
6639 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
6640
6641 if (!chan) {
Johannes Berg2a519312009-02-10 21:25:55 +01006642 err = -EINVAL;
6643 goto out_free;
6644 }
Johannes Berg584991d2009-11-02 13:32:03 +01006645
6646 /* ignore disabled channels */
6647 if (chan->flags & IEEE80211_CHAN_DISABLED)
6648 continue;
6649
6650 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006651 i++;
6652 }
6653 } else {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006654 enum nl80211_band band;
Johannes Berg34850ab2011-07-18 18:08:35 +02006655
Johannes Berg2a519312009-02-10 21:25:55 +01006656 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006657 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Johannes Berg2a519312009-02-10 21:25:55 +01006658 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07006659
Johannes Berg2a519312009-02-10 21:25:55 +01006660 if (!wiphy->bands[band])
6661 continue;
6662 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
Johannes Berg584991d2009-11-02 13:32:03 +01006663 struct ieee80211_channel *chan;
6664
6665 chan = &wiphy->bands[band]->channels[j];
6666
6667 if (chan->flags & IEEE80211_CHAN_DISABLED)
6668 continue;
6669
6670 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006671 i++;
6672 }
6673 }
6674 }
6675
Johannes Berg584991d2009-11-02 13:32:03 +01006676 if (!i) {
6677 err = -EINVAL;
6678 goto out_free;
6679 }
6680
6681 request->n_channels = i;
6682
Johannes Berg2a519312009-02-10 21:25:55 +01006683 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01006684 if (n_ssids) {
Johannes Berg2a519312009-02-10 21:25:55 +01006685 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03006686 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Johannes Berg2a519312009-02-10 21:25:55 +01006687 err = -EINVAL;
6688 goto out_free;
6689 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03006690 request->ssids[i].ssid_len = nla_len(attr);
Johannes Berg2a519312009-02-10 21:25:55 +01006691 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
Johannes Berg2a519312009-02-10 21:25:55 +01006692 i++;
6693 }
6694 }
6695
Jouni Malinen70692ad2009-02-16 19:39:13 +02006696 if (info->attrs[NL80211_ATTR_IE]) {
6697 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Johannes Bergde95a54b2009-04-01 11:58:36 +02006698 memcpy((void *)request->ie,
6699 nla_data(info->attrs[NL80211_ATTR_IE]),
Jouni Malinen70692ad2009-02-16 19:39:13 +02006700 request->ie_len);
6701 }
6702
Johannes Berg57fbcce2016-04-12 15:56:15 +02006703 for (i = 0; i < NUM_NL80211_BANDS; i++)
Johannes Berga401d2b2011-07-20 00:52:16 +02006704 if (wiphy->bands[i])
6705 request->rates[i] =
6706 (1 << wiphy->bands[i]->n_bitrates) - 1;
Johannes Berg34850ab2011-07-18 18:08:35 +02006707
6708 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
6709 nla_for_each_nested(attr,
6710 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
6711 tmp) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006712 enum nl80211_band band = nla_type(attr);
Johannes Berg34850ab2011-07-18 18:08:35 +02006713
Johannes Berg57fbcce2016-04-12 15:56:15 +02006714 if (band < 0 || band >= NUM_NL80211_BANDS) {
Johannes Berg34850ab2011-07-18 18:08:35 +02006715 err = -EINVAL;
6716 goto out_free;
6717 }
Felix Fietkau1b09cd82013-11-20 19:40:41 +01006718
6719 if (!wiphy->bands[band])
6720 continue;
6721
Johannes Berg34850ab2011-07-18 18:08:35 +02006722 err = ieee80211_get_ratemask(wiphy->bands[band],
6723 nla_data(attr),
6724 nla_len(attr),
6725 &request->rates[band]);
6726 if (err)
6727 goto out_free;
6728 }
6729 }
6730
Avraham Stern1d762502016-07-05 17:10:13 +03006731 if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
6732 if (!wiphy_ext_feature_isset(wiphy,
6733 NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
6734 err = -EOPNOTSUPP;
6735 goto out_free;
6736 }
6737
6738 request->duration =
6739 nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
6740 request->duration_mandatory =
6741 nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
6742 }
6743
Sam Leffler46856bb2012-10-11 21:03:32 -07006744 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
Sam Lefflered4737712012-10-11 21:03:31 -07006745 request->flags = nla_get_u32(
6746 info->attrs[NL80211_ATTR_SCAN_FLAGS]);
Johannes Berg00c3a6e2013-10-26 17:14:38 +02006747 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
6748 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
Sam Leffler46856bb2012-10-11 21:03:32 -07006749 err = -EOPNOTSUPP;
6750 goto out_free;
6751 }
Johannes Bergad2b26a2014-06-12 21:39:05 +02006752
6753 if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
6754 if (!(wiphy->features &
6755 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) {
6756 err = -EOPNOTSUPP;
6757 goto out_free;
6758 }
6759
6760 if (wdev->current_bss) {
6761 err = -EOPNOTSUPP;
6762 goto out_free;
6763 }
6764
6765 err = nl80211_parse_random_mac(info->attrs,
6766 request->mac_addr,
6767 request->mac_addr_mask);
6768 if (err)
6769 goto out_free;
6770 }
Sam Leffler46856bb2012-10-11 21:03:32 -07006771 }
Sam Lefflered4737712012-10-11 21:03:31 -07006772
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05306773 request->no_cck =
6774 nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
6775
Vamsi Krishna2fa436b2016-12-02 23:59:08 +02006776 /* Initial implementation used NL80211_ATTR_MAC to set the specific
6777 * BSSID to scan for. This was problematic because that same attribute
6778 * was already used for another purpose (local random MAC address). The
6779 * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
6780 * compatibility with older userspace components, also use the
6781 * NL80211_ATTR_MAC value here if it can be determined to be used for
6782 * the specific BSSID use case instead of the random MAC address
6783 * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
6784 */
6785 if (info->attrs[NL80211_ATTR_BSSID])
6786 memcpy(request->bssid,
6787 nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
6788 else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
6789 info->attrs[NL80211_ATTR_MAC])
Jouni Malinen818965d2016-02-26 22:12:47 +02006790 memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
6791 ETH_ALEN);
6792 else
6793 eth_broadcast_addr(request->bssid);
6794
Johannes Bergfd014282012-06-18 19:17:03 +02006795 request->wdev = wdev;
Johannes Berg79c97e92009-07-07 03:56:12 +02006796 request->wiphy = &rdev->wiphy;
Sam Leffler15d60302012-10-11 21:03:34 -07006797 request->scan_start = jiffies;
Johannes Berg2a519312009-02-10 21:25:55 +01006798
Johannes Berg79c97e92009-07-07 03:56:12 +02006799 rdev->scan_req = request;
Hila Gonene35e4d22012-06-27 17:19:42 +03006800 err = rdev_scan(rdev, request);
Johannes Berg2a519312009-02-10 21:25:55 +01006801
Johannes Berg463d0182009-07-14 00:33:35 +02006802 if (!err) {
Johannes Bergfd014282012-06-18 19:17:03 +02006803 nl80211_send_scan_start(rdev, wdev);
6804 if (wdev->netdev)
6805 dev_hold(wdev->netdev);
Johannes Berg4c476992010-10-04 21:36:35 +02006806 } else {
Johannes Berg2a519312009-02-10 21:25:55 +01006807 out_free:
Johannes Berg79c97e92009-07-07 03:56:12 +02006808 rdev->scan_req = NULL;
Johannes Berg2a519312009-02-10 21:25:55 +01006809 kfree(request);
6810 }
Johannes Berg3b858752009-03-12 09:55:09 +01006811
Johannes Bergf9f47522013-03-19 15:04:07 +01006812 unlock:
Johannes Berg2a519312009-02-10 21:25:55 +01006813 return err;
6814}
6815
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +05306816static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
6817{
6818 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6819 struct wireless_dev *wdev = info->user_ptr[1];
6820
6821 if (!rdev->ops->abort_scan)
6822 return -EOPNOTSUPP;
6823
6824 if (rdev->scan_msg)
6825 return 0;
6826
6827 if (!rdev->scan_req)
6828 return -ENOENT;
6829
6830 rdev_abort_scan(rdev, wdev);
6831 return 0;
6832}
6833
Avraham Stern3b06d272015-10-12 09:51:34 +03006834static int
6835nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
6836 struct cfg80211_sched_scan_request *request,
6837 struct nlattr **attrs)
6838{
6839 int tmp, err, i = 0;
6840 struct nlattr *attr;
6841
6842 if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
6843 u32 interval;
6844
6845 /*
6846 * If scan plans are not specified,
Arend Van Spriel5a88de52016-11-17 09:02:40 +00006847 * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
Avraham Stern3b06d272015-10-12 09:51:34 +03006848 * case one scan plan will be set with the specified scan
6849 * interval and infinite number of iterations.
6850 */
Avraham Stern3b06d272015-10-12 09:51:34 +03006851 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
6852 if (!interval)
6853 return -EINVAL;
6854
6855 request->scan_plans[0].interval =
6856 DIV_ROUND_UP(interval, MSEC_PER_SEC);
6857 if (!request->scan_plans[0].interval)
6858 return -EINVAL;
6859
6860 if (request->scan_plans[0].interval >
6861 wiphy->max_sched_scan_plan_interval)
6862 request->scan_plans[0].interval =
6863 wiphy->max_sched_scan_plan_interval;
6864
6865 return 0;
6866 }
6867
6868 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
6869 struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
6870
6871 if (WARN_ON(i >= n_plans))
6872 return -EINVAL;
6873
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006874 err = nla_parse_nested(plan, NL80211_SCHED_SCAN_PLAN_MAX,
6875 attr, nl80211_plan_policy);
Avraham Stern3b06d272015-10-12 09:51:34 +03006876 if (err)
6877 return err;
6878
6879 if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
6880 return -EINVAL;
6881
6882 request->scan_plans[i].interval =
6883 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
6884 if (!request->scan_plans[i].interval ||
6885 request->scan_plans[i].interval >
6886 wiphy->max_sched_scan_plan_interval)
6887 return -EINVAL;
6888
6889 if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
6890 request->scan_plans[i].iterations =
6891 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
6892 if (!request->scan_plans[i].iterations ||
6893 (request->scan_plans[i].iterations >
6894 wiphy->max_sched_scan_plan_iterations))
6895 return -EINVAL;
6896 } else if (i < n_plans - 1) {
6897 /*
6898 * All scan plans but the last one must specify
6899 * a finite number of iterations
6900 */
6901 return -EINVAL;
6902 }
6903
6904 i++;
6905 }
6906
6907 /*
6908 * The last scan plan must not specify the number of
6909 * iterations, it is supposed to run infinitely
6910 */
6911 if (request->scan_plans[n_plans - 1].iterations)
6912 return -EINVAL;
6913
6914 return 0;
6915}
6916
Luciano Coelho256da022014-11-10 16:13:46 +02006917static struct cfg80211_sched_scan_request *
Johannes Bergad2b26a2014-06-12 21:39:05 +02006918nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00006919 struct nlattr **attrs, int max_match_sets)
Luciano Coelho807f8a82011-05-11 17:09:35 +03006920{
6921 struct cfg80211_sched_scan_request *request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006922 struct nlattr *attr;
Avraham Stern3b06d272015-10-12 09:51:34 +03006923 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02006924 enum nl80211_band band;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006925 size_t ie_len;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006926 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
Johannes Bergea73cbc2014-01-24 10:53:53 +01006927 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006928
Luciano Coelho256da022014-11-10 16:13:46 +02006929 if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
6930 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006931
Luciano Coelho256da022014-11-10 16:13:46 +02006932 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03006933 n_channels = validate_scan_freqs(
Luciano Coelho256da022014-11-10 16:13:46 +02006934 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006935 if (!n_channels)
Luciano Coelho256da022014-11-10 16:13:46 +02006936 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006937 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006938 n_channels = ieee80211_get_num_supported_channels(wiphy);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006939 }
6940
Luciano Coelho256da022014-11-10 16:13:46 +02006941 if (attrs[NL80211_ATTR_SCAN_SSIDS])
6942 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03006943 tmp)
6944 n_ssids++;
6945
Luciano Coelho93b6aa62011-07-13 14:57:28 +03006946 if (n_ssids > wiphy->max_sched_scan_ssids)
Luciano Coelho256da022014-11-10 16:13:46 +02006947 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006948
Johannes Bergea73cbc2014-01-24 10:53:53 +01006949 /*
6950 * First, count the number of 'real' matchsets. Due to an issue with
6951 * the old implementation, matchsets containing only the RSSI attribute
6952 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
6953 * RSSI for all matchsets, rather than their own matchset for reporting
6954 * all APs with a strong RSSI. This is needed to be compatible with
6955 * older userspace that treated a matchset with only the RSSI as the
6956 * global RSSI for all other matchsets - if there are other matchsets.
6957 */
Luciano Coelho256da022014-11-10 16:13:46 +02006958 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006959 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02006960 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Johannes Bergea73cbc2014-01-24 10:53:53 +01006961 tmp) {
6962 struct nlattr *rssi;
6963
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006964 err = nla_parse_nested(tb,
6965 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
6966 attr, nl80211_match_policy);
Johannes Bergea73cbc2014-01-24 10:53:53 +01006967 if (err)
Luciano Coelho256da022014-11-10 16:13:46 +02006968 return ERR_PTR(err);
Johannes Bergea73cbc2014-01-24 10:53:53 +01006969 /* add other standalone attributes here */
6970 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
6971 n_match_sets++;
6972 continue;
6973 }
6974 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
6975 if (rssi)
6976 default_match_rssi = nla_get_s32(rssi);
6977 }
6978 }
6979
6980 /* However, if there's no other matchset, add the RSSI one */
6981 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
6982 n_match_sets = 1;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006983
Arend Van Sprielaad1e812017-01-27 12:27:44 +00006984 if (n_match_sets > max_match_sets)
Luciano Coelho256da022014-11-10 16:13:46 +02006985 return ERR_PTR(-EINVAL);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006986
Luciano Coelho256da022014-11-10 16:13:46 +02006987 if (attrs[NL80211_ATTR_IE])
6988 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006989 else
6990 ie_len = 0;
6991
Luciano Coelho5a865ba2011-07-13 14:57:29 +03006992 if (ie_len > wiphy->max_sched_scan_ie_len)
Luciano Coelho256da022014-11-10 16:13:46 +02006993 return ERR_PTR(-EINVAL);
Luciano Coelhoc10841c2011-06-30 08:32:41 +03006994
Avraham Stern3b06d272015-10-12 09:51:34 +03006995 if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
6996 /*
6997 * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
6998 * each scan plan already specifies its own interval
6999 */
7000 if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7001 return ERR_PTR(-EINVAL);
7002
7003 nla_for_each_nested(attr,
7004 attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
7005 n_plans++;
7006 } else {
7007 /*
7008 * The scan interval attribute is kept for backward
7009 * compatibility. If no scan plans are specified and sched scan
7010 * interval is specified, one scan plan will be set with this
7011 * scan interval and infinite number of iterations.
7012 */
7013 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7014 return ERR_PTR(-EINVAL);
7015
7016 n_plans = 1;
7017 }
7018
7019 if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
7020 return ERR_PTR(-EINVAL);
7021
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007022 if (!wiphy_ext_feature_isset(
7023 wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
7024 (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
7025 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
7026 return ERR_PTR(-EINVAL);
7027
Luciano Coelho807f8a82011-05-11 17:09:35 +03007028 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007029 + sizeof(*request->ssids) * n_ssids
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007030 + sizeof(*request->match_sets) * n_match_sets
Avraham Stern3b06d272015-10-12 09:51:34 +03007031 + sizeof(*request->scan_plans) * n_plans
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007032 + sizeof(*request->channels) * n_channels
Luciano Coelho807f8a82011-05-11 17:09:35 +03007033 + ie_len, GFP_KERNEL);
Luciano Coelho256da022014-11-10 16:13:46 +02007034 if (!request)
7035 return ERR_PTR(-ENOMEM);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007036
7037 if (n_ssids)
7038 request->ssids = (void *)&request->channels[n_channels];
7039 request->n_ssids = n_ssids;
7040 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01007041 if (n_ssids)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007042 request->ie = (void *)(request->ssids + n_ssids);
7043 else
7044 request->ie = (void *)(request->channels + n_channels);
7045 }
7046
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007047 if (n_match_sets) {
7048 if (request->ie)
7049 request->match_sets = (void *)(request->ie + ie_len);
Johannes Berg13874e42015-01-23 11:25:20 +01007050 else if (n_ssids)
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007051 request->match_sets =
7052 (void *)(request->ssids + n_ssids);
7053 else
7054 request->match_sets =
7055 (void *)(request->channels + n_channels);
7056 }
7057 request->n_match_sets = n_match_sets;
7058
Avraham Stern3b06d272015-10-12 09:51:34 +03007059 if (n_match_sets)
7060 request->scan_plans = (void *)(request->match_sets +
7061 n_match_sets);
7062 else if (request->ie)
7063 request->scan_plans = (void *)(request->ie + ie_len);
7064 else if (n_ssids)
7065 request->scan_plans = (void *)(request->ssids + n_ssids);
7066 else
7067 request->scan_plans = (void *)(request->channels + n_channels);
7068
7069 request->n_scan_plans = n_plans;
7070
Luciano Coelho807f8a82011-05-11 17:09:35 +03007071 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007072 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007073 /* user specified, bail out if channel not found */
7074 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007075 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007076 tmp) {
7077 struct ieee80211_channel *chan;
7078
7079 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
7080
7081 if (!chan) {
7082 err = -EINVAL;
7083 goto out_free;
7084 }
7085
7086 /* ignore disabled channels */
7087 if (chan->flags & IEEE80211_CHAN_DISABLED)
7088 continue;
7089
7090 request->channels[i] = chan;
7091 i++;
7092 }
7093 } else {
7094 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007095 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007096 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007097
Luciano Coelho807f8a82011-05-11 17:09:35 +03007098 if (!wiphy->bands[band])
7099 continue;
7100 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
7101 struct ieee80211_channel *chan;
7102
7103 chan = &wiphy->bands[band]->channels[j];
7104
7105 if (chan->flags & IEEE80211_CHAN_DISABLED)
7106 continue;
7107
7108 request->channels[i] = chan;
7109 i++;
7110 }
7111 }
7112 }
7113
7114 if (!i) {
7115 err = -EINVAL;
7116 goto out_free;
7117 }
7118
7119 request->n_channels = i;
7120
7121 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01007122 if (n_ssids) {
Luciano Coelho256da022014-11-10 16:13:46 +02007123 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007124 tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03007125 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007126 err = -EINVAL;
7127 goto out_free;
7128 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03007129 request->ssids[i].ssid_len = nla_len(attr);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007130 memcpy(request->ssids[i].ssid, nla_data(attr),
7131 nla_len(attr));
Luciano Coelho807f8a82011-05-11 17:09:35 +03007132 i++;
7133 }
7134 }
7135
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007136 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007137 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007138 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007139 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007140 tmp) {
Thomas Pedersen88e920b2012-06-21 11:09:54 -07007141 struct nlattr *ssid, *rssi;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007142
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007143 err = nla_parse_nested(tb,
7144 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
7145 attr, nl80211_match_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01007146 if (err)
7147 goto out_free;
Johannes Berg4a4ab0d2012-06-13 11:17:11 +02007148 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007149 if (ssid) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01007150 if (WARN_ON(i >= n_match_sets)) {
7151 /* this indicates a programming error,
7152 * the loop above should have verified
7153 * things properly
7154 */
7155 err = -EINVAL;
7156 goto out_free;
7157 }
7158
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007159 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
7160 err = -EINVAL;
7161 goto out_free;
7162 }
7163 memcpy(request->match_sets[i].ssid.ssid,
7164 nla_data(ssid), nla_len(ssid));
7165 request->match_sets[i].ssid.ssid_len =
7166 nla_len(ssid);
Kirtika Ruchandani56ab3642016-05-29 19:54:10 -07007167 /* special attribute - old implementation w/a */
Johannes Bergea73cbc2014-01-24 10:53:53 +01007168 request->match_sets[i].rssi_thold =
7169 default_match_rssi;
7170 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7171 if (rssi)
7172 request->match_sets[i].rssi_thold =
7173 nla_get_s32(rssi);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007174 }
7175 i++;
7176 }
Johannes Bergea73cbc2014-01-24 10:53:53 +01007177
7178 /* there was no other matchset, so the RSSI one is alone */
Luciano Coelhof89f46c2014-12-01 11:32:09 +02007179 if (i == 0 && n_match_sets)
Johannes Bergea73cbc2014-01-24 10:53:53 +01007180 request->match_sets[0].rssi_thold = default_match_rssi;
7181
7182 request->min_rssi_thold = INT_MAX;
7183 for (i = 0; i < n_match_sets; i++)
7184 request->min_rssi_thold =
7185 min(request->match_sets[i].rssi_thold,
7186 request->min_rssi_thold);
7187 } else {
7188 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007189 }
7190
Johannes Berg9900e482014-02-04 21:01:25 +01007191 if (ie_len) {
7192 request->ie_len = ie_len;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007193 memcpy((void *)request->ie,
Luciano Coelho256da022014-11-10 16:13:46 +02007194 nla_data(attrs[NL80211_ATTR_IE]),
Luciano Coelho807f8a82011-05-11 17:09:35 +03007195 request->ie_len);
7196 }
7197
Luciano Coelho256da022014-11-10 16:13:46 +02007198 if (attrs[NL80211_ATTR_SCAN_FLAGS]) {
Sam Lefflered4737712012-10-11 21:03:31 -07007199 request->flags = nla_get_u32(
Luciano Coelho256da022014-11-10 16:13:46 +02007200 attrs[NL80211_ATTR_SCAN_FLAGS]);
Johannes Berg00c3a6e2013-10-26 17:14:38 +02007201 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
7202 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
Sam Leffler46856bb2012-10-11 21:03:32 -07007203 err = -EOPNOTSUPP;
7204 goto out_free;
7205 }
Johannes Bergad2b26a2014-06-12 21:39:05 +02007206
7207 if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
7208 u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7209
7210 if (!wdev) /* must be net-detect */
7211 flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7212
7213 if (!(wiphy->features & flg)) {
7214 err = -EOPNOTSUPP;
7215 goto out_free;
7216 }
7217
7218 if (wdev && wdev->current_bss) {
7219 err = -EOPNOTSUPP;
7220 goto out_free;
7221 }
7222
7223 err = nl80211_parse_random_mac(attrs, request->mac_addr,
7224 request->mac_addr_mask);
7225 if (err)
7226 goto out_free;
7227 }
Sam Leffler46856bb2012-10-11 21:03:32 -07007228 }
Sam Lefflered4737712012-10-11 21:03:31 -07007229
Luciano Coelho9c748932015-01-16 16:04:09 +02007230 if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
7231 request->delay =
7232 nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
7233
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007234 if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
7235 request->relative_rssi = nla_get_s8(
7236 attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
7237 request->relative_rssi_set = true;
7238 }
7239
7240 if (request->relative_rssi_set &&
7241 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
7242 struct nl80211_bss_select_rssi_adjust *rssi_adjust;
7243
7244 rssi_adjust = nla_data(
7245 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
7246 request->rssi_adjust.band = rssi_adjust->band;
7247 request->rssi_adjust.delta = rssi_adjust->delta;
7248 if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
7249 err = -EINVAL;
7250 goto out_free;
7251 }
7252 }
7253
Avraham Stern3b06d272015-10-12 09:51:34 +03007254 err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
7255 if (err)
7256 goto out_free;
7257
Sam Leffler15d60302012-10-11 21:03:34 -07007258 request->scan_start = jiffies;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007259
Luciano Coelho256da022014-11-10 16:13:46 +02007260 return request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007261
7262out_free:
7263 kfree(request);
Luciano Coelho256da022014-11-10 16:13:46 +02007264 return ERR_PTR(err);
7265}
7266
7267static int nl80211_start_sched_scan(struct sk_buff *skb,
7268 struct genl_info *info)
7269{
7270 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7271 struct net_device *dev = info->user_ptr[1];
Johannes Bergad2b26a2014-06-12 21:39:05 +02007272 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007273 struct cfg80211_sched_scan_request *sched_scan_req;
Luciano Coelho256da022014-11-10 16:13:46 +02007274 int err;
7275
7276 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
7277 !rdev->ops->sched_scan_start)
7278 return -EOPNOTSUPP;
7279
7280 if (rdev->sched_scan_req)
7281 return -EINPROGRESS;
7282
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007283 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007284 info->attrs,
7285 rdev->wiphy.max_match_sets);
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007286
7287 err = PTR_ERR_OR_ZERO(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007288 if (err)
7289 goto out_err;
7290
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007291 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007292 if (err)
7293 goto out_free;
7294
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007295 sched_scan_req->dev = dev;
7296 sched_scan_req->wiphy = &rdev->wiphy;
7297
Jukka Rissanen93a1e862014-12-15 13:25:39 +02007298 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
7299 sched_scan_req->owner_nlportid = info->snd_portid;
7300
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007301 rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007302
7303 nl80211_send_sched_scan(rdev, dev,
7304 NL80211_CMD_START_SCHED_SCAN);
7305 return 0;
7306
7307out_free:
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007308 kfree(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007309out_err:
Luciano Coelho807f8a82011-05-11 17:09:35 +03007310 return err;
7311}
7312
7313static int nl80211_stop_sched_scan(struct sk_buff *skb,
7314 struct genl_info *info)
7315{
7316 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7317
7318 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
7319 !rdev->ops->sched_scan_stop)
7320 return -EOPNOTSUPP;
7321
Johannes Berg5fe231e2013-05-08 21:45:15 +02007322 return __cfg80211_stop_sched_scan(rdev, false);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007323}
7324
Simon Wunderlich04f39042013-02-08 18:16:19 +01007325static int nl80211_start_radar_detection(struct sk_buff *skb,
7326 struct genl_info *info)
7327{
7328 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7329 struct net_device *dev = info->user_ptr[1];
7330 struct wireless_dev *wdev = dev->ieee80211_ptr;
7331 struct cfg80211_chan_def chandef;
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007332 enum nl80211_dfs_regions dfs_region;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007333 unsigned int cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007334 int err;
7335
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007336 dfs_region = reg_get_dfs_region(wdev->wiphy);
7337 if (dfs_region == NL80211_DFS_UNSET)
7338 return -EINVAL;
7339
Simon Wunderlich04f39042013-02-08 18:16:19 +01007340 err = nl80211_parse_chandef(rdev, info, &chandef);
7341 if (err)
7342 return err;
7343
Simon Wunderlichff311bc2013-09-03 19:43:18 +02007344 if (netif_carrier_ok(dev))
7345 return -EBUSY;
7346
Simon Wunderlich04f39042013-02-08 18:16:19 +01007347 if (wdev->cac_started)
7348 return -EBUSY;
7349
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007350 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
Luciano Coelho00ec75f2014-05-15 13:05:39 +03007351 wdev->iftype);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007352 if (err < 0)
7353 return err;
7354
7355 if (err == 0)
7356 return -EINVAL;
7357
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +01007358 if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
Simon Wunderlich04f39042013-02-08 18:16:19 +01007359 return -EINVAL;
7360
7361 if (!rdev->ops->start_radar_detection)
7362 return -EOPNOTSUPP;
7363
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007364 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
7365 if (WARN_ON(!cac_time_ms))
7366 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
7367
Ilan Peera1056b1b2015-10-22 22:27:46 +03007368 err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007369 if (!err) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01007370 wdev->chandef = chandef;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007371 wdev->cac_started = true;
7372 wdev->cac_start_time = jiffies;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007373 wdev->cac_time_ms = cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007374 }
Simon Wunderlich04f39042013-02-08 18:16:19 +01007375 return err;
7376}
7377
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007378static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
7379{
7380 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7381 struct net_device *dev = info->user_ptr[1];
7382 struct wireless_dev *wdev = dev->ieee80211_ptr;
7383 struct cfg80211_csa_settings params;
7384 /* csa_attrs is defined static to avoid waste of stack size - this
7385 * function is called under RTNL lock, so this should not be a problem.
7386 */
7387 static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007388 int err;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007389 bool need_new_beacon = false;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007390 int len, i;
Luciano Coelho252e07c2014-10-08 09:48:34 +03007391 u32 cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007392
7393 if (!rdev->ops->channel_switch ||
7394 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
7395 return -EOPNOTSUPP;
7396
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007397 switch (dev->ieee80211_ptr->iftype) {
7398 case NL80211_IFTYPE_AP:
7399 case NL80211_IFTYPE_P2P_GO:
7400 need_new_beacon = true;
7401
7402 /* useless if AP is not running */
7403 if (!wdev->beacon_interval)
Johannes Berg1ff79df2014-01-22 10:05:27 +01007404 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007405 break;
7406 case NL80211_IFTYPE_ADHOC:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007407 if (!wdev->ssid_len)
7408 return -ENOTCONN;
7409 break;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07007410 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007411 if (!wdev->mesh_id_len)
7412 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007413 break;
7414 default:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007415 return -EOPNOTSUPP;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007416 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007417
7418 memset(&params, 0, sizeof(params));
7419
7420 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
7421 !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
7422 return -EINVAL;
7423
7424 /* only important for AP, IBSS and mesh create IEs internally */
Andrei Otcheretianskid0a361a2013-10-17 10:52:17 +02007425 if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007426 return -EINVAL;
7427
Luciano Coelho252e07c2014-10-08 09:48:34 +03007428 /* Even though the attribute is u32, the specification says
7429 * u8, so let's make sure we don't overflow.
7430 */
7431 cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
7432 if (cs_count > 255)
7433 return -EINVAL;
7434
7435 params.count = cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007436
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007437 if (!need_new_beacon)
7438 goto skip_beacons;
7439
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007440 err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
7441 if (err)
7442 return err;
7443
7444 err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
7445 info->attrs[NL80211_ATTR_CSA_IES],
7446 nl80211_policy);
7447 if (err)
7448 return err;
7449
7450 err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
7451 if (err)
7452 return err;
7453
7454 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
7455 return -EINVAL;
7456
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007457 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7458 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007459 return -EINVAL;
7460
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007461 params.n_counter_offsets_beacon = len / sizeof(u16);
7462 if (rdev->wiphy.max_num_csa_counters &&
7463 (params.n_counter_offsets_beacon >
7464 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007465 return -EINVAL;
7466
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007467 params.counter_offsets_beacon =
7468 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7469
7470 /* sanity checks - counters should fit and be the same */
7471 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
7472 u16 offset = params.counter_offsets_beacon[i];
7473
7474 if (offset >= params.beacon_csa.tail_len)
7475 return -EINVAL;
7476
7477 if (params.beacon_csa.tail[offset] != params.count)
7478 return -EINVAL;
7479 }
7480
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007481 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007482 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7483 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007484 return -EINVAL;
7485
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007486 params.n_counter_offsets_presp = len / sizeof(u16);
7487 if (rdev->wiphy.max_num_csa_counters &&
Johannes Bergad5987b2016-09-13 15:53:55 +02007488 (params.n_counter_offsets_presp >
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007489 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007490 return -EINVAL;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007491
7492 params.counter_offsets_presp =
7493 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7494
7495 /* sanity checks - counters should fit and be the same */
7496 for (i = 0; i < params.n_counter_offsets_presp; i++) {
7497 u16 offset = params.counter_offsets_presp[i];
7498
7499 if (offset >= params.beacon_csa.probe_resp_len)
7500 return -EINVAL;
7501
7502 if (params.beacon_csa.probe_resp[offset] !=
7503 params.count)
7504 return -EINVAL;
7505 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007506 }
7507
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007508skip_beacons:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007509 err = nl80211_parse_chandef(rdev, info, &params.chandef);
7510 if (err)
7511 return err;
7512
Arik Nemtsov923b3522015-07-08 15:41:44 +03007513 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
7514 wdev->iftype))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007515 return -EINVAL;
7516
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007517 err = cfg80211_chandef_dfs_required(wdev->wiphy,
7518 &params.chandef,
7519 wdev->iftype);
7520 if (err < 0)
7521 return err;
7522
Fabian Frederickdcc6c2f2014-10-25 17:57:35 +02007523 if (err > 0)
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007524 params.radar_required = true;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007525
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007526 if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
7527 params.block_tx = true;
7528
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007529 wdev_lock(wdev);
7530 err = rdev_channel_switch(rdev, dev, &params);
7531 wdev_unlock(wdev);
7532
7533 return err;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007534}
7535
Johannes Berg9720bb32011-06-21 09:45:33 +02007536static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
7537 u32 seq, int flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007538 struct cfg80211_registered_device *rdev,
Johannes Berg48ab9052009-07-10 18:42:31 +02007539 struct wireless_dev *wdev,
7540 struct cfg80211_internal_bss *intbss)
Johannes Berg2a519312009-02-10 21:25:55 +01007541{
Johannes Berg48ab9052009-07-10 18:42:31 +02007542 struct cfg80211_bss *res = &intbss->pub;
Johannes Berg9caf0362012-11-29 01:25:20 +01007543 const struct cfg80211_bss_ies *ies;
Johannes Berg2a519312009-02-10 21:25:55 +01007544 void *hdr;
7545 struct nlattr *bss;
Johannes Berg48ab9052009-07-10 18:42:31 +02007546
7547 ASSERT_WDEV_LOCK(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007548
Eric W. Biederman15e47302012-09-07 20:12:54 +00007549 hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007550 NL80211_CMD_NEW_SCAN_RESULTS);
7551 if (!hdr)
7552 return -1;
7553
Johannes Berg9720bb32011-06-21 09:45:33 +02007554 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
7555
Johannes Berg97990a02013-04-19 01:02:55 +02007556 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
7557 goto nla_put_failure;
7558 if (wdev->netdev &&
David S. Miller9360ffd2012-03-29 04:41:26 -04007559 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
7560 goto nla_put_failure;
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007561 if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
7562 NL80211_ATTR_PAD))
Johannes Berg97990a02013-04-19 01:02:55 +02007563 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007564
7565 bss = nla_nest_start(msg, NL80211_ATTR_BSS);
7566 if (!bss)
7567 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04007568 if ((!is_zero_ether_addr(res->bssid) &&
Johannes Berg9caf0362012-11-29 01:25:20 +01007569 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
David S. Miller9360ffd2012-03-29 04:41:26 -04007570 goto nla_put_failure;
Johannes Berg9caf0362012-11-29 01:25:20 +01007571
7572 rcu_read_lock();
Johannes Berg0e227082014-08-12 20:34:30 +02007573 /* indicate whether we have probe response data or not */
7574 if (rcu_access_pointer(res->proberesp_ies) &&
7575 nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
7576 goto fail_unlock_rcu;
7577
7578 /* this pointer prefers to be pointed to probe response data
7579 * but is always valid
7580 */
Johannes Berg9caf0362012-11-29 01:25:20 +01007581 ies = rcu_dereference(res->ies);
Johannes Berg8cef2c92013-02-05 16:54:31 +01007582 if (ies) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007583 if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
7584 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007585 goto fail_unlock_rcu;
Johannes Berg8cef2c92013-02-05 16:54:31 +01007586 if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
7587 ies->len, ies->data))
7588 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007589 }
Johannes Berg0e227082014-08-12 20:34:30 +02007590
7591 /* and this pointer is always (unless driver didn't know) beacon data */
Johannes Berg9caf0362012-11-29 01:25:20 +01007592 ies = rcu_dereference(res->beacon_ies);
Johannes Berg0e227082014-08-12 20:34:30 +02007593 if (ies && ies->from_beacon) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007594 if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
7595 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007596 goto fail_unlock_rcu;
7597 if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
7598 ies->len, ies->data))
7599 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007600 }
7601 rcu_read_unlock();
7602
David S. Miller9360ffd2012-03-29 04:41:26 -04007603 if (res->beacon_interval &&
7604 nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
7605 goto nla_put_failure;
7606 if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
7607 nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
Simon Wunderlichdcd6eac2013-07-08 16:55:49 +02007608 nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007609 nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
7610 jiffies_to_msecs(jiffies - intbss->ts)))
7611 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007612
Avraham Stern1d762502016-07-05 17:10:13 +03007613 if (intbss->parent_tsf &&
7614 (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
7615 intbss->parent_tsf, NL80211_BSS_PAD) ||
7616 nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
7617 intbss->parent_bssid)))
7618 goto nla_put_failure;
7619
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007620 if (intbss->ts_boottime &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007621 nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
7622 intbss->ts_boottime, NL80211_BSS_PAD))
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007623 goto nla_put_failure;
7624
Johannes Berg77965c972009-02-18 18:45:06 +01007625 switch (rdev->wiphy.signal_type) {
Johannes Berg2a519312009-02-10 21:25:55 +01007626 case CFG80211_SIGNAL_TYPE_MBM:
David S. Miller9360ffd2012-03-29 04:41:26 -04007627 if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
7628 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007629 break;
7630 case CFG80211_SIGNAL_TYPE_UNSPEC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007631 if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
7632 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007633 break;
7634 default:
7635 break;
7636 }
7637
Johannes Berg48ab9052009-07-10 18:42:31 +02007638 switch (wdev->iftype) {
Johannes Berg074ac8d2010-09-16 14:58:22 +02007639 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg48ab9052009-07-10 18:42:31 +02007640 case NL80211_IFTYPE_STATION:
David S. Miller9360ffd2012-03-29 04:41:26 -04007641 if (intbss == wdev->current_bss &&
7642 nla_put_u32(msg, NL80211_BSS_STATUS,
7643 NL80211_BSS_STATUS_ASSOCIATED))
7644 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007645 break;
7646 case NL80211_IFTYPE_ADHOC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007647 if (intbss == wdev->current_bss &&
7648 nla_put_u32(msg, NL80211_BSS_STATUS,
7649 NL80211_BSS_STATUS_IBSS_JOINED))
7650 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007651 break;
7652 default:
7653 break;
7654 }
7655
Johannes Berg2a519312009-02-10 21:25:55 +01007656 nla_nest_end(msg, bss);
7657
Johannes Berg053c0952015-01-16 22:09:00 +01007658 genlmsg_end(msg, hdr);
7659 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007660
Johannes Berg8cef2c92013-02-05 16:54:31 +01007661 fail_unlock_rcu:
7662 rcu_read_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01007663 nla_put_failure:
7664 genlmsg_cancel(msg, hdr);
7665 return -EMSGSIZE;
7666}
7667
Johannes Berg97990a02013-04-19 01:02:55 +02007668static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
Johannes Berg2a519312009-02-10 21:25:55 +01007669{
Johannes Berg48ab9052009-07-10 18:42:31 +02007670 struct cfg80211_registered_device *rdev;
Johannes Berg2a519312009-02-10 21:25:55 +01007671 struct cfg80211_internal_bss *scan;
Johannes Berg48ab9052009-07-10 18:42:31 +02007672 struct wireless_dev *wdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007673 int start = cb->args[2], idx = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007674 int err;
7675
Johannes Berg97990a02013-04-19 01:02:55 +02007676 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007677 if (err)
7678 return err;
Johannes Berg2a519312009-02-10 21:25:55 +01007679
Johannes Berg48ab9052009-07-10 18:42:31 +02007680 wdev_lock(wdev);
7681 spin_lock_bh(&rdev->bss_lock);
7682 cfg80211_bss_expire(rdev);
7683
Johannes Berg9720bb32011-06-21 09:45:33 +02007684 cb->seq = rdev->bss_generation;
7685
Johannes Berg48ab9052009-07-10 18:42:31 +02007686 list_for_each_entry(scan, &rdev->bss_list, list) {
Johannes Berg2a519312009-02-10 21:25:55 +01007687 if (++idx <= start)
7688 continue;
Johannes Berg9720bb32011-06-21 09:45:33 +02007689 if (nl80211_send_bss(skb, cb,
Johannes Berg2a519312009-02-10 21:25:55 +01007690 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg48ab9052009-07-10 18:42:31 +02007691 rdev, wdev, scan) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +01007692 idx--;
Johannes Berg67748892010-10-04 21:14:06 +02007693 break;
Johannes Berg2a519312009-02-10 21:25:55 +01007694 }
7695 }
7696
Johannes Berg48ab9052009-07-10 18:42:31 +02007697 spin_unlock_bh(&rdev->bss_lock);
7698 wdev_unlock(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007699
Johannes Berg97990a02013-04-19 01:02:55 +02007700 cb->args[2] = idx;
7701 nl80211_finish_wdev_dump(rdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007702
Johannes Berg67748892010-10-04 21:14:06 +02007703 return skb->len;
Johannes Berg2a519312009-02-10 21:25:55 +01007704}
7705
Eric W. Biederman15e47302012-09-07 20:12:54 +00007706static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007707 int flags, struct net_device *dev,
7708 bool allow_radio_stats,
7709 struct survey_info *survey)
Holger Schurig61fa7132009-11-11 12:25:40 +01007710{
7711 void *hdr;
7712 struct nlattr *infoattr;
7713
Johannes Berg11f78ac2014-11-14 16:43:50 +01007714 /* skip radio stats if userspace didn't request them */
7715 if (!survey->channel && !allow_radio_stats)
7716 return 0;
7717
Eric W. Biederman15e47302012-09-07 20:12:54 +00007718 hdr = nl80211hdr_put(msg, portid, seq, flags,
Holger Schurig61fa7132009-11-11 12:25:40 +01007719 NL80211_CMD_NEW_SURVEY_RESULTS);
7720 if (!hdr)
7721 return -ENOMEM;
7722
David S. Miller9360ffd2012-03-29 04:41:26 -04007723 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
7724 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007725
7726 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
7727 if (!infoattr)
7728 goto nla_put_failure;
7729
Johannes Berg11f78ac2014-11-14 16:43:50 +01007730 if (survey->channel &&
7731 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
David S. Miller9360ffd2012-03-29 04:41:26 -04007732 survey->channel->center_freq))
7733 goto nla_put_failure;
7734
7735 if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
7736 nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
7737 goto nla_put_failure;
7738 if ((survey->filled & SURVEY_INFO_IN_USE) &&
7739 nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
7740 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007741 if ((survey->filled & SURVEY_INFO_TIME) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007742 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
7743 survey->time, 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_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007746 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
7747 survey->time_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_EXT_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007750 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
7751 survey->time_ext_busy, 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_RX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007754 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
7755 survey->time_rx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007756 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007757 if ((survey->filled & SURVEY_INFO_TIME_TX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007758 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
7759 survey->time_tx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007760 goto nla_put_failure;
Johannes Berg052536a2014-11-14 16:44:11 +01007761 if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007762 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
7763 survey->time_scan, NL80211_SURVEY_INFO_PAD))
Johannes Berg052536a2014-11-14 16:44:11 +01007764 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007765
7766 nla_nest_end(msg, infoattr);
7767
Johannes Berg053c0952015-01-16 22:09:00 +01007768 genlmsg_end(msg, hdr);
7769 return 0;
Holger Schurig61fa7132009-11-11 12:25:40 +01007770
7771 nla_put_failure:
7772 genlmsg_cancel(msg, hdr);
7773 return -EMSGSIZE;
7774}
7775
Johannes Berg11f78ac2014-11-14 16:43:50 +01007776static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
Holger Schurig61fa7132009-11-11 12:25:40 +01007777{
Johannes Bergc90c39d2016-10-24 14:40:01 +02007778 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Holger Schurig61fa7132009-11-11 12:25:40 +01007779 struct survey_info survey;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007780 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007781 struct wireless_dev *wdev;
7782 int survey_idx = cb->args[2];
Holger Schurig61fa7132009-11-11 12:25:40 +01007783 int res;
Johannes Berg11f78ac2014-11-14 16:43:50 +01007784 bool radio_stats;
Holger Schurig61fa7132009-11-11 12:25:40 +01007785
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007786 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007787 if (res)
7788 return res;
Holger Schurig61fa7132009-11-11 12:25:40 +01007789
Johannes Berg11f78ac2014-11-14 16:43:50 +01007790 /* prepare_wdev_dump parsed the attributes */
Johannes Bergc90c39d2016-10-24 14:40:01 +02007791 radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
Johannes Berg11f78ac2014-11-14 16:43:50 +01007792
Johannes Berg97990a02013-04-19 01:02:55 +02007793 if (!wdev->netdev) {
7794 res = -EINVAL;
7795 goto out_err;
7796 }
7797
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007798 if (!rdev->ops->dump_survey) {
Holger Schurig61fa7132009-11-11 12:25:40 +01007799 res = -EOPNOTSUPP;
7800 goto out_err;
7801 }
7802
7803 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007804 res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
Holger Schurig61fa7132009-11-11 12:25:40 +01007805 if (res == -ENOENT)
7806 break;
7807 if (res)
7808 goto out_err;
7809
Johannes Berg11f78ac2014-11-14 16:43:50 +01007810 /* don't send disabled channels, but do send non-channel data */
7811 if (survey.channel &&
7812 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
Luis R. Rodriguez180cdc72011-05-27 07:24:02 -07007813 survey_idx++;
7814 continue;
7815 }
7816
Holger Schurig61fa7132009-11-11 12:25:40 +01007817 if (nl80211_send_survey(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00007818 NETLINK_CB(cb->skb).portid,
Holger Schurig61fa7132009-11-11 12:25:40 +01007819 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007820 wdev->netdev, radio_stats, &survey) < 0)
Holger Schurig61fa7132009-11-11 12:25:40 +01007821 goto out;
7822 survey_idx++;
7823 }
7824
7825 out:
Johannes Berg97990a02013-04-19 01:02:55 +02007826 cb->args[2] = survey_idx;
Holger Schurig61fa7132009-11-11 12:25:40 +01007827 res = skb->len;
7828 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007829 nl80211_finish_wdev_dump(rdev);
Holger Schurig61fa7132009-11-11 12:25:40 +01007830 return res;
7831}
7832
Samuel Ortizb23aa672009-07-01 21:26:54 +02007833static bool nl80211_valid_wpa_versions(u32 wpa_versions)
7834{
7835 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
7836 NL80211_WPA_VERSION_2));
7837}
7838
Jouni Malinen636a5d32009-03-19 13:39:22 +02007839static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
7840{
Johannes Berg4c476992010-10-04 21:36:35 +02007841 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7842 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02007843 struct ieee80211_channel *chan;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007844 const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
7845 int err, ssid_len, ie_len = 0, auth_data_len = 0;
Johannes Berg19957bb2009-07-02 17:20:43 +02007846 enum nl80211_auth_type auth_type;
Johannes Bergfffd0932009-07-08 14:22:54 +02007847 struct key_parse key;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03007848 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007849
Johannes Bergf4a11bb2009-03-27 12:40:28 +01007850 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
7851 return -EINVAL;
7852
7853 if (!info->attrs[NL80211_ATTR_MAC])
7854 return -EINVAL;
7855
Jouni Malinen17780922009-03-27 20:52:47 +02007856 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
7857 return -EINVAL;
7858
Johannes Berg19957bb2009-07-02 17:20:43 +02007859 if (!info->attrs[NL80211_ATTR_SSID])
7860 return -EINVAL;
7861
7862 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
7863 return -EINVAL;
7864
Johannes Bergfffd0932009-07-08 14:22:54 +02007865 err = nl80211_parse_key(info, &key);
7866 if (err)
7867 return err;
7868
7869 if (key.idx >= 0) {
Johannes Berge31b8212010-10-05 19:39:30 +02007870 if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
7871 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02007872 if (!key.p.key || !key.p.key_len)
7873 return -EINVAL;
7874 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
7875 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
7876 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
7877 key.p.key_len != WLAN_KEY_LEN_WEP104))
7878 return -EINVAL;
Johannes Bergb6b55552016-09-13 16:25:58 +02007879 if (key.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +02007880 return -EINVAL;
7881 } else {
7882 key.p.key_len = 0;
7883 key.p.key = NULL;
7884 }
7885
Johannes Bergafea0b72010-08-10 09:46:42 +02007886 if (key.idx >= 0) {
7887 int i;
7888 bool ok = false;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007889
Johannes Bergafea0b72010-08-10 09:46:42 +02007890 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
7891 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
7892 ok = true;
7893 break;
7894 }
7895 }
Johannes Berg4c476992010-10-04 21:36:35 +02007896 if (!ok)
7897 return -EINVAL;
Johannes Bergafea0b72010-08-10 09:46:42 +02007898 }
7899
Johannes Berg4c476992010-10-04 21:36:35 +02007900 if (!rdev->ops->auth)
7901 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007902
Johannes Berg074ac8d2010-09-16 14:58:22 +02007903 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02007904 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
7905 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02007906
Johannes Berg19957bb2009-07-02 17:20:43 +02007907 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen664834d2014-01-15 00:01:44 +02007908 chan = nl80211_get_valid_chan(&rdev->wiphy,
7909 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
7910 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02007911 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007912
Johannes Berg19957bb2009-07-02 17:20:43 +02007913 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
7914 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
7915
7916 if (info->attrs[NL80211_ATTR_IE]) {
7917 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
7918 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
7919 }
7920
7921 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03007922 if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
Johannes Berg4c476992010-10-04 21:36:35 +02007923 return -EINVAL;
Johannes Berg19957bb2009-07-02 17:20:43 +02007924
Jouni Malinen63181062016-10-27 00:42:02 +03007925 if ((auth_type == NL80211_AUTHTYPE_SAE ||
7926 auth_type == NL80211_AUTHTYPE_FILS_SK ||
7927 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
7928 auth_type == NL80211_AUTHTYPE_FILS_PK) &&
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007929 !info->attrs[NL80211_ATTR_AUTH_DATA])
Jouni Malinene39e5b52012-09-30 19:29:39 +03007930 return -EINVAL;
7931
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007932 if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
Jouni Malinen63181062016-10-27 00:42:02 +03007933 if (auth_type != NL80211_AUTHTYPE_SAE &&
7934 auth_type != NL80211_AUTHTYPE_FILS_SK &&
7935 auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
7936 auth_type != NL80211_AUTHTYPE_FILS_PK)
Jouni Malinene39e5b52012-09-30 19:29:39 +03007937 return -EINVAL;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007938 auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
7939 auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03007940 /* need to include at least Auth Transaction and Status Code */
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007941 if (auth_data_len < 4)
Jouni Malinene39e5b52012-09-30 19:29:39 +03007942 return -EINVAL;
7943 }
7944
Jouni Malinend5cdfac2010-04-04 09:37:19 +03007945 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
7946
Johannes Berg95de8172012-01-20 13:55:25 +01007947 /*
7948 * Since we no longer track auth state, ignore
7949 * requests to only change local state.
7950 */
7951 if (local_state_change)
7952 return 0;
7953
Johannes Berg91bf9b22013-05-15 17:44:01 +02007954 wdev_lock(dev->ieee80211_ptr);
7955 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
7956 ssid, ssid_len, ie, ie_len,
7957 key.p.key, key.p.key_len, key.idx,
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007958 auth_data, auth_data_len);
Johannes Berg91bf9b22013-05-15 17:44:01 +02007959 wdev_unlock(dev->ieee80211_ptr);
7960 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007961}
7962
Johannes Bergc0692b82010-08-27 14:26:53 +03007963static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
7964 struct genl_info *info,
Johannes Berg3dc27d22009-07-02 21:36:37 +02007965 struct cfg80211_crypto_settings *settings,
7966 int cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02007967{
Johannes Bergc0b2bbd2009-07-25 16:54:36 +02007968 memset(settings, 0, sizeof(*settings));
7969
Samuel Ortizb23aa672009-07-01 21:26:54 +02007970 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
7971
Johannes Bergc0692b82010-08-27 14:26:53 +03007972 if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
7973 u16 proto;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007974
Johannes Bergc0692b82010-08-27 14:26:53 +03007975 proto = nla_get_u16(
7976 info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
7977 settings->control_port_ethertype = cpu_to_be16(proto);
7978 if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
7979 proto != ETH_P_PAE)
7980 return -EINVAL;
7981 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
7982 settings->control_port_no_encrypt = true;
7983 } else
7984 settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
7985
Samuel Ortizb23aa672009-07-01 21:26:54 +02007986 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
7987 void *data;
7988 int len, i;
7989
7990 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
7991 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
7992 settings->n_ciphers_pairwise = len / sizeof(u32);
7993
7994 if (len % sizeof(u32))
7995 return -EINVAL;
7996
Johannes Berg3dc27d22009-07-02 21:36:37 +02007997 if (settings->n_ciphers_pairwise > cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02007998 return -EINVAL;
7999
8000 memcpy(settings->ciphers_pairwise, data, len);
8001
8002 for (i = 0; i < settings->n_ciphers_pairwise; i++)
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008003 if (!cfg80211_supported_cipher_suite(
8004 &rdev->wiphy,
Samuel Ortizb23aa672009-07-01 21:26:54 +02008005 settings->ciphers_pairwise[i]))
8006 return -EINVAL;
8007 }
8008
8009 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
8010 settings->cipher_group =
8011 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008012 if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
8013 settings->cipher_group))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008014 return -EINVAL;
8015 }
8016
8017 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
8018 settings->wpa_versions =
8019 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
8020 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
8021 return -EINVAL;
8022 }
8023
8024 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
8025 void *data;
Jouni Malinen6d302402011-09-21 18:11:33 +03008026 int len;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008027
8028 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
8029 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
8030 settings->n_akm_suites = len / sizeof(u32);
8031
8032 if (len % sizeof(u32))
8033 return -EINVAL;
8034
Jouni Malinen1b9ca022011-09-21 16:13:07 +03008035 if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
8036 return -EINVAL;
8037
Samuel Ortizb23aa672009-07-01 21:26:54 +02008038 memcpy(settings->akm_suites, data, len);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008039 }
8040
8041 return 0;
8042}
8043
Jouni Malinen636a5d32009-03-19 13:39:22 +02008044static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
8045{
Johannes Berg4c476992010-10-04 21:36:35 +02008046 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8047 struct net_device *dev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02008048 struct ieee80211_channel *chan;
Johannes Bergf62fab72013-02-21 20:09:09 +01008049 struct cfg80211_assoc_request req = {};
8050 const u8 *bssid, *ssid;
8051 int err, ssid_len = 0;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008052
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008053 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8054 return -EINVAL;
8055
8056 if (!info->attrs[NL80211_ATTR_MAC] ||
Johannes Berg19957bb2009-07-02 17:20:43 +02008057 !info->attrs[NL80211_ATTR_SSID] ||
8058 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008059 return -EINVAL;
8060
Johannes Berg4c476992010-10-04 21:36:35 +02008061 if (!rdev->ops->assoc)
8062 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008063
Johannes Berg074ac8d2010-09-16 14:58:22 +02008064 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008065 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8066 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008067
Johannes Berg19957bb2009-07-02 17:20:43 +02008068 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008069
Jouni Malinen664834d2014-01-15 00:01:44 +02008070 chan = nl80211_get_valid_chan(&rdev->wiphy,
8071 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8072 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02008073 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008074
Johannes Berg19957bb2009-07-02 17:20:43 +02008075 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8076 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008077
8078 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008079 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8080 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008081 }
8082
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008083 if (info->attrs[NL80211_ATTR_USE_MFP]) {
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008084 enum nl80211_mfp mfp =
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008085 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008086 if (mfp == NL80211_MFP_REQUIRED)
Johannes Bergf62fab72013-02-21 20:09:09 +01008087 req.use_mfp = true;
Johannes Berg4c476992010-10-04 21:36:35 +02008088 else if (mfp != NL80211_MFP_NO)
8089 return -EINVAL;
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008090 }
8091
Johannes Berg3e5d7642009-07-07 14:37:26 +02008092 if (info->attrs[NL80211_ATTR_PREV_BSSID])
Johannes Bergf62fab72013-02-21 20:09:09 +01008093 req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
Johannes Berg3e5d7642009-07-07 14:37:26 +02008094
Ben Greear7e7c8922011-11-18 11:31:59 -08008095 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008096 req.flags |= ASSOC_REQ_DISABLE_HT;
Ben Greear7e7c8922011-11-18 11:31:59 -08008097
8098 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008099 memcpy(&req.ht_capa_mask,
8100 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8101 sizeof(req.ht_capa_mask));
Ben Greear7e7c8922011-11-18 11:31:59 -08008102
8103 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008104 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Ben Greear7e7c8922011-11-18 11:31:59 -08008105 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008106 memcpy(&req.ht_capa,
8107 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8108 sizeof(req.ht_capa));
Ben Greear7e7c8922011-11-18 11:31:59 -08008109 }
8110
Johannes Bergee2aca32013-02-21 17:36:01 +01008111 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008112 req.flags |= ASSOC_REQ_DISABLE_VHT;
Johannes Bergee2aca32013-02-21 17:36:01 +01008113
8114 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008115 memcpy(&req.vht_capa_mask,
8116 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8117 sizeof(req.vht_capa_mask));
Johannes Bergee2aca32013-02-21 17:36:01 +01008118
8119 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008120 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergee2aca32013-02-21 17:36:01 +01008121 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008122 memcpy(&req.vht_capa,
8123 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8124 sizeof(req.vht_capa));
Johannes Bergee2aca32013-02-21 17:36:01 +01008125 }
8126
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008127 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008128 if (!((rdev->wiphy.features &
8129 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8130 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8131 !wiphy_ext_feature_isset(&rdev->wiphy,
8132 NL80211_EXT_FEATURE_RRM))
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008133 return -EINVAL;
8134 req.flags |= ASSOC_REQ_USE_RRM;
8135 }
8136
Jouni Malinen348bd452016-10-27 00:42:03 +03008137 if (info->attrs[NL80211_ATTR_FILS_KEK]) {
8138 req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
8139 req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
8140 if (!info->attrs[NL80211_ATTR_FILS_NONCES])
8141 return -EINVAL;
8142 req.fils_nonces =
8143 nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
8144 }
8145
Johannes Bergf62fab72013-02-21 20:09:09 +01008146 err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008147 if (!err) {
8148 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008149
Johannes Bergf62fab72013-02-21 20:09:09 +01008150 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
8151 ssid, ssid_len, &req);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008152
8153 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8154 dev->ieee80211_ptr->conn_owner_nlportid =
8155 info->snd_portid;
8156 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8157 bssid, ETH_ALEN);
8158 }
8159
Johannes Berg91bf9b22013-05-15 17:44:01 +02008160 wdev_unlock(dev->ieee80211_ptr);
8161 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008162
Jouni Malinen636a5d32009-03-19 13:39:22 +02008163 return err;
8164}
8165
8166static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
8167{
Johannes Berg4c476992010-10-04 21:36:35 +02008168 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8169 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008170 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008171 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008172 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008173 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008174
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008175 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8176 return -EINVAL;
8177
8178 if (!info->attrs[NL80211_ATTR_MAC])
8179 return -EINVAL;
8180
8181 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8182 return -EINVAL;
8183
Johannes Berg4c476992010-10-04 21:36:35 +02008184 if (!rdev->ops->deauth)
8185 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008186
Johannes Berg074ac8d2010-09-16 14:58:22 +02008187 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008188 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8189 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008190
Johannes Berg19957bb2009-07-02 17:20:43 +02008191 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008192
Johannes Berg19957bb2009-07-02 17:20:43 +02008193 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8194 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008195 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008196 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008197 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008198
8199 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008200 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8201 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008202 }
8203
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008204 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8205
Johannes Berg91bf9b22013-05-15 17:44:01 +02008206 wdev_lock(dev->ieee80211_ptr);
8207 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
8208 local_state_change);
8209 wdev_unlock(dev->ieee80211_ptr);
8210 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008211}
8212
8213static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
8214{
Johannes Berg4c476992010-10-04 21:36:35 +02008215 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8216 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008217 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008218 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008219 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008220 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008221
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008222 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8223 return -EINVAL;
8224
8225 if (!info->attrs[NL80211_ATTR_MAC])
8226 return -EINVAL;
8227
8228 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8229 return -EINVAL;
8230
Johannes Berg4c476992010-10-04 21:36:35 +02008231 if (!rdev->ops->disassoc)
8232 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008233
Johannes Berg074ac8d2010-09-16 14:58:22 +02008234 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008235 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8236 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008237
Johannes Berg19957bb2009-07-02 17:20:43 +02008238 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008239
Johannes Berg19957bb2009-07-02 17:20:43 +02008240 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8241 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008242 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008243 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008244 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008245
8246 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008247 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8248 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008249 }
8250
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008251 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8252
Johannes Berg91bf9b22013-05-15 17:44:01 +02008253 wdev_lock(dev->ieee80211_ptr);
8254 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
8255 local_state_change);
8256 wdev_unlock(dev->ieee80211_ptr);
8257 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008258}
8259
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008260static bool
8261nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
Johannes Berg57fbcce2016-04-12 15:56:15 +02008262 int mcast_rate[NUM_NL80211_BANDS],
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008263 int rateval)
8264{
8265 struct wiphy *wiphy = &rdev->wiphy;
8266 bool found = false;
8267 int band, i;
8268
Johannes Berg57fbcce2016-04-12 15:56:15 +02008269 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008270 struct ieee80211_supported_band *sband;
8271
8272 sband = wiphy->bands[band];
8273 if (!sband)
8274 continue;
8275
8276 for (i = 0; i < sband->n_bitrates; i++) {
8277 if (sband->bitrates[i].bitrate == rateval) {
8278 mcast_rate[band] = i + 1;
8279 found = true;
8280 break;
8281 }
8282 }
8283 }
8284
8285 return found;
8286}
8287
Johannes Berg04a773a2009-04-19 21:24:32 +02008288static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
8289{
Johannes Berg4c476992010-10-04 21:36:35 +02008290 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8291 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008292 struct cfg80211_ibss_params ibss;
8293 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008294 struct cfg80211_cached_keys *connkeys = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +02008295 int err;
8296
Johannes Berg8e30bc52009-04-22 17:45:38 +02008297 memset(&ibss, 0, sizeof(ibss));
8298
Johannes Berg04a773a2009-04-19 21:24:32 +02008299 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8300 return -EINVAL;
8301
Johannes Berg683b6d32012-11-08 21:25:48 +01008302 if (!info->attrs[NL80211_ATTR_SSID] ||
Johannes Berg04a773a2009-04-19 21:24:32 +02008303 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8304 return -EINVAL;
8305
Johannes Berg8e30bc52009-04-22 17:45:38 +02008306 ibss.beacon_interval = 100;
8307
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308308 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
Johannes Berg8e30bc52009-04-22 17:45:38 +02008309 ibss.beacon_interval =
8310 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308311
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05308312 err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
8313 ibss.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308314 if (err)
8315 return err;
Johannes Berg8e30bc52009-04-22 17:45:38 +02008316
Johannes Berg4c476992010-10-04 21:36:35 +02008317 if (!rdev->ops->join_ibss)
8318 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008319
Johannes Berg4c476992010-10-04 21:36:35 +02008320 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8321 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008322
Johannes Berg79c97e92009-07-07 03:56:12 +02008323 wiphy = &rdev->wiphy;
Johannes Berg04a773a2009-04-19 21:24:32 +02008324
Johannes Berg39193492011-09-16 13:45:25 +02008325 if (info->attrs[NL80211_ATTR_MAC]) {
Johannes Berg04a773a2009-04-19 21:24:32 +02008326 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg39193492011-09-16 13:45:25 +02008327
8328 if (!is_valid_ether_addr(ibss.bssid))
8329 return -EINVAL;
8330 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008331 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8332 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8333
8334 if (info->attrs[NL80211_ATTR_IE]) {
8335 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8336 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8337 }
8338
Johannes Berg683b6d32012-11-08 21:25:48 +01008339 err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
8340 if (err)
8341 return err;
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008342
Ilan Peer174e0cd2014-02-23 09:13:01 +02008343 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
8344 NL80211_IFTYPE_ADHOC))
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008345 return -EINVAL;
8346
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008347 switch (ibss.chandef.width) {
Simon Wunderlichbf372642013-07-08 16:55:58 +02008348 case NL80211_CHAN_WIDTH_5:
8349 case NL80211_CHAN_WIDTH_10:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008350 case NL80211_CHAN_WIDTH_20_NOHT:
8351 break;
8352 case NL80211_CHAN_WIDTH_20:
8353 case NL80211_CHAN_WIDTH_40:
Janusz.Dziedzic@tieto.comffc11992015-02-21 16:52:39 +01008354 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8355 return -EINVAL;
8356 break;
8357 case NL80211_CHAN_WIDTH_80:
8358 case NL80211_CHAN_WIDTH_80P80:
8359 case NL80211_CHAN_WIDTH_160:
8360 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8361 return -EINVAL;
8362 if (!wiphy_ext_feature_isset(&rdev->wiphy,
8363 NL80211_EXT_FEATURE_VHT_IBSS))
8364 return -EINVAL;
8365 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008366 default:
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008367 return -EINVAL;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008368 }
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008369
Johannes Berg04a773a2009-04-19 21:24:32 +02008370 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
Johannes Bergfffd0932009-07-08 14:22:54 +02008371 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg04a773a2009-04-19 21:24:32 +02008372
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008373 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
8374 u8 *rates =
8375 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8376 int n_rates =
8377 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8378 struct ieee80211_supported_band *sband =
Johannes Berg683b6d32012-11-08 21:25:48 +01008379 wiphy->bands[ibss.chandef.chan->band];
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008380
Johannes Berg34850ab2011-07-18 18:08:35 +02008381 err = ieee80211_get_ratemask(sband, rates, n_rates,
8382 &ibss.basic_rates);
8383 if (err)
8384 return err;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008385 }
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008386
Simon Wunderlich803768f2013-06-28 10:39:58 +02008387 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8388 memcpy(&ibss.ht_capa_mask,
8389 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8390 sizeof(ibss.ht_capa_mask));
8391
8392 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
8393 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8394 return -EINVAL;
8395 memcpy(&ibss.ht_capa,
8396 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8397 sizeof(ibss.ht_capa));
8398 }
8399
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008400 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
8401 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
8402 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
8403 return -EINVAL;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008404
Johannes Berg4c476992010-10-04 21:36:35 +02008405 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Sujith Manoharande7044e2012-10-18 10:19:28 +05308406 bool no_ht = false;
8407
Johannes Berg4c476992010-10-04 21:36:35 +02008408 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308409 info->attrs[NL80211_ATTR_KEYS],
8410 &no_ht);
Johannes Berg4c476992010-10-04 21:36:35 +02008411 if (IS_ERR(connkeys))
8412 return PTR_ERR(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308413
Johannes Berg3d9d1d62012-11-08 23:14:50 +01008414 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
8415 no_ht) {
Ola Olsson5e950a72016-02-11 01:00:22 +01008416 kzfree(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308417 return -EINVAL;
8418 }
Johannes Berg4c476992010-10-04 21:36:35 +02008419 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008420
Antonio Quartulli267335d2012-01-31 20:25:47 +01008421 ibss.control_port =
8422 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
8423
Simon Wunderlich5336fa82013-10-07 18:41:05 +02008424 ibss.userspace_handles_dfs =
8425 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
8426
Johannes Berg4c476992010-10-04 21:36:35 +02008427 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008428 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008429 kzfree(connkeys);
Johannes Berg04a773a2009-04-19 21:24:32 +02008430 return err;
8431}
8432
8433static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
8434{
Johannes Berg4c476992010-10-04 21:36:35 +02008435 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8436 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008437
Johannes Berg4c476992010-10-04 21:36:35 +02008438 if (!rdev->ops->leave_ibss)
8439 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008440
Johannes Berg4c476992010-10-04 21:36:35 +02008441 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8442 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008443
Johannes Berg4c476992010-10-04 21:36:35 +02008444 return cfg80211_leave_ibss(rdev, dev, false);
Johannes Berg04a773a2009-04-19 21:24:32 +02008445}
8446
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008447static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
8448{
8449 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8450 struct net_device *dev = info->user_ptr[1];
Johannes Berg57fbcce2016-04-12 15:56:15 +02008451 int mcast_rate[NUM_NL80211_BANDS];
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008452 u32 nla_rate;
8453 int err;
8454
8455 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
Bertold Van den Bergh876dc932015-08-05 16:02:21 +02008456 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
8457 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008458 return -EOPNOTSUPP;
8459
8460 if (!rdev->ops->set_mcast_rate)
8461 return -EOPNOTSUPP;
8462
8463 memset(mcast_rate, 0, sizeof(mcast_rate));
8464
8465 if (!info->attrs[NL80211_ATTR_MCAST_RATE])
8466 return -EINVAL;
8467
8468 nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
8469 if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
8470 return -EINVAL;
8471
Ilan Peera1056b1b2015-10-22 22:27:46 +03008472 err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008473
8474 return err;
8475}
8476
Johannes Bergad7e7182013-11-13 13:37:47 +01008477static struct sk_buff *
8478__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008479 struct wireless_dev *wdev, int approxlen,
8480 u32 portid, u32 seq, enum nl80211_commands cmd,
Johannes Berg567ffc32013-12-18 14:43:31 +01008481 enum nl80211_attrs attr,
8482 const struct nl80211_vendor_cmd_info *info,
8483 gfp_t gfp)
Johannes Bergad7e7182013-11-13 13:37:47 +01008484{
8485 struct sk_buff *skb;
8486 void *hdr;
8487 struct nlattr *data;
8488
8489 skb = nlmsg_new(approxlen + 100, gfp);
8490 if (!skb)
8491 return NULL;
8492
8493 hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
8494 if (!hdr) {
8495 kfree_skb(skb);
8496 return NULL;
8497 }
8498
8499 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
8500 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01008501
8502 if (info) {
8503 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
8504 info->vendor_id))
8505 goto nla_put_failure;
8506 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
8507 info->subcmd))
8508 goto nla_put_failure;
8509 }
8510
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008511 if (wdev) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008512 if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
8513 wdev_id(wdev), NL80211_ATTR_PAD))
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008514 goto nla_put_failure;
8515 if (wdev->netdev &&
8516 nla_put_u32(skb, NL80211_ATTR_IFINDEX,
8517 wdev->netdev->ifindex))
8518 goto nla_put_failure;
8519 }
8520
Johannes Bergad7e7182013-11-13 13:37:47 +01008521 data = nla_nest_start(skb, attr);
Johannes Berg76e1fb42016-09-14 09:55:57 +02008522 if (!data)
8523 goto nla_put_failure;
Johannes Bergad7e7182013-11-13 13:37:47 +01008524
8525 ((void **)skb->cb)[0] = rdev;
8526 ((void **)skb->cb)[1] = hdr;
8527 ((void **)skb->cb)[2] = data;
8528
8529 return skb;
8530
8531 nla_put_failure:
8532 kfree_skb(skb);
8533 return NULL;
8534}
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008535
Johannes Berge03ad6e2014-01-01 17:22:30 +01008536struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008537 struct wireless_dev *wdev,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008538 enum nl80211_commands cmd,
8539 enum nl80211_attrs attr,
8540 int vendor_event_idx,
8541 int approxlen, gfp_t gfp)
8542{
Zhao, Gangf26cbf42014-04-21 12:53:03 +08008543 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berge03ad6e2014-01-01 17:22:30 +01008544 const struct nl80211_vendor_cmd_info *info;
8545
8546 switch (cmd) {
8547 case NL80211_CMD_TESTMODE:
8548 if (WARN_ON(vendor_event_idx != -1))
8549 return NULL;
8550 info = NULL;
8551 break;
8552 case NL80211_CMD_VENDOR:
8553 if (WARN_ON(vendor_event_idx < 0 ||
8554 vendor_event_idx >= wiphy->n_vendor_events))
8555 return NULL;
8556 info = &wiphy->vendor_events[vendor_event_idx];
8557 break;
8558 default:
8559 WARN_ON(1);
8560 return NULL;
8561 }
8562
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008563 return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008564 cmd, attr, info, gfp);
8565}
8566EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
8567
8568void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
8569{
8570 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
8571 void *hdr = ((void **)skb->cb)[1];
8572 struct nlattr *data = ((void **)skb->cb)[2];
8573 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
8574
Johannes Bergbd8c78e2014-07-30 14:55:26 +02008575 /* clear CB data for netlink core to own from now on */
8576 memset(skb->cb, 0, sizeof(skb->cb));
8577
Johannes Berge03ad6e2014-01-01 17:22:30 +01008578 nla_nest_end(skb, data);
8579 genlmsg_end(skb, hdr);
8580
8581 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
8582 mcgrp = NL80211_MCGRP_VENDOR;
8583
8584 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
8585 mcgrp, gfp);
8586}
8587EXPORT_SYMBOL(__cfg80211_send_event_skb);
8588
Johannes Bergaff89a92009-07-01 21:26:51 +02008589#ifdef CONFIG_NL80211_TESTMODE
Johannes Bergaff89a92009-07-01 21:26:51 +02008590static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
8591{
Johannes Berg4c476992010-10-04 21:36:35 +02008592 struct cfg80211_registered_device *rdev = info->user_ptr[0];
David Spinadelfc73f112013-07-31 18:04:15 +03008593 struct wireless_dev *wdev =
8594 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
Johannes Bergaff89a92009-07-01 21:26:51 +02008595 int err;
8596
David Spinadelfc73f112013-07-31 18:04:15 +03008597 if (!rdev->ops->testmode_cmd)
8598 return -EOPNOTSUPP;
8599
8600 if (IS_ERR(wdev)) {
8601 err = PTR_ERR(wdev);
8602 if (err != -EINVAL)
8603 return err;
8604 wdev = NULL;
8605 } else if (wdev->wiphy != &rdev->wiphy) {
8606 return -EINVAL;
8607 }
8608
Johannes Bergaff89a92009-07-01 21:26:51 +02008609 if (!info->attrs[NL80211_ATTR_TESTDATA])
8610 return -EINVAL;
8611
Johannes Bergad7e7182013-11-13 13:37:47 +01008612 rdev->cur_cmd_info = info;
David Spinadelfc73f112013-07-31 18:04:15 +03008613 err = rdev_testmode_cmd(rdev, wdev,
Johannes Bergaff89a92009-07-01 21:26:51 +02008614 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
8615 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
Johannes Bergad7e7182013-11-13 13:37:47 +01008616 rdev->cur_cmd_info = NULL;
Johannes Bergaff89a92009-07-01 21:26:51 +02008617
Johannes Bergaff89a92009-07-01 21:26:51 +02008618 return err;
8619}
8620
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008621static int nl80211_testmode_dump(struct sk_buff *skb,
8622 struct netlink_callback *cb)
8623{
Johannes Berg00918d32011-12-13 17:22:05 +01008624 struct cfg80211_registered_device *rdev;
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008625 int err;
8626 long phy_idx;
8627 void *data = NULL;
8628 int data_len = 0;
8629
Johannes Berg5fe231e2013-05-08 21:45:15 +02008630 rtnl_lock();
8631
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008632 if (cb->args[0]) {
8633 /*
8634 * 0 is a valid index, but not valid for args[0],
8635 * so we need to offset by 1.
8636 */
8637 phy_idx = cb->args[0] - 1;
Luca Coelhoa4956dc2017-02-07 22:13:56 +02008638
8639 rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
8640 if (!rdev) {
8641 err = -ENOENT;
8642 goto out_err;
8643 }
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008644 } else {
Johannes Bergc90c39d2016-10-24 14:40:01 +02008645 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
8646
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008647 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +02008648 attrbuf, nl80211_fam.maxattr, nl80211_policy);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008649 if (err)
Johannes Berg5fe231e2013-05-08 21:45:15 +02008650 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008651
Johannes Bergc90c39d2016-10-24 14:40:01 +02008652 rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg2bd7e352012-06-15 14:23:16 +02008653 if (IS_ERR(rdev)) {
Johannes Berg5fe231e2013-05-08 21:45:15 +02008654 err = PTR_ERR(rdev);
8655 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008656 }
Johannes Berg2bd7e352012-06-15 14:23:16 +02008657 phy_idx = rdev->wiphy_idx;
Johannes Berg2bd7e352012-06-15 14:23:16 +02008658
Johannes Bergc90c39d2016-10-24 14:40:01 +02008659 if (attrbuf[NL80211_ATTR_TESTDATA])
8660 cb->args[1] = (long)attrbuf[NL80211_ATTR_TESTDATA];
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008661 }
8662
8663 if (cb->args[1]) {
8664 data = nla_data((void *)cb->args[1]);
8665 data_len = nla_len((void *)cb->args[1]);
8666 }
8667
Johannes Berg00918d32011-12-13 17:22:05 +01008668 if (!rdev->ops->testmode_dump) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008669 err = -EOPNOTSUPP;
8670 goto out_err;
8671 }
8672
8673 while (1) {
Eric W. Biederman15e47302012-09-07 20:12:54 +00008674 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008675 cb->nlh->nlmsg_seq, NLM_F_MULTI,
8676 NL80211_CMD_TESTMODE);
8677 struct nlattr *tmdata;
8678
Dan Carpentercb35fba2013-08-14 14:50:01 +03008679 if (!hdr)
8680 break;
8681
David S. Miller9360ffd2012-03-29 04:41:26 -04008682 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008683 genlmsg_cancel(skb, hdr);
8684 break;
8685 }
8686
8687 tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
8688 if (!tmdata) {
8689 genlmsg_cancel(skb, hdr);
8690 break;
8691 }
Hila Gonene35e4d22012-06-27 17:19:42 +03008692 err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008693 nla_nest_end(skb, tmdata);
8694
8695 if (err == -ENOBUFS || err == -ENOENT) {
8696 genlmsg_cancel(skb, hdr);
8697 break;
8698 } else if (err) {
8699 genlmsg_cancel(skb, hdr);
8700 goto out_err;
8701 }
8702
8703 genlmsg_end(skb, hdr);
8704 }
8705
8706 err = skb->len;
8707 /* see above */
8708 cb->args[0] = phy_idx + 1;
8709 out_err:
Johannes Berg5fe231e2013-05-08 21:45:15 +02008710 rtnl_unlock();
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008711 return err;
8712}
Johannes Bergaff89a92009-07-01 21:26:51 +02008713#endif
8714
Samuel Ortizb23aa672009-07-01 21:26:54 +02008715static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
8716{
Johannes Berg4c476992010-10-04 21:36:35 +02008717 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8718 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02008719 struct cfg80211_connect_params connect;
8720 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008721 struct cfg80211_cached_keys *connkeys = NULL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008722 int err;
8723
8724 memset(&connect, 0, sizeof(connect));
8725
8726 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8727 return -EINVAL;
8728
8729 if (!info->attrs[NL80211_ATTR_SSID] ||
8730 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8731 return -EINVAL;
8732
8733 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
8734 connect.auth_type =
8735 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008736 if (!nl80211_valid_auth_type(rdev, connect.auth_type,
8737 NL80211_CMD_CONNECT))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008738 return -EINVAL;
8739 } else
8740 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
8741
8742 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
8743
Johannes Bergc0692b82010-08-27 14:26:53 +03008744 err = nl80211_crypto_settings(rdev, info, &connect.crypto,
Johannes Berg3dc27d22009-07-02 21:36:37 +02008745 NL80211_MAX_NR_CIPHER_SUITES);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008746 if (err)
8747 return err;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008748
Johannes Berg074ac8d2010-09-16 14:58:22 +02008749 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008750 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8751 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008752
Johannes Berg79c97e92009-07-07 03:56:12 +02008753 wiphy = &rdev->wiphy;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008754
Bala Shanmugam4486ea92012-03-07 17:27:12 +05308755 connect.bg_scan_period = -1;
8756 if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
8757 (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
8758 connect.bg_scan_period =
8759 nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
8760 }
8761
Samuel Ortizb23aa672009-07-01 21:26:54 +02008762 if (info->attrs[NL80211_ATTR_MAC])
8763 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen1df4a512014-01-15 00:00:47 +02008764 else if (info->attrs[NL80211_ATTR_MAC_HINT])
8765 connect.bssid_hint =
8766 nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008767 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8768 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8769
8770 if (info->attrs[NL80211_ATTR_IE]) {
8771 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8772 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8773 }
8774
Jouni Malinencee00a92013-01-15 17:15:57 +02008775 if (info->attrs[NL80211_ATTR_USE_MFP]) {
8776 connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
8777 if (connect.mfp != NL80211_MFP_REQUIRED &&
8778 connect.mfp != NL80211_MFP_NO)
8779 return -EINVAL;
8780 } else {
8781 connect.mfp = NL80211_MFP_NO;
8782 }
8783
Jouni Malinenba6fbac2016-03-29 13:53:27 +03008784 if (info->attrs[NL80211_ATTR_PREV_BSSID])
8785 connect.prev_bssid =
8786 nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
8787
Samuel Ortizb23aa672009-07-01 21:26:54 +02008788 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02008789 connect.channel = nl80211_get_valid_chan(
8790 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8791 if (!connect.channel)
Johannes Berg4c476992010-10-04 21:36:35 +02008792 return -EINVAL;
Jouni Malinen1df4a512014-01-15 00:00:47 +02008793 } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02008794 connect.channel_hint = nl80211_get_valid_chan(
8795 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
8796 if (!connect.channel_hint)
Jouni Malinen1df4a512014-01-15 00:00:47 +02008797 return -EINVAL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008798 }
8799
Johannes Bergfffd0932009-07-08 14:22:54 +02008800 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
8801 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308802 info->attrs[NL80211_ATTR_KEYS], NULL);
Johannes Berg4c476992010-10-04 21:36:35 +02008803 if (IS_ERR(connkeys))
8804 return PTR_ERR(connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008805 }
8806
Ben Greear7e7c8922011-11-18 11:31:59 -08008807 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
8808 connect.flags |= ASSOC_REQ_DISABLE_HT;
8809
8810 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8811 memcpy(&connect.ht_capa_mask,
8812 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8813 sizeof(connect.ht_capa_mask));
8814
8815 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Wei Yongjunb4e4f472012-09-02 21:41:04 +08008816 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03008817 kzfree(connkeys);
Ben Greear7e7c8922011-11-18 11:31:59 -08008818 return -EINVAL;
Wei Yongjunb4e4f472012-09-02 21:41:04 +08008819 }
Ben Greear7e7c8922011-11-18 11:31:59 -08008820 memcpy(&connect.ht_capa,
8821 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8822 sizeof(connect.ht_capa));
8823 }
8824
Johannes Bergee2aca32013-02-21 17:36:01 +01008825 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
8826 connect.flags |= ASSOC_REQ_DISABLE_VHT;
8827
8828 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
8829 memcpy(&connect.vht_capa_mask,
8830 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8831 sizeof(connect.vht_capa_mask));
8832
8833 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
8834 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03008835 kzfree(connkeys);
Johannes Bergee2aca32013-02-21 17:36:01 +01008836 return -EINVAL;
8837 }
8838 memcpy(&connect.vht_capa,
8839 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8840 sizeof(connect.vht_capa));
8841 }
8842
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008843 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008844 if (!((rdev->wiphy.features &
8845 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8846 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8847 !wiphy_ext_feature_isset(&rdev->wiphy,
8848 NL80211_EXT_FEATURE_RRM)) {
Ola Olsson707554b2015-12-11 21:04:52 +01008849 kzfree(connkeys);
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008850 return -EINVAL;
Ola Olsson707554b2015-12-11 21:04:52 +01008851 }
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008852 connect.flags |= ASSOC_REQ_USE_RRM;
8853 }
8854
Lior David34d50512016-01-28 10:58:25 +02008855 connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
Johannes Berg57fbcce2016-04-12 15:56:15 +02008856 if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
Lior David34d50512016-01-28 10:58:25 +02008857 kzfree(connkeys);
8858 return -EOPNOTSUPP;
8859 }
8860
Arend van Spriel38de03d2016-03-02 20:37:18 +01008861 if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
8862 /* bss selection makes no sense if bssid is set */
8863 if (connect.bssid) {
8864 kzfree(connkeys);
8865 return -EINVAL;
8866 }
8867
8868 err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
8869 wiphy, &connect.bss_select);
8870 if (err) {
8871 kzfree(connkeys);
8872 return err;
8873 }
8874 }
8875
Johannes Berg83739b02013-05-15 17:44:01 +02008876 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008877
Jouni Malinen4ce2bd92016-03-29 13:53:28 +03008878 err = cfg80211_connect(rdev, dev, &connect, connkeys,
8879 connect.prev_bssid);
Johannes Bergfffd0932009-07-08 14:22:54 +02008880 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008881 kzfree(connkeys);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008882
8883 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8884 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
8885 if (connect.bssid)
8886 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8887 connect.bssid, ETH_ALEN);
8888 else
8889 memset(dev->ieee80211_ptr->disconnect_bssid,
8890 0, ETH_ALEN);
8891 }
8892
8893 wdev_unlock(dev->ieee80211_ptr);
8894
Samuel Ortizb23aa672009-07-01 21:26:54 +02008895 return err;
8896}
8897
vamsi krishna088e8df2016-10-27 16:51:11 +03008898static int nl80211_update_connect_params(struct sk_buff *skb,
8899 struct genl_info *info)
8900{
8901 struct cfg80211_connect_params connect = {};
8902 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8903 struct net_device *dev = info->user_ptr[1];
8904 struct wireless_dev *wdev = dev->ieee80211_ptr;
8905 u32 changed = 0;
8906 int ret;
8907
8908 if (!rdev->ops->update_connect_params)
8909 return -EOPNOTSUPP;
8910
8911 if (info->attrs[NL80211_ATTR_IE]) {
8912 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8913 return -EINVAL;
8914 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8915 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8916 changed |= UPDATE_ASSOC_IES;
8917 }
8918
8919 wdev_lock(dev->ieee80211_ptr);
8920 if (!wdev->current_bss)
8921 ret = -ENOLINK;
8922 else
8923 ret = rdev_update_connect_params(rdev, dev, &connect, changed);
8924 wdev_unlock(dev->ieee80211_ptr);
8925
8926 return ret;
8927}
8928
Samuel Ortizb23aa672009-07-01 21:26:54 +02008929static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
8930{
Johannes Berg4c476992010-10-04 21:36:35 +02008931 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8932 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02008933 u16 reason;
Johannes Berg83739b02013-05-15 17:44:01 +02008934 int ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008935
8936 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8937 reason = WLAN_REASON_DEAUTH_LEAVING;
8938 else
8939 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8940
8941 if (reason == 0)
8942 return -EINVAL;
8943
Johannes Berg074ac8d2010-09-16 14:58:22 +02008944 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008945 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8946 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008947
Johannes Berg83739b02013-05-15 17:44:01 +02008948 wdev_lock(dev->ieee80211_ptr);
8949 ret = cfg80211_disconnect(rdev, dev, reason, true);
8950 wdev_unlock(dev->ieee80211_ptr);
8951 return ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008952}
8953
Johannes Berg463d0182009-07-14 00:33:35 +02008954static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
8955{
Johannes Berg4c476992010-10-04 21:36:35 +02008956 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg463d0182009-07-14 00:33:35 +02008957 struct net *net;
8958 int err;
Johannes Berg463d0182009-07-14 00:33:35 +02008959
Vadim Kochan4b681c82015-01-12 16:34:05 +02008960 if (info->attrs[NL80211_ATTR_PID]) {
8961 u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
8962
8963 net = get_net_ns_by_pid(pid);
8964 } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
8965 u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
8966
8967 net = get_net_ns_by_fd(fd);
8968 } else {
Johannes Berg463d0182009-07-14 00:33:35 +02008969 return -EINVAL;
Vadim Kochan4b681c82015-01-12 16:34:05 +02008970 }
Johannes Berg463d0182009-07-14 00:33:35 +02008971
Johannes Berg4c476992010-10-04 21:36:35 +02008972 if (IS_ERR(net))
8973 return PTR_ERR(net);
Johannes Berg463d0182009-07-14 00:33:35 +02008974
8975 err = 0;
8976
8977 /* check if anything to do */
Johannes Berg4c476992010-10-04 21:36:35 +02008978 if (!net_eq(wiphy_net(&rdev->wiphy), net))
8979 err = cfg80211_switch_netns(rdev, net);
Johannes Berg463d0182009-07-14 00:33:35 +02008980
Johannes Berg463d0182009-07-14 00:33:35 +02008981 put_net(net);
Johannes Berg463d0182009-07-14 00:33:35 +02008982 return err;
8983}
8984
Samuel Ortiz67fbb162009-11-24 23:59:15 +01008985static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
8986{
Johannes Berg4c476992010-10-04 21:36:35 +02008987 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01008988 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
8989 struct cfg80211_pmksa *pmksa) = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02008990 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01008991 struct cfg80211_pmksa pmksa;
8992
8993 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
8994
8995 if (!info->attrs[NL80211_ATTR_MAC])
8996 return -EINVAL;
8997
8998 if (!info->attrs[NL80211_ATTR_PMKID])
8999 return -EINVAL;
9000
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009001 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
9002 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9003
Johannes Berg074ac8d2010-09-16 14:58:22 +02009004 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009005 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9006 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009007
9008 switch (info->genlhdr->cmd) {
9009 case NL80211_CMD_SET_PMKSA:
9010 rdev_ops = rdev->ops->set_pmksa;
9011 break;
9012 case NL80211_CMD_DEL_PMKSA:
9013 rdev_ops = rdev->ops->del_pmksa;
9014 break;
9015 default:
9016 WARN_ON(1);
9017 break;
9018 }
9019
Johannes Berg4c476992010-10-04 21:36:35 +02009020 if (!rdev_ops)
9021 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009022
Johannes Berg4c476992010-10-04 21:36:35 +02009023 return rdev_ops(&rdev->wiphy, dev, &pmksa);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009024}
9025
9026static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
9027{
Johannes Berg4c476992010-10-04 21:36:35 +02009028 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9029 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009030
Johannes Berg074ac8d2010-09-16 14:58:22 +02009031 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009032 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9033 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009034
Johannes Berg4c476992010-10-04 21:36:35 +02009035 if (!rdev->ops->flush_pmksa)
9036 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009037
Hila Gonene35e4d22012-06-27 17:19:42 +03009038 return rdev_flush_pmksa(rdev, dev);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009039}
9040
Arik Nemtsov109086c2011-09-28 14:12:50 +03009041static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
9042{
9043 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9044 struct net_device *dev = info->user_ptr[1];
9045 u8 action_code, dialog_token;
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309046 u32 peer_capability = 0;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009047 u16 status_code;
9048 u8 *peer;
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009049 bool initiator;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009050
9051 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9052 !rdev->ops->tdls_mgmt)
9053 return -EOPNOTSUPP;
9054
9055 if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
9056 !info->attrs[NL80211_ATTR_STATUS_CODE] ||
9057 !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
9058 !info->attrs[NL80211_ATTR_IE] ||
9059 !info->attrs[NL80211_ATTR_MAC])
9060 return -EINVAL;
9061
9062 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9063 action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
9064 status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
9065 dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009066 initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309067 if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
9068 peer_capability =
9069 nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009070
Hila Gonene35e4d22012-06-27 17:19:42 +03009071 return rdev_tdls_mgmt(rdev, dev, peer, action_code,
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309072 dialog_token, status_code, peer_capability,
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009073 initiator,
Hila Gonene35e4d22012-06-27 17:19:42 +03009074 nla_data(info->attrs[NL80211_ATTR_IE]),
9075 nla_len(info->attrs[NL80211_ATTR_IE]));
Arik Nemtsov109086c2011-09-28 14:12:50 +03009076}
9077
9078static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
9079{
9080 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9081 struct net_device *dev = info->user_ptr[1];
9082 enum nl80211_tdls_operation operation;
9083 u8 *peer;
9084
9085 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9086 !rdev->ops->tdls_oper)
9087 return -EOPNOTSUPP;
9088
9089 if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
9090 !info->attrs[NL80211_ATTR_MAC])
9091 return -EINVAL;
9092
9093 operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
9094 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9095
Hila Gonene35e4d22012-06-27 17:19:42 +03009096 return rdev_tdls_oper(rdev, dev, peer, operation);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009097}
9098
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009099static int nl80211_remain_on_channel(struct sk_buff *skb,
9100 struct genl_info *info)
9101{
Johannes Berg4c476992010-10-04 21:36:35 +02009102 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009103 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009104 struct cfg80211_chan_def chandef;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009105 struct sk_buff *msg;
9106 void *hdr;
9107 u64 cookie;
Johannes Berg683b6d32012-11-08 21:25:48 +01009108 u32 duration;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009109 int err;
9110
9111 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
9112 !info->attrs[NL80211_ATTR_DURATION])
9113 return -EINVAL;
9114
9115 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
9116
Johannes Berg7c4ef712011-11-18 15:33:48 +01009117 if (!rdev->ops->remain_on_channel ||
9118 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
Johannes Berg4c476992010-10-04 21:36:35 +02009119 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009120
Johannes Bergebf348f2012-06-01 12:50:54 +02009121 /*
9122 * We should be on that channel for at least a minimum amount of
9123 * time (10ms) but no longer than the driver supports.
9124 */
9125 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9126 duration > rdev->wiphy.max_remain_on_channel_duration)
9127 return -EINVAL;
9128
Johannes Berg683b6d32012-11-08 21:25:48 +01009129 err = nl80211_parse_chandef(rdev, info, &chandef);
9130 if (err)
9131 return err;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009132
9133 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009134 if (!msg)
9135 return -ENOMEM;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009136
Eric W. Biederman15e47302012-09-07 20:12:54 +00009137 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009138 NL80211_CMD_REMAIN_ON_CHANNEL);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009139 if (!hdr) {
9140 err = -ENOBUFS;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009141 goto free_msg;
9142 }
9143
Johannes Berg683b6d32012-11-08 21:25:48 +01009144 err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
9145 duration, &cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009146
9147 if (err)
9148 goto free_msg;
9149
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009150 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9151 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009152 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009153
9154 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009155
9156 return genlmsg_reply(msg, info);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009157
9158 nla_put_failure:
9159 err = -ENOBUFS;
9160 free_msg:
9161 nlmsg_free(msg);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009162 return err;
9163}
9164
9165static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
9166 struct genl_info *info)
9167{
Johannes Berg4c476992010-10-04 21:36:35 +02009168 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009169 struct wireless_dev *wdev = info->user_ptr[1];
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009170 u64 cookie;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009171
9172 if (!info->attrs[NL80211_ATTR_COOKIE])
9173 return -EINVAL;
9174
Johannes Berg4c476992010-10-04 21:36:35 +02009175 if (!rdev->ops->cancel_remain_on_channel)
9176 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009177
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009178 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9179
Hila Gonene35e4d22012-06-27 17:19:42 +03009180 return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009181}
9182
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009183static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
9184 struct genl_info *info)
9185{
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009186 struct cfg80211_bitrate_mask mask;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309187 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009188 struct net_device *dev = info->user_ptr[1];
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309189 int err;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009190
Johannes Berg4c476992010-10-04 21:36:35 +02009191 if (!rdev->ops->set_bitrate_mask)
9192 return -EOPNOTSUPP;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009193
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309194 err = nl80211_parse_tx_bitrate_mask(info, &mask);
9195 if (err)
9196 return err;
Janusz Dziedzic78693032013-12-03 09:50:44 +01009197
Hila Gonene35e4d22012-06-27 17:19:42 +03009198 return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009199}
9200
Johannes Berg2e161f782010-08-12 15:38:38 +02009201static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009202{
Johannes Berg4c476992010-10-04 21:36:35 +02009203 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009204 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2e161f782010-08-12 15:38:38 +02009205 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
Jouni Malinen026331c2010-02-15 12:53:10 +02009206
9207 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
9208 return -EINVAL;
9209
Johannes Berg2e161f782010-08-12 15:38:38 +02009210 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
9211 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
Jouni Malinen026331c2010-02-15 12:53:10 +02009212
Johannes Berg71bbc992012-06-15 15:30:18 +02009213 switch (wdev->iftype) {
9214 case NL80211_IFTYPE_STATION:
9215 case NL80211_IFTYPE_ADHOC:
9216 case NL80211_IFTYPE_P2P_CLIENT:
9217 case NL80211_IFTYPE_AP:
9218 case NL80211_IFTYPE_AP_VLAN:
9219 case NL80211_IFTYPE_MESH_POINT:
9220 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009221 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009222 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009223 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009224 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009225 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009226 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009227
9228 /* not much point in registering if we can't reply */
Johannes Berg4c476992010-10-04 21:36:35 +02009229 if (!rdev->ops->mgmt_tx)
9230 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009231
Eric W. Biederman15e47302012-09-07 20:12:54 +00009232 return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
Jouni Malinen026331c2010-02-15 12:53:10 +02009233 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
9234 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
Jouni Malinen026331c2010-02-15 12:53:10 +02009235}
9236
Johannes Berg2e161f782010-08-12 15:38:38 +02009237static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009238{
Johannes Berg4c476992010-10-04 21:36:35 +02009239 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009240 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009241 struct cfg80211_chan_def chandef;
Jouni Malinen026331c2010-02-15 12:53:10 +02009242 int err;
Johannes Bergd64d3732011-11-10 09:44:46 +01009243 void *hdr = NULL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009244 u64 cookie;
Johannes Berge247bd902011-11-04 11:18:21 +01009245 struct sk_buff *msg = NULL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009246 struct cfg80211_mgmt_tx_params params = {
9247 .dont_wait_for_ack =
9248 info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
9249 };
Jouni Malinen026331c2010-02-15 12:53:10 +02009250
Johannes Berg683b6d32012-11-08 21:25:48 +01009251 if (!info->attrs[NL80211_ATTR_FRAME])
Jouni Malinen026331c2010-02-15 12:53:10 +02009252 return -EINVAL;
9253
Johannes Berg4c476992010-10-04 21:36:35 +02009254 if (!rdev->ops->mgmt_tx)
9255 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009256
Johannes Berg71bbc992012-06-15 15:30:18 +02009257 switch (wdev->iftype) {
Antonio Quartulliea141b752013-06-11 14:20:03 +02009258 case NL80211_IFTYPE_P2P_DEVICE:
9259 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
9260 return -EINVAL;
Johannes Berg71bbc992012-06-15 15:30:18 +02009261 case NL80211_IFTYPE_STATION:
9262 case NL80211_IFTYPE_ADHOC:
9263 case NL80211_IFTYPE_P2P_CLIENT:
9264 case NL80211_IFTYPE_AP:
9265 case NL80211_IFTYPE_AP_VLAN:
9266 case NL80211_IFTYPE_MESH_POINT:
9267 case NL80211_IFTYPE_P2P_GO:
9268 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009269 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009270 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009271 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009272 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009273
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009274 if (info->attrs[NL80211_ATTR_DURATION]) {
Johannes Berg7c4ef712011-11-18 15:33:48 +01009275 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009276 return -EINVAL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009277 params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
Johannes Bergebf348f2012-06-01 12:50:54 +02009278
9279 /*
9280 * We should wait on the channel for at least a minimum amount
9281 * of time (10ms) but no longer than the driver supports.
9282 */
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009283 if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9284 params.wait > rdev->wiphy.max_remain_on_channel_duration)
Johannes Bergebf348f2012-06-01 12:50:54 +02009285 return -EINVAL;
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009286 }
9287
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009288 params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009289
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009290 if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Berg7c4ef712011-11-18 15:33:48 +01009291 return -EINVAL;
9292
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009293 params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05309294
Antonio Quartulliea141b752013-06-11 14:20:03 +02009295 /* get the channel if any has been specified, otherwise pass NULL to
9296 * the driver. The latter will use the current one
9297 */
9298 chandef.chan = NULL;
9299 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
9300 err = nl80211_parse_chandef(rdev, info, &chandef);
9301 if (err)
9302 return err;
9303 }
9304
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009305 if (!chandef.chan && params.offchan)
Antonio Quartulliea141b752013-06-11 14:20:03 +02009306 return -EINVAL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009307
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +03009308 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
9309 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
9310
9311 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
9312 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9313 int i;
9314
9315 if (len % sizeof(u16))
9316 return -EINVAL;
9317
9318 params.n_csa_offsets = len / sizeof(u16);
9319 params.csa_offsets =
9320 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9321
9322 /* check that all the offsets fit the frame */
9323 for (i = 0; i < params.n_csa_offsets; i++) {
9324 if (params.csa_offsets[i] >= params.len)
9325 return -EINVAL;
9326 }
9327 }
9328
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009329 if (!params.dont_wait_for_ack) {
Johannes Berge247bd902011-11-04 11:18:21 +01009330 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9331 if (!msg)
9332 return -ENOMEM;
Jouni Malinen026331c2010-02-15 12:53:10 +02009333
Eric W. Biederman15e47302012-09-07 20:12:54 +00009334 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berge247bd902011-11-04 11:18:21 +01009335 NL80211_CMD_FRAME);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009336 if (!hdr) {
9337 err = -ENOBUFS;
Johannes Berge247bd902011-11-04 11:18:21 +01009338 goto free_msg;
9339 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009340 }
Johannes Berge247bd902011-11-04 11:18:21 +01009341
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009342 params.chan = chandef.chan;
9343 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
Jouni Malinen026331c2010-02-15 12:53:10 +02009344 if (err)
9345 goto free_msg;
9346
Johannes Berge247bd902011-11-04 11:18:21 +01009347 if (msg) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009348 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9349 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009350 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +02009351
Johannes Berge247bd902011-11-04 11:18:21 +01009352 genlmsg_end(msg, hdr);
9353 return genlmsg_reply(msg, info);
9354 }
9355
9356 return 0;
Jouni Malinen026331c2010-02-15 12:53:10 +02009357
9358 nla_put_failure:
9359 err = -ENOBUFS;
9360 free_msg:
9361 nlmsg_free(msg);
Jouni Malinen026331c2010-02-15 12:53:10 +02009362 return err;
9363}
9364
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009365static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
9366{
9367 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009368 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009369 u64 cookie;
9370
9371 if (!info->attrs[NL80211_ATTR_COOKIE])
9372 return -EINVAL;
9373
9374 if (!rdev->ops->mgmt_tx_cancel_wait)
9375 return -EOPNOTSUPP;
9376
Johannes Berg71bbc992012-06-15 15:30:18 +02009377 switch (wdev->iftype) {
9378 case NL80211_IFTYPE_STATION:
9379 case NL80211_IFTYPE_ADHOC:
9380 case NL80211_IFTYPE_P2P_CLIENT:
9381 case NL80211_IFTYPE_AP:
9382 case NL80211_IFTYPE_AP_VLAN:
9383 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009384 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009385 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009386 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009387 default:
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009388 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009389 }
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009390
9391 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9392
Hila Gonene35e4d22012-06-27 17:19:42 +03009393 return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009394}
9395
Kalle Valoffb9eb32010-02-17 17:58:10 +02009396static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
9397{
Johannes Berg4c476992010-10-04 21:36:35 +02009398 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009399 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009400 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009401 u8 ps_state;
9402 bool state;
9403 int err;
9404
Johannes Berg4c476992010-10-04 21:36:35 +02009405 if (!info->attrs[NL80211_ATTR_PS_STATE])
9406 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009407
9408 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
9409
Johannes Berg4c476992010-10-04 21:36:35 +02009410 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
9411 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009412
9413 wdev = dev->ieee80211_ptr;
9414
Johannes Berg4c476992010-10-04 21:36:35 +02009415 if (!rdev->ops->set_power_mgmt)
9416 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009417
9418 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
9419
9420 if (state == wdev->ps)
Johannes Berg4c476992010-10-04 21:36:35 +02009421 return 0;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009422
Hila Gonene35e4d22012-06-27 17:19:42 +03009423 err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
Johannes Berg4c476992010-10-04 21:36:35 +02009424 if (!err)
9425 wdev->ps = state;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009426 return err;
9427}
9428
9429static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
9430{
Johannes Berg4c476992010-10-04 21:36:35 +02009431 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009432 enum nl80211_ps_state ps_state;
9433 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009434 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009435 struct sk_buff *msg;
9436 void *hdr;
9437 int err;
9438
Kalle Valoffb9eb32010-02-17 17:58:10 +02009439 wdev = dev->ieee80211_ptr;
9440
Johannes Berg4c476992010-10-04 21:36:35 +02009441 if (!rdev->ops->set_power_mgmt)
9442 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009443
9444 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009445 if (!msg)
9446 return -ENOMEM;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009447
Eric W. Biederman15e47302012-09-07 20:12:54 +00009448 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Kalle Valoffb9eb32010-02-17 17:58:10 +02009449 NL80211_CMD_GET_POWER_SAVE);
9450 if (!hdr) {
Johannes Berg4c476992010-10-04 21:36:35 +02009451 err = -ENOBUFS;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009452 goto free_msg;
9453 }
9454
9455 if (wdev->ps)
9456 ps_state = NL80211_PS_ENABLED;
9457 else
9458 ps_state = NL80211_PS_DISABLED;
9459
David S. Miller9360ffd2012-03-29 04:41:26 -04009460 if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
9461 goto nla_put_failure;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009462
9463 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009464 return genlmsg_reply(msg, info);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009465
Johannes Berg4c476992010-10-04 21:36:35 +02009466 nla_put_failure:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009467 err = -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +02009468 free_msg:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009469 nlmsg_free(msg);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009470 return err;
9471}
9472
Johannes Berg94e860f2014-01-20 23:58:15 +01009473static const struct nla_policy
9474nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009475 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
9476 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
9477 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
Thomas Pedersen84f10702012-07-12 16:17:33 -07009478 [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
9479 [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
9480 [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +01009481 [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009482};
9483
Thomas Pedersen84f10702012-07-12 16:17:33 -07009484static int nl80211_set_cqm_txe(struct genl_info *info,
Johannes Bergd9d8b012012-11-26 12:51:52 +01009485 u32 rate, u32 pkts, u32 intvl)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009486{
9487 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Thomas Pedersen84f10702012-07-12 16:17:33 -07009488 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009489 struct wireless_dev *wdev = dev->ieee80211_ptr;
Thomas Pedersen84f10702012-07-12 16:17:33 -07009490
Johannes Bergd9d8b012012-11-26 12:51:52 +01009491 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009492 return -EINVAL;
9493
Thomas Pedersen84f10702012-07-12 16:17:33 -07009494 if (!rdev->ops->set_cqm_txe_config)
9495 return -EOPNOTSUPP;
9496
9497 if (wdev->iftype != NL80211_IFTYPE_STATION &&
9498 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9499 return -EOPNOTSUPP;
9500
Hila Gonene35e4d22012-06-27 17:19:42 +03009501 return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
Thomas Pedersen84f10702012-07-12 16:17:33 -07009502}
9503
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009504static int nl80211_set_cqm_rssi(struct genl_info *info,
9505 s32 threshold, u32 hysteresis)
9506{
Johannes Berg4c476992010-10-04 21:36:35 +02009507 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009508 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009509 struct wireless_dev *wdev = dev->ieee80211_ptr;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009510
9511 if (threshold > 0)
9512 return -EINVAL;
9513
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009514 /* disabling - hysteresis should also be zero then */
9515 if (threshold == 0)
9516 hysteresis = 0;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009517
Johannes Berg4c476992010-10-04 21:36:35 +02009518 if (!rdev->ops->set_cqm_rssi_config)
9519 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009520
Johannes Berg074ac8d2010-09-16 14:58:22 +02009521 if (wdev->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009522 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9523 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009524
Hila Gonene35e4d22012-06-27 17:19:42 +03009525 return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009526}
9527
9528static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
9529{
9530 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
9531 struct nlattr *cqm;
9532 int err;
9533
9534 cqm = info->attrs[NL80211_ATTR_CQM];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009535 if (!cqm)
9536 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009537
9538 err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
9539 nl80211_attr_cqm_policy);
9540 if (err)
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009541 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009542
9543 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
9544 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009545 s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
9546 u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009547
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009548 return nl80211_set_cqm_rssi(info, threshold, hysteresis);
9549 }
9550
9551 if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
9552 attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
9553 attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
9554 u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
9555 u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
9556 u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
9557
9558 return nl80211_set_cqm_txe(info, rate, pkts, intvl);
9559 }
9560
9561 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009562}
9563
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01009564static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
9565{
9566 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9567 struct net_device *dev = info->user_ptr[1];
9568 struct ocb_setup setup = {};
9569 int err;
9570
9571 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9572 if (err)
9573 return err;
9574
9575 return cfg80211_join_ocb(rdev, dev, &setup);
9576}
9577
9578static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
9579{
9580 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9581 struct net_device *dev = info->user_ptr[1];
9582
9583 return cfg80211_leave_ocb(rdev, dev);
9584}
9585
Johannes Berg29cbe682010-12-03 09:20:44 +01009586static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
9587{
9588 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9589 struct net_device *dev = info->user_ptr[1];
9590 struct mesh_config cfg;
Javier Cardonac80d5452010-12-16 17:37:49 -08009591 struct mesh_setup setup;
Johannes Berg29cbe682010-12-03 09:20:44 +01009592 int err;
9593
9594 /* start with default */
9595 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
Javier Cardonac80d5452010-12-16 17:37:49 -08009596 memcpy(&setup, &default_mesh_setup, sizeof(setup));
Johannes Berg29cbe682010-12-03 09:20:44 +01009597
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009598 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01009599 /* and parse parameters if given */
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009600 err = nl80211_parse_mesh_config(info, &cfg, NULL);
Johannes Berg29cbe682010-12-03 09:20:44 +01009601 if (err)
9602 return err;
9603 }
9604
9605 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
9606 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
9607 return -EINVAL;
9608
Javier Cardonac80d5452010-12-16 17:37:49 -08009609 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
9610 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
9611
Chun-Yeow Yeoh4bb62342011-11-24 17:15:20 -08009612 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
9613 !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
9614 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
9615 return -EINVAL;
9616
Marco Porsch9bdbf042013-01-07 16:04:51 +01009617 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
9618 setup.beacon_interval =
9619 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309620
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05309621 err = cfg80211_validate_beacon_int(rdev,
9622 NL80211_IFTYPE_MESH_POINT,
9623 setup.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309624 if (err)
9625 return err;
Marco Porsch9bdbf042013-01-07 16:04:51 +01009626 }
9627
9628 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
9629 setup.dtim_period =
9630 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
9631 if (setup.dtim_period < 1 || setup.dtim_period > 100)
9632 return -EINVAL;
9633 }
9634
Javier Cardonac80d5452010-12-16 17:37:49 -08009635 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
9636 /* parse additional setup parameters if given */
9637 err = nl80211_parse_mesh_setup(info, &setup);
9638 if (err)
9639 return err;
9640 }
9641
Thomas Pedersend37bb182013-03-04 13:06:13 -08009642 if (setup.user_mpm)
9643 cfg.auto_open_plinks = false;
9644
Johannes Bergcc1d2802012-05-16 23:50:20 +02009645 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01009646 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9647 if (err)
9648 return err;
Johannes Bergcc1d2802012-05-16 23:50:20 +02009649 } else {
9650 /* cfg80211_join_mesh() will sort it out */
Johannes Berg683b6d32012-11-08 21:25:48 +01009651 setup.chandef.chan = NULL;
Johannes Bergcc1d2802012-05-16 23:50:20 +02009652 }
9653
Ashok Nagarajanffb3cf32013-06-03 10:33:36 -07009654 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
9655 u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9656 int n_rates =
9657 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9658 struct ieee80211_supported_band *sband;
9659
9660 if (!setup.chandef.chan)
9661 return -EINVAL;
9662
9663 sband = rdev->wiphy.bands[setup.chandef.chan->band];
9664
9665 err = ieee80211_get_ratemask(sband, rates, n_rates,
9666 &setup.basic_rates);
9667 if (err)
9668 return err;
9669 }
9670
Johannes Berg8564e382016-09-19 09:44:44 +02009671 if (info->attrs[NL80211_ATTR_TX_RATES]) {
9672 err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
9673 if (err)
9674 return err;
9675
9676 err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
9677 &setup.beacon_rate);
9678 if (err)
9679 return err;
9680 }
9681
Javier Cardonac80d5452010-12-16 17:37:49 -08009682 return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01009683}
9684
9685static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
9686{
9687 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9688 struct net_device *dev = info->user_ptr[1];
9689
9690 return cfg80211_leave_mesh(rdev, dev);
9691}
9692
Johannes Bergdfb89c52012-06-27 09:23:48 +02009693#ifdef CONFIG_PM
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009694static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
9695 struct cfg80211_registered_device *rdev)
9696{
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009697 struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009698 struct nlattr *nl_pats, *nl_pat;
9699 int i, pat_len;
9700
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009701 if (!wowlan->n_patterns)
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009702 return 0;
9703
9704 nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
9705 if (!nl_pats)
9706 return -ENOBUFS;
9707
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009708 for (i = 0; i < wowlan->n_patterns; i++) {
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009709 nl_pat = nla_nest_start(msg, i + 1);
9710 if (!nl_pat)
9711 return -ENOBUFS;
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009712 pat_len = wowlan->patterns[i].pattern_len;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07009713 if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009714 wowlan->patterns[i].mask) ||
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07009715 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
9716 wowlan->patterns[i].pattern) ||
9717 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009718 wowlan->patterns[i].pkt_offset))
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009719 return -ENOBUFS;
9720 nla_nest_end(msg, nl_pat);
9721 }
9722 nla_nest_end(msg, nl_pats);
9723
9724 return 0;
9725}
9726
Johannes Berg2a0e0472013-01-23 22:57:40 +01009727static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
9728 struct cfg80211_wowlan_tcp *tcp)
9729{
9730 struct nlattr *nl_tcp;
9731
9732 if (!tcp)
9733 return 0;
9734
9735 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
9736 if (!nl_tcp)
9737 return -ENOBUFS;
9738
Jiri Benc930345e2015-03-29 16:59:25 +02009739 if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
9740 nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
Johannes Berg2a0e0472013-01-23 22:57:40 +01009741 nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
9742 nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
9743 nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
9744 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
9745 tcp->payload_len, tcp->payload) ||
9746 nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
9747 tcp->data_interval) ||
9748 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
9749 tcp->wake_len, tcp->wake_data) ||
9750 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
9751 DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
9752 return -ENOBUFS;
9753
9754 if (tcp->payload_seq.len &&
9755 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
9756 sizeof(tcp->payload_seq), &tcp->payload_seq))
9757 return -ENOBUFS;
9758
9759 if (tcp->payload_tok.len &&
9760 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
9761 sizeof(tcp->payload_tok) + tcp->tokens_size,
9762 &tcp->payload_tok))
9763 return -ENOBUFS;
9764
Johannes Berge248ad32013-05-16 10:24:28 +02009765 nla_nest_end(msg, nl_tcp);
9766
Johannes Berg2a0e0472013-01-23 22:57:40 +01009767 return 0;
9768}
9769
Luciano Coelho75453cc2015-01-09 14:06:37 +02009770static int nl80211_send_wowlan_nd(struct sk_buff *msg,
9771 struct cfg80211_sched_scan_request *req)
9772{
Avraham Stern3b06d272015-10-12 09:51:34 +03009773 struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
Luciano Coelho75453cc2015-01-09 14:06:37 +02009774 int i;
9775
9776 if (!req)
9777 return 0;
9778
9779 nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
9780 if (!nd)
9781 return -ENOBUFS;
9782
Avraham Stern3b06d272015-10-12 09:51:34 +03009783 if (req->n_scan_plans == 1 &&
9784 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
9785 req->scan_plans[0].interval * 1000))
Luciano Coelho75453cc2015-01-09 14:06:37 +02009786 return -ENOBUFS;
9787
Luciano Coelho21fea562015-03-17 16:36:01 +02009788 if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
9789 return -ENOBUFS;
9790
vamsi krishnabf95ecd2017-01-13 01:12:20 +02009791 if (req->relative_rssi_set) {
9792 struct nl80211_bss_select_rssi_adjust rssi_adjust;
9793
9794 if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
9795 req->relative_rssi))
9796 return -ENOBUFS;
9797
9798 rssi_adjust.band = req->rssi_adjust.band;
9799 rssi_adjust.delta = req->rssi_adjust.delta;
9800 if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
9801 sizeof(rssi_adjust), &rssi_adjust))
9802 return -ENOBUFS;
9803 }
9804
Luciano Coelho75453cc2015-01-09 14:06:37 +02009805 freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
9806 if (!freqs)
9807 return -ENOBUFS;
9808
Johannes Berg53b18982016-09-14 09:59:21 +02009809 for (i = 0; i < req->n_channels; i++) {
9810 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
9811 return -ENOBUFS;
9812 }
Luciano Coelho75453cc2015-01-09 14:06:37 +02009813
9814 nla_nest_end(msg, freqs);
9815
9816 if (req->n_match_sets) {
9817 matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009818 if (!matches)
9819 return -ENOBUFS;
9820
Luciano Coelho75453cc2015-01-09 14:06:37 +02009821 for (i = 0; i < req->n_match_sets; i++) {
9822 match = nla_nest_start(msg, i);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009823 if (!match)
9824 return -ENOBUFS;
9825
Johannes Berg53b18982016-09-14 09:59:21 +02009826 if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
9827 req->match_sets[i].ssid.ssid_len,
9828 req->match_sets[i].ssid.ssid))
9829 return -ENOBUFS;
Luciano Coelho75453cc2015-01-09 14:06:37 +02009830 nla_nest_end(msg, match);
9831 }
9832 nla_nest_end(msg, matches);
9833 }
9834
Avraham Stern3b06d272015-10-12 09:51:34 +03009835 scan_plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
9836 if (!scan_plans)
9837 return -ENOBUFS;
9838
9839 for (i = 0; i < req->n_scan_plans; i++) {
9840 scan_plan = nla_nest_start(msg, i + 1);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009841 if (!scan_plan)
9842 return -ENOBUFS;
9843
Avraham Stern3b06d272015-10-12 09:51:34 +03009844 if (!scan_plan ||
9845 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
9846 req->scan_plans[i].interval) ||
9847 (req->scan_plans[i].iterations &&
9848 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
9849 req->scan_plans[i].iterations)))
9850 return -ENOBUFS;
9851 nla_nest_end(msg, scan_plan);
9852 }
9853 nla_nest_end(msg, scan_plans);
9854
Luciano Coelho75453cc2015-01-09 14:06:37 +02009855 nla_nest_end(msg, nd);
9856
9857 return 0;
9858}
9859
Johannes Bergff1b6e62011-05-04 15:37:28 +02009860static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
9861{
9862 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9863 struct sk_buff *msg;
9864 void *hdr;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009865 u32 size = NLMSG_DEFAULT_SIZE;
Johannes Bergff1b6e62011-05-04 15:37:28 +02009866
Johannes Berg964dc9e2013-06-03 17:25:34 +02009867 if (!rdev->wiphy.wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +02009868 return -EOPNOTSUPP;
9869
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009870 if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
Johannes Berg2a0e0472013-01-23 22:57:40 +01009871 /* adjust size to have room for all the data */
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009872 size += rdev->wiphy.wowlan_config->tcp->tokens_size +
9873 rdev->wiphy.wowlan_config->tcp->payload_len +
9874 rdev->wiphy.wowlan_config->tcp->wake_len +
9875 rdev->wiphy.wowlan_config->tcp->wake_len / 8;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009876 }
9877
9878 msg = nlmsg_new(size, GFP_KERNEL);
Johannes Bergff1b6e62011-05-04 15:37:28 +02009879 if (!msg)
9880 return -ENOMEM;
9881
Eric W. Biederman15e47302012-09-07 20:12:54 +00009882 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Bergff1b6e62011-05-04 15:37:28 +02009883 NL80211_CMD_GET_WOWLAN);
9884 if (!hdr)
9885 goto nla_put_failure;
9886
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009887 if (rdev->wiphy.wowlan_config) {
Johannes Bergff1b6e62011-05-04 15:37:28 +02009888 struct nlattr *nl_wowlan;
9889
9890 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
9891 if (!nl_wowlan)
9892 goto nla_put_failure;
9893
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009894 if ((rdev->wiphy.wowlan_config->any &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009895 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009896 (rdev->wiphy.wowlan_config->disconnect &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009897 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009898 (rdev->wiphy.wowlan_config->magic_pkt &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009899 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009900 (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009901 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009902 (rdev->wiphy.wowlan_config->eap_identity_req &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009903 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009904 (rdev->wiphy.wowlan_config->four_way_handshake &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009905 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009906 (rdev->wiphy.wowlan_config->rfkill_release &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009907 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
9908 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009909
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009910 if (nl80211_send_wowlan_patterns(msg, rdev))
9911 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009912
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009913 if (nl80211_send_wowlan_tcp(msg,
9914 rdev->wiphy.wowlan_config->tcp))
Johannes Berg2a0e0472013-01-23 22:57:40 +01009915 goto nla_put_failure;
9916
Luciano Coelho75453cc2015-01-09 14:06:37 +02009917 if (nl80211_send_wowlan_nd(
9918 msg,
9919 rdev->wiphy.wowlan_config->nd_config))
9920 goto nla_put_failure;
9921
Johannes Bergff1b6e62011-05-04 15:37:28 +02009922 nla_nest_end(msg, nl_wowlan);
9923 }
9924
9925 genlmsg_end(msg, hdr);
9926 return genlmsg_reply(msg, info);
9927
9928nla_put_failure:
9929 nlmsg_free(msg);
9930 return -ENOBUFS;
9931}
9932
Johannes Berg2a0e0472013-01-23 22:57:40 +01009933static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
9934 struct nlattr *attr,
9935 struct cfg80211_wowlan *trig)
9936{
9937 struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
9938 struct cfg80211_wowlan_tcp *cfg;
9939 struct nl80211_wowlan_tcp_data_token *tok = NULL;
9940 struct nl80211_wowlan_tcp_data_seq *seq = NULL;
9941 u32 size;
9942 u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
9943 int err, port;
9944
Johannes Berg964dc9e2013-06-03 17:25:34 +02009945 if (!rdev->wiphy.wowlan->tcp)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009946 return -EINVAL;
9947
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02009948 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TCP, attr,
9949 nl80211_wowlan_tcp_policy);
Johannes Berg2a0e0472013-01-23 22:57:40 +01009950 if (err)
9951 return err;
9952
9953 if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
9954 !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
9955 !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
9956 !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
9957 !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
9958 !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
9959 !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
9960 !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
9961 return -EINVAL;
9962
9963 data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +02009964 if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009965 return -EINVAL;
9966
9967 if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
Johannes Berg964dc9e2013-06-03 17:25:34 +02009968 rdev->wiphy.wowlan->tcp->data_interval_max ||
Johannes Berg723d5682013-02-26 13:56:40 +01009969 nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009970 return -EINVAL;
9971
9972 wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +02009973 if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009974 return -EINVAL;
9975
9976 wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
9977 if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
9978 return -EINVAL;
9979
9980 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
9981 u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
9982
9983 tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
9984 tokens_size = tokln - sizeof(*tok);
9985
9986 if (!tok->len || tokens_size % tok->len)
9987 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +02009988 if (!rdev->wiphy.wowlan->tcp->tok)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009989 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +02009990 if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009991 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +02009992 if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009993 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +02009994 if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
Johannes Berg2a0e0472013-01-23 22:57:40 +01009995 return -EINVAL;
9996 if (tok->offset + tok->len > data_size)
9997 return -EINVAL;
9998 }
9999
10000 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
10001 seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010002 if (!rdev->wiphy.wowlan->tcp->seq)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010003 return -EINVAL;
10004 if (seq->len == 0 || seq->len > 4)
10005 return -EINVAL;
10006 if (seq->len + seq->offset > data_size)
10007 return -EINVAL;
10008 }
10009
10010 size = sizeof(*cfg);
10011 size += data_size;
10012 size += wake_size + wake_mask_size;
10013 size += tokens_size;
10014
10015 cfg = kzalloc(size, GFP_KERNEL);
10016 if (!cfg)
10017 return -ENOMEM;
Jiri Benc67b61f62015-03-29 16:59:26 +020010018 cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
10019 cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010020 memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
10021 ETH_ALEN);
10022 if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
10023 port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
10024 else
10025 port = 0;
10026#ifdef CONFIG_INET
10027 /* allocate a socket and port for it and use it */
10028 err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
10029 IPPROTO_TCP, &cfg->sock, 1);
10030 if (err) {
10031 kfree(cfg);
10032 return err;
10033 }
10034 if (inet_csk_get_port(cfg->sock->sk, port)) {
10035 sock_release(cfg->sock);
10036 kfree(cfg);
10037 return -EADDRINUSE;
10038 }
10039 cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
10040#else
10041 if (!port) {
10042 kfree(cfg);
10043 return -EINVAL;
10044 }
10045 cfg->src_port = port;
10046#endif
10047
10048 cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
10049 cfg->payload_len = data_size;
10050 cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
10051 memcpy((void *)cfg->payload,
10052 nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
10053 data_size);
10054 if (seq)
10055 cfg->payload_seq = *seq;
10056 cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
10057 cfg->wake_len = wake_size;
10058 cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
10059 memcpy((void *)cfg->wake_data,
10060 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
10061 wake_size);
10062 cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
10063 data_size + wake_size;
10064 memcpy((void *)cfg->wake_mask,
10065 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
10066 wake_mask_size);
10067 if (tok) {
10068 cfg->tokens_size = tokens_size;
10069 memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
10070 }
10071
10072 trig->tcp = cfg;
10073
10074 return 0;
10075}
10076
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010077static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
10078 const struct wiphy_wowlan_support *wowlan,
10079 struct nlattr *attr,
10080 struct cfg80211_wowlan *trig)
10081{
10082 struct nlattr **tb;
10083 int err;
10084
10085 tb = kzalloc(NUM_NL80211_ATTR * sizeof(*tb), GFP_KERNEL);
10086 if (!tb)
10087 return -ENOMEM;
10088
10089 if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
10090 err = -EOPNOTSUPP;
10091 goto out;
10092 }
10093
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010094 err = nla_parse_nested(tb, NL80211_ATTR_MAX, attr, nl80211_policy);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010095 if (err)
10096 goto out;
10097
Arend Van Sprielaad1e812017-01-27 12:27:44 +000010098 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb,
10099 wowlan->max_nd_match_sets);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010100 err = PTR_ERR_OR_ZERO(trig->nd_config);
10101 if (err)
10102 trig->nd_config = NULL;
10103
10104out:
10105 kfree(tb);
10106 return err;
10107}
10108
Johannes Bergff1b6e62011-05-04 15:37:28 +020010109static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
10110{
10111 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10112 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010113 struct cfg80211_wowlan new_triggers = {};
Johannes Bergae33bd82012-07-12 16:25:02 +020010114 struct cfg80211_wowlan *ntrig;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010115 const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010116 int err, i;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010117 bool prev_enabled = rdev->wiphy.wowlan_config;
Johannes Berg98fc4382015-03-01 09:10:13 +020010118 bool regular = false;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010119
Johannes Berg964dc9e2013-06-03 17:25:34 +020010120 if (!wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010121 return -EOPNOTSUPP;
10122
Johannes Bergae33bd82012-07-12 16:25:02 +020010123 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
10124 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010125 rdev->wiphy.wowlan_config = NULL;
Johannes Bergae33bd82012-07-12 16:25:02 +020010126 goto set_wakeup;
10127 }
Johannes Bergff1b6e62011-05-04 15:37:28 +020010128
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010129 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TRIG,
10130 info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
10131 nl80211_wowlan_policy);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010132 if (err)
10133 return err;
10134
10135 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
10136 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
10137 return -EINVAL;
10138 new_triggers.any = true;
10139 }
10140
10141 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
10142 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
10143 return -EINVAL;
10144 new_triggers.disconnect = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010145 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010146 }
10147
10148 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
10149 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
10150 return -EINVAL;
10151 new_triggers.magic_pkt = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010152 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010153 }
10154
Johannes Berg77dbbb12011-07-13 10:48:55 +020010155 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
10156 return -EINVAL;
10157
10158 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
10159 if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
10160 return -EINVAL;
10161 new_triggers.gtk_rekey_failure = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010162 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010163 }
10164
10165 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
10166 if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
10167 return -EINVAL;
10168 new_triggers.eap_identity_req = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010169 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010170 }
10171
10172 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
10173 if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
10174 return -EINVAL;
10175 new_triggers.four_way_handshake = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010176 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010177 }
10178
10179 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
10180 if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
10181 return -EINVAL;
10182 new_triggers.rfkill_release = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010183 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010184 }
10185
Johannes Bergff1b6e62011-05-04 15:37:28 +020010186 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
10187 struct nlattr *pat;
10188 int n_patterns = 0;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010189 int rem, pat_len, mask_len, pkt_offset;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010190 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010191
Johannes Berg98fc4382015-03-01 09:10:13 +020010192 regular = true;
10193
Johannes Bergff1b6e62011-05-04 15:37:28 +020010194 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10195 rem)
10196 n_patterns++;
10197 if (n_patterns > wowlan->n_patterns)
10198 return -EINVAL;
10199
10200 new_triggers.patterns = kcalloc(n_patterns,
10201 sizeof(new_triggers.patterns[0]),
10202 GFP_KERNEL);
10203 if (!new_triggers.patterns)
10204 return -ENOMEM;
10205
10206 new_triggers.n_patterns = n_patterns;
10207 i = 0;
10208
10209 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10210 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010211 u8 *mask_pat;
10212
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010213 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
10214 NULL);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010215 err = -EINVAL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010216 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10217 !pat_tb[NL80211_PKTPAT_PATTERN])
Johannes Bergff1b6e62011-05-04 15:37:28 +020010218 goto error;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010219 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010220 mask_len = DIV_ROUND_UP(pat_len, 8);
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010221 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010222 goto error;
10223 if (pat_len > wowlan->pattern_max_len ||
10224 pat_len < wowlan->pattern_min_len)
10225 goto error;
10226
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010227 if (!pat_tb[NL80211_PKTPAT_OFFSET])
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010228 pkt_offset = 0;
10229 else
10230 pkt_offset = nla_get_u32(
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010231 pat_tb[NL80211_PKTPAT_OFFSET]);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010232 if (pkt_offset > wowlan->max_pkt_offset)
10233 goto error;
10234 new_triggers.patterns[i].pkt_offset = pkt_offset;
10235
Johannes Berg922bd802014-05-19 17:59:50 +020010236 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10237 if (!mask_pat) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010238 err = -ENOMEM;
10239 goto error;
10240 }
Johannes Berg922bd802014-05-19 17:59:50 +020010241 new_triggers.patterns[i].mask = mask_pat;
10242 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010243 mask_len);
Johannes Berg922bd802014-05-19 17:59:50 +020010244 mask_pat += mask_len;
10245 new_triggers.patterns[i].pattern = mask_pat;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010246 new_triggers.patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010247 memcpy(mask_pat,
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010248 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010249 pat_len);
10250 i++;
10251 }
10252 }
10253
Johannes Berg2a0e0472013-01-23 22:57:40 +010010254 if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010255 regular = true;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010256 err = nl80211_parse_wowlan_tcp(
10257 rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
10258 &new_triggers);
10259 if (err)
10260 goto error;
10261 }
10262
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010263 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010264 regular = true;
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010265 err = nl80211_parse_wowlan_nd(
10266 rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
10267 &new_triggers);
10268 if (err)
10269 goto error;
10270 }
10271
Johannes Berg98fc4382015-03-01 09:10:13 +020010272 /* The 'any' trigger means the device continues operating more or less
10273 * as in its normal operation mode and wakes up the host on most of the
10274 * normal interrupts (like packet RX, ...)
10275 * It therefore makes little sense to combine with the more constrained
10276 * wakeup trigger modes.
10277 */
10278 if (new_triggers.any && regular) {
10279 err = -EINVAL;
10280 goto error;
10281 }
10282
Johannes Bergae33bd82012-07-12 16:25:02 +020010283 ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
10284 if (!ntrig) {
10285 err = -ENOMEM;
10286 goto error;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010287 }
Johannes Bergae33bd82012-07-12 16:25:02 +020010288 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010289 rdev->wiphy.wowlan_config = ntrig;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010290
Johannes Bergae33bd82012-07-12 16:25:02 +020010291 set_wakeup:
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010292 if (rdev->ops->set_wakeup &&
10293 prev_enabled != !!rdev->wiphy.wowlan_config)
10294 rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
Johannes Berg6d525632012-04-04 15:05:25 +020010295
Johannes Bergff1b6e62011-05-04 15:37:28 +020010296 return 0;
10297 error:
10298 for (i = 0; i < new_triggers.n_patterns; i++)
10299 kfree(new_triggers.patterns[i].mask);
10300 kfree(new_triggers.patterns);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010301 if (new_triggers.tcp && new_triggers.tcp->sock)
10302 sock_release(new_triggers.tcp->sock);
10303 kfree(new_triggers.tcp);
Ola Olssone5dbe072015-12-12 23:17:17 +010010304 kfree(new_triggers.nd_config);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010305 return err;
10306}
Johannes Bergdfb89c52012-06-27 09:23:48 +020010307#endif
Johannes Bergff1b6e62011-05-04 15:37:28 +020010308
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010309static int nl80211_send_coalesce_rules(struct sk_buff *msg,
10310 struct cfg80211_registered_device *rdev)
10311{
10312 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
10313 int i, j, pat_len;
10314 struct cfg80211_coalesce_rules *rule;
10315
10316 if (!rdev->coalesce->n_rules)
10317 return 0;
10318
10319 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
10320 if (!nl_rules)
10321 return -ENOBUFS;
10322
10323 for (i = 0; i < rdev->coalesce->n_rules; i++) {
10324 nl_rule = nla_nest_start(msg, i + 1);
10325 if (!nl_rule)
10326 return -ENOBUFS;
10327
10328 rule = &rdev->coalesce->rules[i];
10329 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
10330 rule->delay))
10331 return -ENOBUFS;
10332
10333 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
10334 rule->condition))
10335 return -ENOBUFS;
10336
10337 nl_pats = nla_nest_start(msg,
10338 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
10339 if (!nl_pats)
10340 return -ENOBUFS;
10341
10342 for (j = 0; j < rule->n_patterns; j++) {
10343 nl_pat = nla_nest_start(msg, j + 1);
10344 if (!nl_pat)
10345 return -ENOBUFS;
10346 pat_len = rule->patterns[j].pattern_len;
10347 if (nla_put(msg, NL80211_PKTPAT_MASK,
10348 DIV_ROUND_UP(pat_len, 8),
10349 rule->patterns[j].mask) ||
10350 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
10351 rule->patterns[j].pattern) ||
10352 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
10353 rule->patterns[j].pkt_offset))
10354 return -ENOBUFS;
10355 nla_nest_end(msg, nl_pat);
10356 }
10357 nla_nest_end(msg, nl_pats);
10358 nla_nest_end(msg, nl_rule);
10359 }
10360 nla_nest_end(msg, nl_rules);
10361
10362 return 0;
10363}
10364
10365static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
10366{
10367 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10368 struct sk_buff *msg;
10369 void *hdr;
10370
10371 if (!rdev->wiphy.coalesce)
10372 return -EOPNOTSUPP;
10373
10374 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10375 if (!msg)
10376 return -ENOMEM;
10377
10378 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10379 NL80211_CMD_GET_COALESCE);
10380 if (!hdr)
10381 goto nla_put_failure;
10382
10383 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
10384 goto nla_put_failure;
10385
10386 genlmsg_end(msg, hdr);
10387 return genlmsg_reply(msg, info);
10388
10389nla_put_failure:
10390 nlmsg_free(msg);
10391 return -ENOBUFS;
10392}
10393
10394void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
10395{
10396 struct cfg80211_coalesce *coalesce = rdev->coalesce;
10397 int i, j;
10398 struct cfg80211_coalesce_rules *rule;
10399
10400 if (!coalesce)
10401 return;
10402
10403 for (i = 0; i < coalesce->n_rules; i++) {
10404 rule = &coalesce->rules[i];
10405 for (j = 0; j < rule->n_patterns; j++)
10406 kfree(rule->patterns[j].mask);
10407 kfree(rule->patterns);
10408 }
10409 kfree(coalesce->rules);
10410 kfree(coalesce);
10411 rdev->coalesce = NULL;
10412}
10413
10414static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
10415 struct nlattr *rule,
10416 struct cfg80211_coalesce_rules *new_rule)
10417{
10418 int err, i;
10419 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10420 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
10421 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
10422 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
10423
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010424 err = nla_parse_nested(tb, NL80211_ATTR_COALESCE_RULE_MAX, rule,
10425 nl80211_coalesce_policy);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010426 if (err)
10427 return err;
10428
10429 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
10430 new_rule->delay =
10431 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
10432 if (new_rule->delay > coalesce->max_delay)
10433 return -EINVAL;
10434
10435 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
10436 new_rule->condition =
10437 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
10438 if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
10439 new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
10440 return -EINVAL;
10441
10442 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
10443 return -EINVAL;
10444
10445 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10446 rem)
10447 n_patterns++;
10448 if (n_patterns > coalesce->n_patterns)
10449 return -EINVAL;
10450
10451 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
10452 GFP_KERNEL);
10453 if (!new_rule->patterns)
10454 return -ENOMEM;
10455
10456 new_rule->n_patterns = n_patterns;
10457 i = 0;
10458
10459 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10460 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010461 u8 *mask_pat;
10462
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010463 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010464 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10465 !pat_tb[NL80211_PKTPAT_PATTERN])
10466 return -EINVAL;
10467 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
10468 mask_len = DIV_ROUND_UP(pat_len, 8);
10469 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
10470 return -EINVAL;
10471 if (pat_len > coalesce->pattern_max_len ||
10472 pat_len < coalesce->pattern_min_len)
10473 return -EINVAL;
10474
10475 if (!pat_tb[NL80211_PKTPAT_OFFSET])
10476 pkt_offset = 0;
10477 else
10478 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
10479 if (pkt_offset > coalesce->max_pkt_offset)
10480 return -EINVAL;
10481 new_rule->patterns[i].pkt_offset = pkt_offset;
10482
Johannes Berg922bd802014-05-19 17:59:50 +020010483 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10484 if (!mask_pat)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010485 return -ENOMEM;
Johannes Berg922bd802014-05-19 17:59:50 +020010486
10487 new_rule->patterns[i].mask = mask_pat;
10488 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
10489 mask_len);
10490
10491 mask_pat += mask_len;
10492 new_rule->patterns[i].pattern = mask_pat;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010493 new_rule->patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010494 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
10495 pat_len);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010496 i++;
10497 }
10498
10499 return 0;
10500}
10501
10502static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
10503{
10504 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10505 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10506 struct cfg80211_coalesce new_coalesce = {};
10507 struct cfg80211_coalesce *n_coalesce;
10508 int err, rem_rule, n_rules = 0, i, j;
10509 struct nlattr *rule;
10510 struct cfg80211_coalesce_rules *tmp_rule;
10511
10512 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
10513 return -EOPNOTSUPP;
10514
10515 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
10516 cfg80211_rdev_free_coalesce(rdev);
Ilan Peera1056b1b2015-10-22 22:27:46 +030010517 rdev_set_coalesce(rdev, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010518 return 0;
10519 }
10520
10521 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10522 rem_rule)
10523 n_rules++;
10524 if (n_rules > coalesce->n_rules)
10525 return -EINVAL;
10526
10527 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
10528 GFP_KERNEL);
10529 if (!new_coalesce.rules)
10530 return -ENOMEM;
10531
10532 new_coalesce.n_rules = n_rules;
10533 i = 0;
10534
10535 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10536 rem_rule) {
10537 err = nl80211_parse_coalesce_rule(rdev, rule,
10538 &new_coalesce.rules[i]);
10539 if (err)
10540 goto error;
10541
10542 i++;
10543 }
10544
Ilan Peera1056b1b2015-10-22 22:27:46 +030010545 err = rdev_set_coalesce(rdev, &new_coalesce);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010546 if (err)
10547 goto error;
10548
10549 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
10550 if (!n_coalesce) {
10551 err = -ENOMEM;
10552 goto error;
10553 }
10554 cfg80211_rdev_free_coalesce(rdev);
10555 rdev->coalesce = n_coalesce;
10556
10557 return 0;
10558error:
10559 for (i = 0; i < new_coalesce.n_rules; i++) {
10560 tmp_rule = &new_coalesce.rules[i];
10561 for (j = 0; j < tmp_rule->n_patterns; j++)
10562 kfree(tmp_rule->patterns[j].mask);
10563 kfree(tmp_rule->patterns);
10564 }
10565 kfree(new_coalesce.rules);
10566
10567 return err;
10568}
10569
Johannes Berge5497d72011-07-05 16:35:40 +020010570static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
10571{
10572 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10573 struct net_device *dev = info->user_ptr[1];
10574 struct wireless_dev *wdev = dev->ieee80211_ptr;
10575 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
10576 struct cfg80211_gtk_rekey_data rekey_data;
10577 int err;
10578
10579 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
10580 return -EINVAL;
10581
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010582 err = nla_parse_nested(tb, MAX_NL80211_REKEY_DATA,
10583 info->attrs[NL80211_ATTR_REKEY_DATA],
10584 nl80211_rekey_policy);
Johannes Berge5497d72011-07-05 16:35:40 +020010585 if (err)
10586 return err;
10587
10588 if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
10589 return -ERANGE;
10590 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
10591 return -ERANGE;
10592 if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
10593 return -ERANGE;
10594
Johannes Berg78f686c2014-09-10 22:28:06 +030010595 rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
10596 rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
10597 rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
Johannes Berge5497d72011-07-05 16:35:40 +020010598
10599 wdev_lock(wdev);
10600 if (!wdev->current_bss) {
10601 err = -ENOTCONN;
10602 goto out;
10603 }
10604
10605 if (!rdev->ops->set_rekey_data) {
10606 err = -EOPNOTSUPP;
10607 goto out;
10608 }
10609
Hila Gonene35e4d22012-06-27 17:19:42 +030010610 err = rdev_set_rekey_data(rdev, dev, &rekey_data);
Johannes Berge5497d72011-07-05 16:35:40 +020010611 out:
10612 wdev_unlock(wdev);
10613 return err;
10614}
10615
Johannes Berg28946da2011-11-04 11:18:12 +010010616static int nl80211_register_unexpected_frame(struct sk_buff *skb,
10617 struct genl_info *info)
10618{
10619 struct net_device *dev = info->user_ptr[1];
10620 struct wireless_dev *wdev = dev->ieee80211_ptr;
10621
10622 if (wdev->iftype != NL80211_IFTYPE_AP &&
10623 wdev->iftype != NL80211_IFTYPE_P2P_GO)
10624 return -EINVAL;
10625
Eric W. Biederman15e47302012-09-07 20:12:54 +000010626 if (wdev->ap_unexpected_nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010010627 return -EBUSY;
10628
Eric W. Biederman15e47302012-09-07 20:12:54 +000010629 wdev->ap_unexpected_nlportid = info->snd_portid;
Johannes Berg28946da2011-11-04 11:18:12 +010010630 return 0;
10631}
10632
Johannes Berg7f6cf312011-11-04 11:18:15 +010010633static int nl80211_probe_client(struct sk_buff *skb,
10634 struct genl_info *info)
10635{
10636 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10637 struct net_device *dev = info->user_ptr[1];
10638 struct wireless_dev *wdev = dev->ieee80211_ptr;
10639 struct sk_buff *msg;
10640 void *hdr;
10641 const u8 *addr;
10642 u64 cookie;
10643 int err;
10644
10645 if (wdev->iftype != NL80211_IFTYPE_AP &&
10646 wdev->iftype != NL80211_IFTYPE_P2P_GO)
10647 return -EOPNOTSUPP;
10648
10649 if (!info->attrs[NL80211_ATTR_MAC])
10650 return -EINVAL;
10651
10652 if (!rdev->ops->probe_client)
10653 return -EOPNOTSUPP;
10654
10655 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10656 if (!msg)
10657 return -ENOMEM;
10658
Eric W. Biederman15e47302012-09-07 20:12:54 +000010659 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg7f6cf312011-11-04 11:18:15 +010010660 NL80211_CMD_PROBE_CLIENT);
Dan Carpentercb35fba2013-08-14 14:50:01 +030010661 if (!hdr) {
10662 err = -ENOBUFS;
Johannes Berg7f6cf312011-11-04 11:18:15 +010010663 goto free_msg;
10664 }
10665
10666 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
10667
Hila Gonene35e4d22012-06-27 17:19:42 +030010668 err = rdev_probe_client(rdev, dev, addr, &cookie);
Johannes Berg7f6cf312011-11-04 11:18:15 +010010669 if (err)
10670 goto free_msg;
10671
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020010672 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
10673 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040010674 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010010675
10676 genlmsg_end(msg, hdr);
10677
10678 return genlmsg_reply(msg, info);
10679
10680 nla_put_failure:
10681 err = -ENOBUFS;
10682 free_msg:
10683 nlmsg_free(msg);
10684 return err;
10685}
10686
Johannes Berg5e760232011-11-04 11:18:17 +010010687static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
10688{
10689 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Ben Greear37c73b52012-10-26 14:49:25 -070010690 struct cfg80211_beacon_registration *reg, *nreg;
10691 int rv;
Johannes Berg5e760232011-11-04 11:18:17 +010010692
10693 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
10694 return -EOPNOTSUPP;
10695
Ben Greear37c73b52012-10-26 14:49:25 -070010696 nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
10697 if (!nreg)
10698 return -ENOMEM;
Johannes Berg5e760232011-11-04 11:18:17 +010010699
Ben Greear37c73b52012-10-26 14:49:25 -070010700 /* First, check if already registered. */
10701 spin_lock_bh(&rdev->beacon_registrations_lock);
10702 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
10703 if (reg->nlportid == info->snd_portid) {
10704 rv = -EALREADY;
10705 goto out_err;
10706 }
10707 }
10708 /* Add it to the list */
10709 nreg->nlportid = info->snd_portid;
10710 list_add(&nreg->list, &rdev->beacon_registrations);
10711
10712 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010010713
10714 return 0;
Ben Greear37c73b52012-10-26 14:49:25 -070010715out_err:
10716 spin_unlock_bh(&rdev->beacon_registrations_lock);
10717 kfree(nreg);
10718 return rv;
Johannes Berg5e760232011-11-04 11:18:17 +010010719}
10720
Johannes Berg98104fde2012-06-16 00:19:54 +020010721static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
10722{
10723 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10724 struct wireless_dev *wdev = info->user_ptr[1];
10725 int err;
10726
10727 if (!rdev->ops->start_p2p_device)
10728 return -EOPNOTSUPP;
10729
10730 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
10731 return -EOPNOTSUPP;
10732
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010733 if (wdev_running(wdev))
Johannes Berg98104fde2012-06-16 00:19:54 +020010734 return 0;
10735
Luciano Coelhob6a55012014-02-27 11:07:21 +020010736 if (rfkill_blocked(rdev->rfkill))
10737 return -ERFKILL;
Johannes Berg98104fde2012-06-16 00:19:54 +020010738
Johannes Bergeeb126e2012-10-23 15:16:50 +020010739 err = rdev_start_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020010740 if (err)
10741 return err;
10742
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010743 wdev->is_running = true;
Johannes Berg98104fde2012-06-16 00:19:54 +020010744 rdev->opencount++;
Johannes Berg98104fde2012-06-16 00:19:54 +020010745
10746 return 0;
10747}
10748
10749static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
10750{
10751 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10752 struct wireless_dev *wdev = info->user_ptr[1];
10753
10754 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
10755 return -EOPNOTSUPP;
10756
10757 if (!rdev->ops->stop_p2p_device)
10758 return -EOPNOTSUPP;
10759
Johannes Bergf9f47522013-03-19 15:04:07 +010010760 cfg80211_stop_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020010761
10762 return 0;
10763}
10764
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010765static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
10766{
10767 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10768 struct wireless_dev *wdev = info->user_ptr[1];
10769 struct cfg80211_nan_conf conf = {};
10770 int err;
10771
10772 if (wdev->iftype != NL80211_IFTYPE_NAN)
10773 return -EOPNOTSUPP;
10774
Johannes Bergeeb04a92016-11-21 13:55:48 +010010775 if (wdev_running(wdev))
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010776 return -EEXIST;
10777
10778 if (rfkill_blocked(rdev->rfkill))
10779 return -ERFKILL;
10780
10781 if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
10782 return -EINVAL;
10783
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010784 conf.master_pref =
10785 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
10786 if (!conf.master_pref)
10787 return -EINVAL;
10788
Luca Coelho85859892017-02-08 15:00:34 +020010789 if (info->attrs[NL80211_ATTR_BANDS]) {
10790 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
10791
10792 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
10793 return -EOPNOTSUPP;
10794
10795 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
10796 return -EINVAL;
10797
10798 conf.bands = bands;
10799 }
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010800
10801 err = rdev_start_nan(rdev, wdev, &conf);
10802 if (err)
10803 return err;
10804
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010805 wdev->is_running = true;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010806 rdev->opencount++;
10807
10808 return 0;
10809}
10810
10811static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
10812{
10813 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10814 struct wireless_dev *wdev = info->user_ptr[1];
10815
10816 if (wdev->iftype != NL80211_IFTYPE_NAN)
10817 return -EOPNOTSUPP;
10818
10819 cfg80211_stop_nan(rdev, wdev);
10820
10821 return 0;
10822}
10823
Ayala Bekera442b762016-09-20 17:31:15 +030010824static int validate_nan_filter(struct nlattr *filter_attr)
10825{
10826 struct nlattr *attr;
10827 int len = 0, n_entries = 0, rem;
10828
10829 nla_for_each_nested(attr, filter_attr, rem) {
10830 len += nla_len(attr);
10831 n_entries++;
10832 }
10833
10834 if (len >= U8_MAX)
10835 return -EINVAL;
10836
10837 return n_entries;
10838}
10839
10840static int handle_nan_filter(struct nlattr *attr_filter,
10841 struct cfg80211_nan_func *func,
10842 bool tx)
10843{
10844 struct nlattr *attr;
10845 int n_entries, rem, i;
10846 struct cfg80211_nan_func_filter *filter;
10847
10848 n_entries = validate_nan_filter(attr_filter);
10849 if (n_entries < 0)
10850 return n_entries;
10851
10852 BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
10853
10854 filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
10855 if (!filter)
10856 return -ENOMEM;
10857
10858 i = 0;
10859 nla_for_each_nested(attr, attr_filter, rem) {
Thomas Grafb15ca182016-10-26 10:53:16 +020010860 filter[i].filter = nla_memdup(attr, GFP_KERNEL);
Ayala Bekera442b762016-09-20 17:31:15 +030010861 filter[i].len = nla_len(attr);
10862 i++;
10863 }
10864 if (tx) {
10865 func->num_tx_filters = n_entries;
10866 func->tx_filters = filter;
10867 } else {
10868 func->num_rx_filters = n_entries;
10869 func->rx_filters = filter;
10870 }
10871
10872 return 0;
10873}
10874
10875static int nl80211_nan_add_func(struct sk_buff *skb,
10876 struct genl_info *info)
10877{
10878 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10879 struct wireless_dev *wdev = info->user_ptr[1];
10880 struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
10881 struct cfg80211_nan_func *func;
10882 struct sk_buff *msg = NULL;
10883 void *hdr = NULL;
10884 int err = 0;
10885
10886 if (wdev->iftype != NL80211_IFTYPE_NAN)
10887 return -EOPNOTSUPP;
10888
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010889 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030010890 return -ENOTCONN;
10891
10892 if (!info->attrs[NL80211_ATTR_NAN_FUNC])
10893 return -EINVAL;
10894
10895 if (wdev->owner_nlportid &&
10896 wdev->owner_nlportid != info->snd_portid)
10897 return -ENOTCONN;
10898
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010899 err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,
10900 info->attrs[NL80211_ATTR_NAN_FUNC],
10901 nl80211_nan_func_policy);
Ayala Bekera442b762016-09-20 17:31:15 +030010902 if (err)
10903 return err;
10904
10905 func = kzalloc(sizeof(*func), GFP_KERNEL);
10906 if (!func)
10907 return -ENOMEM;
10908
10909 func->cookie = wdev->wiphy->cookie_counter++;
10910
10911 if (!tb[NL80211_NAN_FUNC_TYPE] ||
10912 nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) {
10913 err = -EINVAL;
10914 goto out;
10915 }
10916
10917
10918 func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
10919
10920 if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
10921 err = -EINVAL;
10922 goto out;
10923 }
10924
10925 memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
10926 sizeof(func->service_id));
10927
10928 func->close_range =
10929 nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
10930
10931 if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
10932 func->serv_spec_info_len =
10933 nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
10934 func->serv_spec_info =
10935 kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
10936 func->serv_spec_info_len,
10937 GFP_KERNEL);
10938 if (!func->serv_spec_info) {
10939 err = -ENOMEM;
10940 goto out;
10941 }
10942 }
10943
10944 if (tb[NL80211_NAN_FUNC_TTL])
10945 func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
10946
10947 switch (func->type) {
10948 case NL80211_NAN_FUNC_PUBLISH:
10949 if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
10950 err = -EINVAL;
10951 goto out;
10952 }
10953
10954 func->publish_type =
10955 nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
10956 func->publish_bcast =
10957 nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
10958
10959 if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
10960 func->publish_bcast) {
10961 err = -EINVAL;
10962 goto out;
10963 }
10964 break;
10965 case NL80211_NAN_FUNC_SUBSCRIBE:
10966 func->subscribe_active =
10967 nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
10968 break;
10969 case NL80211_NAN_FUNC_FOLLOW_UP:
10970 if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
10971 !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]) {
10972 err = -EINVAL;
10973 goto out;
10974 }
10975
10976 func->followup_id =
10977 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
10978 func->followup_reqid =
10979 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
10980 memcpy(func->followup_dest.addr,
10981 nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
10982 sizeof(func->followup_dest.addr));
10983 if (func->ttl) {
10984 err = -EINVAL;
10985 goto out;
10986 }
10987 break;
10988 default:
10989 err = -EINVAL;
10990 goto out;
10991 }
10992
10993 if (tb[NL80211_NAN_FUNC_SRF]) {
10994 struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
10995
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010996 err = nla_parse_nested(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
10997 tb[NL80211_NAN_FUNC_SRF],
10998 nl80211_nan_srf_policy);
Ayala Bekera442b762016-09-20 17:31:15 +030010999 if (err)
11000 goto out;
11001
11002 func->srf_include =
11003 nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
11004
11005 if (srf_tb[NL80211_NAN_SRF_BF]) {
11006 if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
11007 !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
11008 err = -EINVAL;
11009 goto out;
11010 }
11011
11012 func->srf_bf_len =
11013 nla_len(srf_tb[NL80211_NAN_SRF_BF]);
11014 func->srf_bf =
11015 kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
11016 func->srf_bf_len, GFP_KERNEL);
11017 if (!func->srf_bf) {
11018 err = -ENOMEM;
11019 goto out;
11020 }
11021
11022 func->srf_bf_idx =
11023 nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
11024 } else {
11025 struct nlattr *attr, *mac_attr =
11026 srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
11027 int n_entries, rem, i = 0;
11028
11029 if (!mac_attr) {
11030 err = -EINVAL;
11031 goto out;
11032 }
11033
11034 n_entries = validate_acl_mac_addrs(mac_attr);
11035 if (n_entries <= 0) {
11036 err = -EINVAL;
11037 goto out;
11038 }
11039
11040 func->srf_num_macs = n_entries;
11041 func->srf_macs =
11042 kzalloc(sizeof(*func->srf_macs) * n_entries,
11043 GFP_KERNEL);
11044 if (!func->srf_macs) {
11045 err = -ENOMEM;
11046 goto out;
11047 }
11048
11049 nla_for_each_nested(attr, mac_attr, rem)
11050 memcpy(func->srf_macs[i++].addr, nla_data(attr),
11051 sizeof(*func->srf_macs));
11052 }
11053 }
11054
11055 if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
11056 err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
11057 func, true);
11058 if (err)
11059 goto out;
11060 }
11061
11062 if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
11063 err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
11064 func, false);
11065 if (err)
11066 goto out;
11067 }
11068
11069 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11070 if (!msg) {
11071 err = -ENOMEM;
11072 goto out;
11073 }
11074
11075 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11076 NL80211_CMD_ADD_NAN_FUNCTION);
11077 /* This can't really happen - we just allocated 4KB */
11078 if (WARN_ON(!hdr)) {
11079 err = -ENOMEM;
11080 goto out;
11081 }
11082
11083 err = rdev_add_nan_func(rdev, wdev, func);
11084out:
11085 if (err < 0) {
11086 cfg80211_free_nan_func(func);
11087 nlmsg_free(msg);
11088 return err;
11089 }
11090
11091 /* propagate the instance id and cookie to userspace */
11092 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
11093 NL80211_ATTR_PAD))
11094 goto nla_put_failure;
11095
11096 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11097 if (!func_attr)
11098 goto nla_put_failure;
11099
11100 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
11101 func->instance_id))
11102 goto nla_put_failure;
11103
11104 nla_nest_end(msg, func_attr);
11105
11106 genlmsg_end(msg, hdr);
11107 return genlmsg_reply(msg, info);
11108
11109nla_put_failure:
11110 nlmsg_free(msg);
11111 return -ENOBUFS;
11112}
11113
11114static int nl80211_nan_del_func(struct sk_buff *skb,
11115 struct genl_info *info)
11116{
11117 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11118 struct wireless_dev *wdev = info->user_ptr[1];
11119 u64 cookie;
11120
11121 if (wdev->iftype != NL80211_IFTYPE_NAN)
11122 return -EOPNOTSUPP;
11123
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011124 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030011125 return -ENOTCONN;
11126
11127 if (!info->attrs[NL80211_ATTR_COOKIE])
11128 return -EINVAL;
11129
11130 if (wdev->owner_nlportid &&
11131 wdev->owner_nlportid != info->snd_portid)
11132 return -ENOTCONN;
11133
11134 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
11135
11136 rdev_del_nan_func(rdev, wdev, cookie);
11137
11138 return 0;
11139}
11140
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011141static int nl80211_nan_change_config(struct sk_buff *skb,
11142 struct genl_info *info)
11143{
11144 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11145 struct wireless_dev *wdev = info->user_ptr[1];
11146 struct cfg80211_nan_conf conf = {};
11147 u32 changed = 0;
11148
11149 if (wdev->iftype != NL80211_IFTYPE_NAN)
11150 return -EOPNOTSUPP;
11151
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011152 if (!wdev_running(wdev))
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011153 return -ENOTCONN;
11154
11155 if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
11156 conf.master_pref =
11157 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11158 if (conf.master_pref <= 1 || conf.master_pref == 255)
11159 return -EINVAL;
11160
11161 changed |= CFG80211_NAN_CONF_CHANGED_PREF;
11162 }
11163
Luca Coelho85859892017-02-08 15:00:34 +020011164 if (info->attrs[NL80211_ATTR_BANDS]) {
11165 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
11166
11167 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
11168 return -EOPNOTSUPP;
11169
11170 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
11171 return -EINVAL;
11172
11173 conf.bands = bands;
11174 changed |= CFG80211_NAN_CONF_CHANGED_BANDS;
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011175 }
11176
11177 if (!changed)
11178 return -EINVAL;
11179
11180 return rdev_nan_change_conf(rdev, wdev, &conf, changed);
11181}
11182
Ayala Beker50bcd312016-09-20 17:31:17 +030011183void cfg80211_nan_match(struct wireless_dev *wdev,
11184 struct cfg80211_nan_match_params *match, gfp_t gfp)
11185{
11186 struct wiphy *wiphy = wdev->wiphy;
11187 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11188 struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
11189 struct sk_buff *msg;
11190 void *hdr;
11191
11192 if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
11193 return;
11194
11195 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11196 if (!msg)
11197 return;
11198
11199 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
11200 if (!hdr) {
11201 nlmsg_free(msg);
11202 return;
11203 }
11204
11205 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11206 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11207 wdev->netdev->ifindex)) ||
11208 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11209 NL80211_ATTR_PAD))
11210 goto nla_put_failure;
11211
11212 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
11213 NL80211_ATTR_PAD) ||
11214 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
11215 goto nla_put_failure;
11216
11217 match_attr = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH);
11218 if (!match_attr)
11219 goto nla_put_failure;
11220
11221 local_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_LOCAL);
11222 if (!local_func_attr)
11223 goto nla_put_failure;
11224
11225 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
11226 goto nla_put_failure;
11227
11228 nla_nest_end(msg, local_func_attr);
11229
11230 peer_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_PEER);
11231 if (!peer_func_attr)
11232 goto nla_put_failure;
11233
11234 if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
11235 nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
11236 goto nla_put_failure;
11237
11238 if (match->info && match->info_len &&
11239 nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
11240 match->info))
11241 goto nla_put_failure;
11242
11243 nla_nest_end(msg, peer_func_attr);
11244 nla_nest_end(msg, match_attr);
11245 genlmsg_end(msg, hdr);
11246
11247 if (!wdev->owner_nlportid)
11248 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11249 msg, 0, NL80211_MCGRP_NAN, gfp);
11250 else
11251 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11252 wdev->owner_nlportid);
11253
11254 return;
11255
11256nla_put_failure:
11257 nlmsg_free(msg);
11258}
11259EXPORT_SYMBOL(cfg80211_nan_match);
11260
Ayala Beker368e5a72016-09-20 17:31:18 +030011261void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
11262 u8 inst_id,
11263 enum nl80211_nan_func_term_reason reason,
11264 u64 cookie, gfp_t gfp)
11265{
11266 struct wiphy *wiphy = wdev->wiphy;
11267 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11268 struct sk_buff *msg;
11269 struct nlattr *func_attr;
11270 void *hdr;
11271
11272 if (WARN_ON(!inst_id))
11273 return;
11274
11275 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11276 if (!msg)
11277 return;
11278
11279 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
11280 if (!hdr) {
11281 nlmsg_free(msg);
11282 return;
11283 }
11284
11285 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11286 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11287 wdev->netdev->ifindex)) ||
11288 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11289 NL80211_ATTR_PAD))
11290 goto nla_put_failure;
11291
11292 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11293 NL80211_ATTR_PAD))
11294 goto nla_put_failure;
11295
11296 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11297 if (!func_attr)
11298 goto nla_put_failure;
11299
11300 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
11301 nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
11302 goto nla_put_failure;
11303
11304 nla_nest_end(msg, func_attr);
11305 genlmsg_end(msg, hdr);
11306
11307 if (!wdev->owner_nlportid)
11308 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11309 msg, 0, NL80211_MCGRP_NAN, gfp);
11310 else
11311 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11312 wdev->owner_nlportid);
11313
11314 return;
11315
11316nla_put_failure:
11317 nlmsg_free(msg);
11318}
11319EXPORT_SYMBOL(cfg80211_nan_func_terminated);
11320
Johannes Berg3713b4e2013-02-14 16:19:38 +010011321static int nl80211_get_protocol_features(struct sk_buff *skb,
11322 struct genl_info *info)
11323{
11324 void *hdr;
11325 struct sk_buff *msg;
11326
11327 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11328 if (!msg)
11329 return -ENOMEM;
11330
11331 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11332 NL80211_CMD_GET_PROTOCOL_FEATURES);
11333 if (!hdr)
11334 goto nla_put_failure;
11335
11336 if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
11337 NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
11338 goto nla_put_failure;
11339
11340 genlmsg_end(msg, hdr);
11341 return genlmsg_reply(msg, info);
11342
11343 nla_put_failure:
11344 kfree_skb(msg);
11345 return -ENOBUFS;
11346}
11347
Jouni Malinen355199e2013-02-27 17:14:27 +020011348static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
11349{
11350 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11351 struct cfg80211_update_ft_ies_params ft_params;
11352 struct net_device *dev = info->user_ptr[1];
11353
11354 if (!rdev->ops->update_ft_ies)
11355 return -EOPNOTSUPP;
11356
11357 if (!info->attrs[NL80211_ATTR_MDID] ||
11358 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
11359 return -EINVAL;
11360
11361 memset(&ft_params, 0, sizeof(ft_params));
11362 ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
11363 ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
11364 ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
11365
11366 return rdev_update_ft_ies(rdev, dev, &ft_params);
11367}
11368
Arend van Spriel5de17982013-04-18 15:49:00 +020011369static int nl80211_crit_protocol_start(struct sk_buff *skb,
11370 struct genl_info *info)
11371{
11372 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11373 struct wireless_dev *wdev = info->user_ptr[1];
11374 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
11375 u16 duration;
11376 int ret;
11377
11378 if (!rdev->ops->crit_proto_start)
11379 return -EOPNOTSUPP;
11380
11381 if (WARN_ON(!rdev->ops->crit_proto_stop))
11382 return -EINVAL;
11383
11384 if (rdev->crit_proto_nlportid)
11385 return -EBUSY;
11386
11387 /* determine protocol if provided */
11388 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
11389 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
11390
11391 if (proto >= NUM_NL80211_CRIT_PROTO)
11392 return -EINVAL;
11393
11394 /* timeout must be provided */
11395 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
11396 return -EINVAL;
11397
11398 duration =
11399 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
11400
11401 if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
11402 return -ERANGE;
11403
11404 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
11405 if (!ret)
11406 rdev->crit_proto_nlportid = info->snd_portid;
11407
11408 return ret;
11409}
11410
11411static int nl80211_crit_protocol_stop(struct sk_buff *skb,
11412 struct genl_info *info)
11413{
11414 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11415 struct wireless_dev *wdev = info->user_ptr[1];
11416
11417 if (!rdev->ops->crit_proto_stop)
11418 return -EOPNOTSUPP;
11419
11420 if (rdev->crit_proto_nlportid) {
11421 rdev->crit_proto_nlportid = 0;
11422 rdev_crit_proto_stop(rdev, wdev);
11423 }
11424 return 0;
11425}
11426
Johannes Bergad7e7182013-11-13 13:37:47 +010011427static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
11428{
11429 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11430 struct wireless_dev *wdev =
11431 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
11432 int i, err;
11433 u32 vid, subcmd;
11434
11435 if (!rdev->wiphy.vendor_commands)
11436 return -EOPNOTSUPP;
11437
11438 if (IS_ERR(wdev)) {
11439 err = PTR_ERR(wdev);
11440 if (err != -EINVAL)
11441 return err;
11442 wdev = NULL;
11443 } else if (wdev->wiphy != &rdev->wiphy) {
11444 return -EINVAL;
11445 }
11446
11447 if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
11448 !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
11449 return -EINVAL;
11450
11451 vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
11452 subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
11453 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
11454 const struct wiphy_vendor_command *vcmd;
11455 void *data = NULL;
11456 int len = 0;
11457
11458 vcmd = &rdev->wiphy.vendor_commands[i];
11459
11460 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11461 continue;
11462
11463 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11464 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
11465 if (!wdev)
11466 return -EINVAL;
11467 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
11468 !wdev->netdev)
11469 return -EINVAL;
11470
11471 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011472 if (!wdev_running(wdev))
Johannes Bergad7e7182013-11-13 13:37:47 +010011473 return -ENETDOWN;
11474 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030011475
11476 if (!vcmd->doit)
11477 return -EOPNOTSUPP;
Johannes Bergad7e7182013-11-13 13:37:47 +010011478 } else {
11479 wdev = NULL;
11480 }
11481
11482 if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
11483 data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11484 len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11485 }
11486
11487 rdev->cur_cmd_info = info;
11488 err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
11489 data, len);
11490 rdev->cur_cmd_info = NULL;
11491 return err;
11492 }
11493
11494 return -EOPNOTSUPP;
11495}
11496
Johannes Berg7bdbe402015-08-15 22:39:49 +030011497static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
11498 struct netlink_callback *cb,
11499 struct cfg80211_registered_device **rdev,
11500 struct wireless_dev **wdev)
11501{
Johannes Bergc90c39d2016-10-24 14:40:01 +020011502 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011503 u32 vid, subcmd;
11504 unsigned int i;
11505 int vcmd_idx = -1;
11506 int err;
11507 void *data = NULL;
11508 unsigned int data_len = 0;
11509
11510 rtnl_lock();
11511
11512 if (cb->args[0]) {
11513 /* subtract the 1 again here */
11514 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
11515 struct wireless_dev *tmp;
11516
11517 if (!wiphy) {
11518 err = -ENODEV;
11519 goto out_unlock;
11520 }
11521 *rdev = wiphy_to_rdev(wiphy);
11522 *wdev = NULL;
11523
11524 if (cb->args[1]) {
Johannes Berg53873f12016-05-03 16:52:04 +030011525 list_for_each_entry(tmp, &wiphy->wdev_list, list) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011526 if (tmp->identifier == cb->args[1] - 1) {
11527 *wdev = tmp;
11528 break;
11529 }
11530 }
11531 }
11532
11533 /* keep rtnl locked in successful case */
11534 return 0;
11535 }
11536
11537 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +020011538 attrbuf, nl80211_fam.maxattr, nl80211_policy);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011539 if (err)
11540 goto out_unlock;
11541
Johannes Bergc90c39d2016-10-24 14:40:01 +020011542 if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
11543 !attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011544 err = -EINVAL;
11545 goto out_unlock;
11546 }
11547
Johannes Bergc90c39d2016-10-24 14:40:01 +020011548 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011549 if (IS_ERR(*wdev))
11550 *wdev = NULL;
11551
Johannes Bergc90c39d2016-10-24 14:40:01 +020011552 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011553 if (IS_ERR(*rdev)) {
11554 err = PTR_ERR(*rdev);
11555 goto out_unlock;
11556 }
11557
Johannes Bergc90c39d2016-10-24 14:40:01 +020011558 vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
11559 subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011560
11561 for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
11562 const struct wiphy_vendor_command *vcmd;
11563
11564 vcmd = &(*rdev)->wiphy.vendor_commands[i];
11565
11566 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11567 continue;
11568
11569 if (!vcmd->dumpit) {
11570 err = -EOPNOTSUPP;
11571 goto out_unlock;
11572 }
11573
11574 vcmd_idx = i;
11575 break;
11576 }
11577
11578 if (vcmd_idx < 0) {
11579 err = -EOPNOTSUPP;
11580 goto out_unlock;
11581 }
11582
Johannes Bergc90c39d2016-10-24 14:40:01 +020011583 if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
11584 data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
11585 data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011586 }
11587
11588 /* 0 is the first index - add 1 to parse only once */
11589 cb->args[0] = (*rdev)->wiphy_idx + 1;
11590 /* add 1 to know if it was NULL */
11591 cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
11592 cb->args[2] = vcmd_idx;
11593 cb->args[3] = (unsigned long)data;
11594 cb->args[4] = data_len;
11595
11596 /* keep rtnl locked in successful case */
11597 return 0;
11598 out_unlock:
11599 rtnl_unlock();
11600 return err;
11601}
11602
11603static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
11604 struct netlink_callback *cb)
11605{
11606 struct cfg80211_registered_device *rdev;
11607 struct wireless_dev *wdev;
11608 unsigned int vcmd_idx;
11609 const struct wiphy_vendor_command *vcmd;
11610 void *data;
11611 int data_len;
11612 int err;
11613 struct nlattr *vendor_data;
11614
11615 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
11616 if (err)
11617 return err;
11618
11619 vcmd_idx = cb->args[2];
11620 data = (void *)cb->args[3];
11621 data_len = cb->args[4];
11622 vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
11623
11624 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11625 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
11626 if (!wdev)
11627 return -EINVAL;
11628 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
11629 !wdev->netdev)
11630 return -EINVAL;
11631
11632 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011633 if (!wdev_running(wdev))
Johannes Berg7bdbe402015-08-15 22:39:49 +030011634 return -ENETDOWN;
11635 }
11636 }
11637
11638 while (1) {
11639 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
11640 cb->nlh->nlmsg_seq, NLM_F_MULTI,
11641 NL80211_CMD_VENDOR);
11642 if (!hdr)
11643 break;
11644
11645 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020011646 (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
11647 wdev_id(wdev),
11648 NL80211_ATTR_PAD))) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011649 genlmsg_cancel(skb, hdr);
11650 break;
11651 }
11652
11653 vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
11654 if (!vendor_data) {
11655 genlmsg_cancel(skb, hdr);
11656 break;
11657 }
11658
11659 err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
11660 (unsigned long *)&cb->args[5]);
11661 nla_nest_end(skb, vendor_data);
11662
11663 if (err == -ENOBUFS || err == -ENOENT) {
11664 genlmsg_cancel(skb, hdr);
11665 break;
11666 } else if (err) {
11667 genlmsg_cancel(skb, hdr);
11668 goto out;
11669 }
11670
11671 genlmsg_end(skb, hdr);
11672 }
11673
11674 err = skb->len;
11675 out:
11676 rtnl_unlock();
11677 return err;
11678}
11679
Johannes Bergad7e7182013-11-13 13:37:47 +010011680struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
11681 enum nl80211_commands cmd,
11682 enum nl80211_attrs attr,
11683 int approxlen)
11684{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080011685 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Bergad7e7182013-11-13 13:37:47 +010011686
11687 if (WARN_ON(!rdev->cur_cmd_info))
11688 return NULL;
11689
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020011690 return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
Johannes Bergad7e7182013-11-13 13:37:47 +010011691 rdev->cur_cmd_info->snd_portid,
11692 rdev->cur_cmd_info->snd_seq,
Johannes Berg567ffc32013-12-18 14:43:31 +010011693 cmd, attr, NULL, GFP_KERNEL);
Johannes Bergad7e7182013-11-13 13:37:47 +010011694}
11695EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
11696
11697int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
11698{
11699 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
11700 void *hdr = ((void **)skb->cb)[1];
11701 struct nlattr *data = ((void **)skb->cb)[2];
11702
Johannes Bergbd8c78e2014-07-30 14:55:26 +020011703 /* clear CB data for netlink core to own from now on */
11704 memset(skb->cb, 0, sizeof(skb->cb));
11705
Johannes Bergad7e7182013-11-13 13:37:47 +010011706 if (WARN_ON(!rdev->cur_cmd_info)) {
11707 kfree_skb(skb);
11708 return -EINVAL;
11709 }
11710
11711 nla_nest_end(skb, data);
11712 genlmsg_end(skb, hdr);
11713 return genlmsg_reply(skb, rdev->cur_cmd_info);
11714}
11715EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
11716
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080011717static int nl80211_set_qos_map(struct sk_buff *skb,
11718 struct genl_info *info)
11719{
11720 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11721 struct cfg80211_qos_map *qos_map = NULL;
11722 struct net_device *dev = info->user_ptr[1];
11723 u8 *pos, len, num_des, des_len, des;
11724 int ret;
11725
11726 if (!rdev->ops->set_qos_map)
11727 return -EOPNOTSUPP;
11728
11729 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
11730 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
11731 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
11732
11733 if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
11734 len > IEEE80211_QOS_MAP_LEN_MAX)
11735 return -EINVAL;
11736
11737 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
11738 if (!qos_map)
11739 return -ENOMEM;
11740
11741 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
11742 if (num_des) {
11743 des_len = num_des *
11744 sizeof(struct cfg80211_dscp_exception);
11745 memcpy(qos_map->dscp_exception, pos, des_len);
11746 qos_map->num_des = num_des;
11747 for (des = 0; des < num_des; des++) {
11748 if (qos_map->dscp_exception[des].up > 7) {
11749 kfree(qos_map);
11750 return -EINVAL;
11751 }
11752 }
11753 pos += des_len;
11754 }
11755 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
11756 }
11757
11758 wdev_lock(dev->ieee80211_ptr);
11759 ret = nl80211_key_allowed(dev->ieee80211_ptr);
11760 if (!ret)
11761 ret = rdev_set_qos_map(rdev, dev, qos_map);
11762 wdev_unlock(dev->ieee80211_ptr);
11763
11764 kfree(qos_map);
11765 return ret;
11766}
11767
Johannes Berg960d01a2014-09-09 22:55:35 +030011768static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
11769{
11770 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11771 struct net_device *dev = info->user_ptr[1];
11772 struct wireless_dev *wdev = dev->ieee80211_ptr;
11773 const u8 *peer;
11774 u8 tsid, up;
11775 u16 admitted_time = 0;
11776 int err;
11777
Johannes Berg723e73a2014-10-22 09:25:06 +020011778 if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
Johannes Berg960d01a2014-09-09 22:55:35 +030011779 return -EOPNOTSUPP;
11780
11781 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
11782 !info->attrs[NL80211_ATTR_USER_PRIO])
11783 return -EINVAL;
11784
11785 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
11786 if (tsid >= IEEE80211_NUM_TIDS)
11787 return -EINVAL;
11788
11789 up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
11790 if (up >= IEEE80211_NUM_UPS)
11791 return -EINVAL;
11792
11793 /* WMM uses TIDs 0-7 even for TSPEC */
Johannes Berg723e73a2014-10-22 09:25:06 +020011794 if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
Johannes Berg960d01a2014-09-09 22:55:35 +030011795 /* TODO: handle 802.11 TSPEC/admission control
Johannes Berg723e73a2014-10-22 09:25:06 +020011796 * need more attributes for that (e.g. BA session requirement);
11797 * change the WMM adminssion test above to allow both then
Johannes Berg960d01a2014-09-09 22:55:35 +030011798 */
11799 return -EINVAL;
11800 }
11801
11802 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
11803
11804 if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
11805 admitted_time =
11806 nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
11807 if (!admitted_time)
11808 return -EINVAL;
11809 }
11810
11811 wdev_lock(wdev);
11812 switch (wdev->iftype) {
11813 case NL80211_IFTYPE_STATION:
11814 case NL80211_IFTYPE_P2P_CLIENT:
11815 if (wdev->current_bss)
11816 break;
11817 err = -ENOTCONN;
11818 goto out;
11819 default:
11820 err = -EOPNOTSUPP;
11821 goto out;
11822 }
11823
11824 err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
11825
11826 out:
11827 wdev_unlock(wdev);
11828 return err;
11829}
11830
11831static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
11832{
11833 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11834 struct net_device *dev = info->user_ptr[1];
11835 struct wireless_dev *wdev = dev->ieee80211_ptr;
11836 const u8 *peer;
11837 u8 tsid;
11838 int err;
11839
11840 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
11841 return -EINVAL;
11842
11843 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
11844 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
11845
11846 wdev_lock(wdev);
11847 err = rdev_del_tx_ts(rdev, dev, tsid, peer);
11848 wdev_unlock(wdev);
11849
11850 return err;
11851}
11852
Arik Nemtsov1057d352014-11-19 12:54:26 +020011853static int nl80211_tdls_channel_switch(struct sk_buff *skb,
11854 struct genl_info *info)
11855{
11856 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11857 struct net_device *dev = info->user_ptr[1];
11858 struct wireless_dev *wdev = dev->ieee80211_ptr;
11859 struct cfg80211_chan_def chandef = {};
11860 const u8 *addr;
11861 u8 oper_class;
11862 int err;
11863
11864 if (!rdev->ops->tdls_channel_switch ||
11865 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
11866 return -EOPNOTSUPP;
11867
11868 switch (dev->ieee80211_ptr->iftype) {
11869 case NL80211_IFTYPE_STATION:
11870 case NL80211_IFTYPE_P2P_CLIENT:
11871 break;
11872 default:
11873 return -EOPNOTSUPP;
11874 }
11875
11876 if (!info->attrs[NL80211_ATTR_MAC] ||
11877 !info->attrs[NL80211_ATTR_OPER_CLASS])
11878 return -EINVAL;
11879
11880 err = nl80211_parse_chandef(rdev, info, &chandef);
11881 if (err)
11882 return err;
11883
11884 /*
11885 * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
11886 * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
11887 * specification is not defined for them.
11888 */
Johannes Berg57fbcce2016-04-12 15:56:15 +020011889 if (chandef.chan->band == NL80211_BAND_2GHZ &&
Arik Nemtsov1057d352014-11-19 12:54:26 +020011890 chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
11891 chandef.width != NL80211_CHAN_WIDTH_20)
11892 return -EINVAL;
11893
11894 /* we will be active on the TDLS link */
Arik Nemtsov923b3522015-07-08 15:41:44 +030011895 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
11896 wdev->iftype))
Arik Nemtsov1057d352014-11-19 12:54:26 +020011897 return -EINVAL;
11898
11899 /* don't allow switching to DFS channels */
11900 if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
11901 return -EINVAL;
11902
11903 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
11904 oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
11905
11906 wdev_lock(wdev);
11907 err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
11908 wdev_unlock(wdev);
11909
11910 return err;
11911}
11912
11913static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
11914 struct genl_info *info)
11915{
11916 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11917 struct net_device *dev = info->user_ptr[1];
11918 struct wireless_dev *wdev = dev->ieee80211_ptr;
11919 const u8 *addr;
11920
11921 if (!rdev->ops->tdls_channel_switch ||
11922 !rdev->ops->tdls_cancel_channel_switch ||
11923 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
11924 return -EOPNOTSUPP;
11925
11926 switch (dev->ieee80211_ptr->iftype) {
11927 case NL80211_IFTYPE_STATION:
11928 case NL80211_IFTYPE_P2P_CLIENT:
11929 break;
11930 default:
11931 return -EOPNOTSUPP;
11932 }
11933
11934 if (!info->attrs[NL80211_ATTR_MAC])
11935 return -EINVAL;
11936
11937 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
11938
11939 wdev_lock(wdev);
11940 rdev_tdls_cancel_channel_switch(rdev, dev, addr);
11941 wdev_unlock(wdev);
11942
11943 return 0;
11944}
11945
Michael Braunce0ce132016-10-10 19:12:22 +020011946static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
11947 struct genl_info *info)
11948{
11949 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11950 struct net_device *dev = info->user_ptr[1];
11951 struct wireless_dev *wdev = dev->ieee80211_ptr;
11952 const struct nlattr *nla;
11953 bool enabled;
11954
Michael Braunce0ce132016-10-10 19:12:22 +020011955 if (!rdev->ops->set_multicast_to_unicast)
11956 return -EOPNOTSUPP;
11957
11958 if (wdev->iftype != NL80211_IFTYPE_AP &&
11959 wdev->iftype != NL80211_IFTYPE_P2P_GO)
11960 return -EOPNOTSUPP;
11961
11962 nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
11963 enabled = nla_get_flag(nla);
11964
11965 return rdev_set_multicast_to_unicast(rdev, dev, enabled);
11966}
11967
Johannes Berg4c476992010-10-04 21:36:35 +020011968#define NL80211_FLAG_NEED_WIPHY 0x01
11969#define NL80211_FLAG_NEED_NETDEV 0x02
11970#define NL80211_FLAG_NEED_RTNL 0x04
Johannes Berg41265712010-10-04 21:14:05 +020011971#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
11972#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
11973 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg1bf614e2012-06-15 15:23:36 +020011974#define NL80211_FLAG_NEED_WDEV 0x10
Johannes Berg98104fde2012-06-16 00:19:54 +020011975/* If a netdev is associated, it must be UP, P2P must be started */
Johannes Berg1bf614e2012-06-15 15:23:36 +020011976#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
11977 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg5393b912014-09-10 15:00:16 +030011978#define NL80211_FLAG_CLEAR_SKB 0x20
Johannes Berg4c476992010-10-04 21:36:35 +020011979
Johannes Bergf84f7712013-11-14 17:14:45 +010011980static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020011981 struct genl_info *info)
11982{
11983 struct cfg80211_registered_device *rdev;
Johannes Berg89a54e42012-06-15 14:33:17 +020011984 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020011985 struct net_device *dev;
Johannes Berg4c476992010-10-04 21:36:35 +020011986 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
11987
11988 if (rtnl)
11989 rtnl_lock();
11990
11991 if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
Johannes Berg4f7eff12012-06-15 14:14:22 +020011992 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
Johannes Berg4c476992010-10-04 21:36:35 +020011993 if (IS_ERR(rdev)) {
11994 if (rtnl)
11995 rtnl_unlock();
11996 return PTR_ERR(rdev);
11997 }
11998 info->user_ptr[0] = rdev;
Johannes Berg1bf614e2012-06-15 15:23:36 +020011999 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
12000 ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020012001 ASSERT_RTNL();
12002
Johannes Berg89a54e42012-06-15 14:33:17 +020012003 wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
12004 info->attrs);
12005 if (IS_ERR(wdev)) {
Johannes Berg4c476992010-10-04 21:36:35 +020012006 if (rtnl)
12007 rtnl_unlock();
Johannes Berg89a54e42012-06-15 14:33:17 +020012008 return PTR_ERR(wdev);
Johannes Berg4c476992010-10-04 21:36:35 +020012009 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012010
Johannes Berg89a54e42012-06-15 14:33:17 +020012011 dev = wdev->netdev;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080012012 rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg89a54e42012-06-15 14:33:17 +020012013
Johannes Berg1bf614e2012-06-15 15:23:36 +020012014 if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
12015 if (!dev) {
Johannes Berg1bf614e2012-06-15 15:23:36 +020012016 if (rtnl)
12017 rtnl_unlock();
12018 return -EINVAL;
12019 }
12020
12021 info->user_ptr[1] = dev;
12022 } else {
12023 info->user_ptr[1] = wdev;
Johannes Berg41265712010-10-04 21:14:05 +020012024 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012025
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012026 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
12027 !wdev_running(wdev)) {
12028 if (rtnl)
12029 rtnl_unlock();
12030 return -ENETDOWN;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012031 }
12032
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012033 if (dev)
12034 dev_hold(dev);
12035
Johannes Berg4c476992010-10-04 21:36:35 +020012036 info->user_ptr[0] = rdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012037 }
12038
12039 return 0;
12040}
12041
Johannes Bergf84f7712013-11-14 17:14:45 +010012042static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012043 struct genl_info *info)
12044{
Johannes Berg1bf614e2012-06-15 15:23:36 +020012045 if (info->user_ptr[1]) {
12046 if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
12047 struct wireless_dev *wdev = info->user_ptr[1];
12048
12049 if (wdev->netdev)
12050 dev_put(wdev->netdev);
12051 } else {
12052 dev_put(info->user_ptr[1]);
12053 }
12054 }
Johannes Berg5393b912014-09-10 15:00:16 +030012055
Johannes Berg4c476992010-10-04 21:36:35 +020012056 if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
12057 rtnl_unlock();
Johannes Berg5393b912014-09-10 15:00:16 +030012058
12059 /* If needed, clear the netlink message payload from the SKB
12060 * as it might contain key data that shouldn't stick around on
12061 * the heap after the SKB is freed. The netlink message header
12062 * is still needed for further processing, so leave it intact.
12063 */
12064 if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
12065 struct nlmsghdr *nlh = nlmsg_hdr(skb);
12066
12067 memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
12068 }
Johannes Berg4c476992010-10-04 21:36:35 +020012069}
12070
Johannes Berg4534de82013-11-14 17:14:46 +010012071static const struct genl_ops nl80211_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040012072 {
12073 .cmd = NL80211_CMD_GET_WIPHY,
12074 .doit = nl80211_get_wiphy,
12075 .dumpit = nl80211_dump_wiphy,
Johannes Berg86e8cf92013-06-19 10:57:22 +020012076 .done = nl80211_dump_wiphy_done,
Johannes Berg55682962007-09-20 13:09:35 -040012077 .policy = nl80211_policy,
12078 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012079 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12080 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012081 },
12082 {
12083 .cmd = NL80211_CMD_SET_WIPHY,
12084 .doit = nl80211_set_wiphy,
12085 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012086 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012087 .internal_flags = NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012088 },
12089 {
12090 .cmd = NL80211_CMD_GET_INTERFACE,
12091 .doit = nl80211_get_interface,
12092 .dumpit = nl80211_dump_interface,
12093 .policy = nl80211_policy,
12094 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012095 .internal_flags = NL80211_FLAG_NEED_WDEV |
12096 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012097 },
12098 {
12099 .cmd = NL80211_CMD_SET_INTERFACE,
12100 .doit = nl80211_set_interface,
12101 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012102 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012103 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12104 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012105 },
12106 {
12107 .cmd = NL80211_CMD_NEW_INTERFACE,
12108 .doit = nl80211_new_interface,
12109 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012110 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012111 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12112 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012113 },
12114 {
12115 .cmd = NL80211_CMD_DEL_INTERFACE,
12116 .doit = nl80211_del_interface,
12117 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012118 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg84efbb82012-06-16 00:00:26 +020012119 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012120 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012121 },
Johannes Berg41ade002007-12-19 02:03:29 +010012122 {
12123 .cmd = NL80211_CMD_GET_KEY,
12124 .doit = nl80211_get_key,
12125 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012126 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012127 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012128 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012129 },
12130 {
12131 .cmd = NL80211_CMD_SET_KEY,
12132 .doit = nl80211_set_key,
12133 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012134 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012135 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012136 NL80211_FLAG_NEED_RTNL |
12137 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012138 },
12139 {
12140 .cmd = NL80211_CMD_NEW_KEY,
12141 .doit = nl80211_new_key,
12142 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012143 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012144 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012145 NL80211_FLAG_NEED_RTNL |
12146 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012147 },
12148 {
12149 .cmd = NL80211_CMD_DEL_KEY,
12150 .doit = nl80211_del_key,
12151 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012152 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012153 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012154 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012155 },
Johannes Berged1b6cc2007-12-19 02:03:32 +010012156 {
12157 .cmd = NL80211_CMD_SET_BEACON,
12158 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012159 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012160 .doit = nl80211_set_beacon,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012161 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012162 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012163 },
12164 {
Johannes Berg88600202012-02-13 15:17:18 +010012165 .cmd = NL80211_CMD_START_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012166 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012167 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012168 .doit = nl80211_start_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012169 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012170 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012171 },
12172 {
Johannes Berg88600202012-02-13 15:17:18 +010012173 .cmd = NL80211_CMD_STOP_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012174 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012175 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012176 .doit = nl80211_stop_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012177 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012178 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012179 },
Johannes Berg5727ef12007-12-19 02:03:34 +010012180 {
12181 .cmd = NL80211_CMD_GET_STATION,
12182 .doit = nl80211_get_station,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012183 .dumpit = nl80211_dump_station,
Johannes Berg5727ef12007-12-19 02:03:34 +010012184 .policy = nl80211_policy,
Johannes Berg4c476992010-10-04 21:36:35 +020012185 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12186 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012187 },
12188 {
12189 .cmd = NL80211_CMD_SET_STATION,
12190 .doit = nl80211_set_station,
12191 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012192 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012193 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012194 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012195 },
12196 {
12197 .cmd = NL80211_CMD_NEW_STATION,
12198 .doit = nl80211_new_station,
12199 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012200 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012201 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012202 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012203 },
12204 {
12205 .cmd = NL80211_CMD_DEL_STATION,
12206 .doit = nl80211_del_station,
12207 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012208 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012209 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012210 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012211 },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012212 {
12213 .cmd = NL80211_CMD_GET_MPATH,
12214 .doit = nl80211_get_mpath,
12215 .dumpit = nl80211_dump_mpath,
12216 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012217 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012218 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012219 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012220 },
12221 {
Henning Rogge66be7d22014-09-12 08:58:49 +020012222 .cmd = NL80211_CMD_GET_MPP,
12223 .doit = nl80211_get_mpp,
12224 .dumpit = nl80211_dump_mpp,
12225 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012226 .flags = GENL_UNS_ADMIN_PERM,
Henning Rogge66be7d22014-09-12 08:58:49 +020012227 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12228 NL80211_FLAG_NEED_RTNL,
12229 },
12230 {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012231 .cmd = NL80211_CMD_SET_MPATH,
12232 .doit = nl80211_set_mpath,
12233 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012234 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012235 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012236 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012237 },
12238 {
12239 .cmd = NL80211_CMD_NEW_MPATH,
12240 .doit = nl80211_new_mpath,
12241 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012242 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012243 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012244 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012245 },
12246 {
12247 .cmd = NL80211_CMD_DEL_MPATH,
12248 .doit = nl80211_del_mpath,
12249 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012250 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012251 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012252 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012253 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012254 {
12255 .cmd = NL80211_CMD_SET_BSS,
12256 .doit = nl80211_set_bss,
12257 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012258 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012259 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012260 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012261 },
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012262 {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012263 .cmd = NL80211_CMD_GET_REG,
Arik Nemtsovad30ca22014-12-15 19:25:59 +020012264 .doit = nl80211_get_reg_do,
12265 .dumpit = nl80211_get_reg_dump,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012266 .policy = nl80211_policy,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012267 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012268 /* can be retrieved by unprivileged users */
12269 },
Johannes Bergb6863032015-10-15 09:25:18 +020012270#ifdef CONFIG_CFG80211_CRDA_SUPPORT
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012271 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012272 .cmd = NL80211_CMD_SET_REG,
12273 .doit = nl80211_set_reg,
12274 .policy = nl80211_policy,
12275 .flags = GENL_ADMIN_PERM,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012276 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012277 },
Johannes Bergb6863032015-10-15 09:25:18 +020012278#endif
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012279 {
12280 .cmd = NL80211_CMD_REQ_SET_REG,
12281 .doit = nl80211_req_set_reg,
12282 .policy = nl80211_policy,
12283 .flags = GENL_ADMIN_PERM,
12284 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012285 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012286 .cmd = NL80211_CMD_GET_MESH_CONFIG,
12287 .doit = nl80211_get_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012288 .policy = nl80211_policy,
12289 /* can be retrieved by unprivileged users */
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012290 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012291 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012292 },
12293 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012294 .cmd = NL80211_CMD_SET_MESH_CONFIG,
12295 .doit = nl80211_update_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012296 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012297 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012298 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012299 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012300 },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +020012301 {
Johannes Berg2a519312009-02-10 21:25:55 +010012302 .cmd = NL80211_CMD_TRIGGER_SCAN,
12303 .doit = nl80211_trigger_scan,
12304 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012305 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergfd014282012-06-18 19:17:03 +020012306 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012307 NL80211_FLAG_NEED_RTNL,
Johannes Berg2a519312009-02-10 21:25:55 +010012308 },
12309 {
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012310 .cmd = NL80211_CMD_ABORT_SCAN,
12311 .doit = nl80211_abort_scan,
12312 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012313 .flags = GENL_UNS_ADMIN_PERM,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012314 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12315 NL80211_FLAG_NEED_RTNL,
12316 },
12317 {
Johannes Berg2a519312009-02-10 21:25:55 +010012318 .cmd = NL80211_CMD_GET_SCAN,
12319 .policy = nl80211_policy,
12320 .dumpit = nl80211_dump_scan,
12321 },
Jouni Malinen636a5d32009-03-19 13:39:22 +020012322 {
Luciano Coelho807f8a82011-05-11 17:09:35 +030012323 .cmd = NL80211_CMD_START_SCHED_SCAN,
12324 .doit = nl80211_start_sched_scan,
12325 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012326 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012327 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12328 NL80211_FLAG_NEED_RTNL,
12329 },
12330 {
12331 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
12332 .doit = nl80211_stop_sched_scan,
12333 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012334 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012335 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12336 NL80211_FLAG_NEED_RTNL,
12337 },
12338 {
Jouni Malinen636a5d32009-03-19 13:39:22 +020012339 .cmd = NL80211_CMD_AUTHENTICATE,
12340 .doit = nl80211_authenticate,
12341 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012342 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012343 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012344 NL80211_FLAG_NEED_RTNL |
12345 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012346 },
12347 {
12348 .cmd = NL80211_CMD_ASSOCIATE,
12349 .doit = nl80211_associate,
12350 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012351 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012352 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012353 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012354 },
12355 {
12356 .cmd = NL80211_CMD_DEAUTHENTICATE,
12357 .doit = nl80211_deauthenticate,
12358 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012359 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012360 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012361 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012362 },
12363 {
12364 .cmd = NL80211_CMD_DISASSOCIATE,
12365 .doit = nl80211_disassociate,
12366 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012367 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012368 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012369 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012370 },
Johannes Berg04a773a2009-04-19 21:24:32 +020012371 {
12372 .cmd = NL80211_CMD_JOIN_IBSS,
12373 .doit = nl80211_join_ibss,
12374 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012375 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012376 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012377 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012378 },
12379 {
12380 .cmd = NL80211_CMD_LEAVE_IBSS,
12381 .doit = nl80211_leave_ibss,
12382 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012383 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012384 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012385 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012386 },
Johannes Bergaff89a92009-07-01 21:26:51 +020012387#ifdef CONFIG_NL80211_TESTMODE
12388 {
12389 .cmd = NL80211_CMD_TESTMODE,
12390 .doit = nl80211_testmode_do,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070012391 .dumpit = nl80211_testmode_dump,
Johannes Bergaff89a92009-07-01 21:26:51 +020012392 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012393 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012394 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12395 NL80211_FLAG_NEED_RTNL,
Johannes Bergaff89a92009-07-01 21:26:51 +020012396 },
12397#endif
Samuel Ortizb23aa672009-07-01 21:26:54 +020012398 {
12399 .cmd = NL80211_CMD_CONNECT,
12400 .doit = nl80211_connect,
12401 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012402 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012403 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012404 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012405 },
12406 {
vamsi krishna088e8df2016-10-27 16:51:11 +030012407 .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
12408 .doit = nl80211_update_connect_params,
12409 .policy = nl80211_policy,
12410 .flags = GENL_ADMIN_PERM,
12411 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12412 NL80211_FLAG_NEED_RTNL,
12413 },
12414 {
Samuel Ortizb23aa672009-07-01 21:26:54 +020012415 .cmd = NL80211_CMD_DISCONNECT,
12416 .doit = nl80211_disconnect,
12417 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012418 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012419 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012420 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012421 },
Johannes Berg463d0182009-07-14 00:33:35 +020012422 {
12423 .cmd = NL80211_CMD_SET_WIPHY_NETNS,
12424 .doit = nl80211_wiphy_netns,
12425 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012426 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012427 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12428 NL80211_FLAG_NEED_RTNL,
Johannes Berg463d0182009-07-14 00:33:35 +020012429 },
Holger Schurig61fa7132009-11-11 12:25:40 +010012430 {
12431 .cmd = NL80211_CMD_GET_SURVEY,
12432 .policy = nl80211_policy,
12433 .dumpit = nl80211_dump_survey,
12434 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012435 {
12436 .cmd = NL80211_CMD_SET_PMKSA,
12437 .doit = nl80211_setdel_pmksa,
12438 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012439 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012440 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012441 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012442 },
12443 {
12444 .cmd = NL80211_CMD_DEL_PMKSA,
12445 .doit = nl80211_setdel_pmksa,
12446 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012447 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012448 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012449 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012450 },
12451 {
12452 .cmd = NL80211_CMD_FLUSH_PMKSA,
12453 .doit = nl80211_flush_pmksa,
12454 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012455 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012456 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012457 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012458 },
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012459 {
12460 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
12461 .doit = nl80211_remain_on_channel,
12462 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012463 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012464 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012465 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012466 },
12467 {
12468 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
12469 .doit = nl80211_cancel_remain_on_channel,
12470 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012471 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012472 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012473 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012474 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012475 {
12476 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
12477 .doit = nl80211_set_tx_bitrate_mask,
12478 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012479 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012480 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12481 NL80211_FLAG_NEED_RTNL,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012482 },
Jouni Malinen026331c2010-02-15 12:53:10 +020012483 {
Johannes Berg2e161f782010-08-12 15:38:38 +020012484 .cmd = NL80211_CMD_REGISTER_FRAME,
12485 .doit = nl80211_register_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012486 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012487 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012488 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012489 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012490 },
12491 {
Johannes Berg2e161f782010-08-12 15:38:38 +020012492 .cmd = NL80211_CMD_FRAME,
12493 .doit = nl80211_tx_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012494 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012495 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012496 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012497 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012498 },
Kalle Valoffb9eb32010-02-17 17:58:10 +020012499 {
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012500 .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
12501 .doit = nl80211_tx_mgmt_cancel_wait,
12502 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012503 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012504 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012505 NL80211_FLAG_NEED_RTNL,
12506 },
12507 {
Kalle Valoffb9eb32010-02-17 17:58:10 +020012508 .cmd = NL80211_CMD_SET_POWER_SAVE,
12509 .doit = nl80211_set_power_save,
12510 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012511 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012512 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12513 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012514 },
12515 {
12516 .cmd = NL80211_CMD_GET_POWER_SAVE,
12517 .doit = nl80211_get_power_save,
12518 .policy = nl80211_policy,
12519 /* can be retrieved by unprivileged users */
Johannes Berg4c476992010-10-04 21:36:35 +020012520 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12521 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012522 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012523 {
12524 .cmd = NL80211_CMD_SET_CQM,
12525 .doit = nl80211_set_cqm,
12526 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012527 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012528 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12529 NL80211_FLAG_NEED_RTNL,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012530 },
Johannes Bergf444de02010-05-05 15:25:02 +020012531 {
12532 .cmd = NL80211_CMD_SET_CHANNEL,
12533 .doit = nl80211_set_channel,
12534 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012535 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012536 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12537 NL80211_FLAG_NEED_RTNL,
Johannes Bergf444de02010-05-05 15:25:02 +020012538 },
Bill Jordane8347eb2010-10-01 13:54:28 -040012539 {
12540 .cmd = NL80211_CMD_SET_WDS_PEER,
12541 .doit = nl80211_set_wds_peer,
12542 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012543 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg43b19952010-10-07 13:10:30 +020012544 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12545 NL80211_FLAG_NEED_RTNL,
Bill Jordane8347eb2010-10-01 13:54:28 -040012546 },
Johannes Berg29cbe682010-12-03 09:20:44 +010012547 {
12548 .cmd = NL80211_CMD_JOIN_MESH,
12549 .doit = nl80211_join_mesh,
12550 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012551 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012552 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12553 NL80211_FLAG_NEED_RTNL,
12554 },
12555 {
12556 .cmd = NL80211_CMD_LEAVE_MESH,
12557 .doit = nl80211_leave_mesh,
12558 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012559 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012560 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12561 NL80211_FLAG_NEED_RTNL,
12562 },
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012563 {
12564 .cmd = NL80211_CMD_JOIN_OCB,
12565 .doit = nl80211_join_ocb,
12566 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012567 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012568 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12569 NL80211_FLAG_NEED_RTNL,
12570 },
12571 {
12572 .cmd = NL80211_CMD_LEAVE_OCB,
12573 .doit = nl80211_leave_ocb,
12574 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012575 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012576 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12577 NL80211_FLAG_NEED_RTNL,
12578 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020012579#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +020012580 {
12581 .cmd = NL80211_CMD_GET_WOWLAN,
12582 .doit = nl80211_get_wowlan,
12583 .policy = nl80211_policy,
12584 /* can be retrieved by unprivileged users */
12585 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12586 NL80211_FLAG_NEED_RTNL,
12587 },
12588 {
12589 .cmd = NL80211_CMD_SET_WOWLAN,
12590 .doit = nl80211_set_wowlan,
12591 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012592 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergff1b6e62011-05-04 15:37:28 +020012593 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12594 NL80211_FLAG_NEED_RTNL,
12595 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020012596#endif
Johannes Berge5497d72011-07-05 16:35:40 +020012597 {
12598 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
12599 .doit = nl80211_set_rekey_data,
12600 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012601 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berge5497d72011-07-05 16:35:40 +020012602 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012603 NL80211_FLAG_NEED_RTNL |
12604 NL80211_FLAG_CLEAR_SKB,
Johannes Berge5497d72011-07-05 16:35:40 +020012605 },
Arik Nemtsov109086c2011-09-28 14:12:50 +030012606 {
12607 .cmd = NL80211_CMD_TDLS_MGMT,
12608 .doit = nl80211_tdls_mgmt,
12609 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012610 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030012611 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12612 NL80211_FLAG_NEED_RTNL,
12613 },
12614 {
12615 .cmd = NL80211_CMD_TDLS_OPER,
12616 .doit = nl80211_tdls_oper,
12617 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012618 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030012619 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12620 NL80211_FLAG_NEED_RTNL,
12621 },
Johannes Berg28946da2011-11-04 11:18:12 +010012622 {
12623 .cmd = NL80211_CMD_UNEXPECTED_FRAME,
12624 .doit = nl80211_register_unexpected_frame,
12625 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012626 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg28946da2011-11-04 11:18:12 +010012627 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12628 NL80211_FLAG_NEED_RTNL,
12629 },
Johannes Berg7f6cf312011-11-04 11:18:15 +010012630 {
12631 .cmd = NL80211_CMD_PROBE_CLIENT,
12632 .doit = nl80211_probe_client,
12633 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012634 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012635 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg7f6cf312011-11-04 11:18:15 +010012636 NL80211_FLAG_NEED_RTNL,
12637 },
Johannes Berg5e760232011-11-04 11:18:17 +010012638 {
12639 .cmd = NL80211_CMD_REGISTER_BEACONS,
12640 .doit = nl80211_register_beacons,
12641 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012642 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg5e760232011-11-04 11:18:17 +010012643 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12644 NL80211_FLAG_NEED_RTNL,
12645 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010012646 {
12647 .cmd = NL80211_CMD_SET_NOACK_MAP,
12648 .doit = nl80211_set_noack_map,
12649 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012650 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010012651 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12652 NL80211_FLAG_NEED_RTNL,
12653 },
Johannes Berg98104fde2012-06-16 00:19:54 +020012654 {
12655 .cmd = NL80211_CMD_START_P2P_DEVICE,
12656 .doit = nl80211_start_p2p_device,
12657 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012658 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020012659 .internal_flags = NL80211_FLAG_NEED_WDEV |
12660 NL80211_FLAG_NEED_RTNL,
12661 },
12662 {
12663 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
12664 .doit = nl80211_stop_p2p_device,
12665 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012666 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020012667 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12668 NL80211_FLAG_NEED_RTNL,
12669 },
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012670 {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012671 .cmd = NL80211_CMD_START_NAN,
12672 .doit = nl80211_start_nan,
12673 .policy = nl80211_policy,
12674 .flags = GENL_ADMIN_PERM,
12675 .internal_flags = NL80211_FLAG_NEED_WDEV |
12676 NL80211_FLAG_NEED_RTNL,
12677 },
12678 {
12679 .cmd = NL80211_CMD_STOP_NAN,
12680 .doit = nl80211_stop_nan,
12681 .policy = nl80211_policy,
12682 .flags = GENL_ADMIN_PERM,
12683 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12684 NL80211_FLAG_NEED_RTNL,
12685 },
12686 {
Ayala Bekera442b762016-09-20 17:31:15 +030012687 .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
12688 .doit = nl80211_nan_add_func,
12689 .policy = nl80211_policy,
12690 .flags = GENL_ADMIN_PERM,
12691 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12692 NL80211_FLAG_NEED_RTNL,
12693 },
12694 {
12695 .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
12696 .doit = nl80211_nan_del_func,
12697 .policy = nl80211_policy,
12698 .flags = GENL_ADMIN_PERM,
12699 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12700 NL80211_FLAG_NEED_RTNL,
12701 },
12702 {
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030012703 .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
12704 .doit = nl80211_nan_change_config,
12705 .policy = nl80211_policy,
12706 .flags = GENL_ADMIN_PERM,
12707 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12708 NL80211_FLAG_NEED_RTNL,
12709 },
12710 {
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012711 .cmd = NL80211_CMD_SET_MCAST_RATE,
12712 .doit = nl80211_set_mcast_rate,
12713 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012714 .flags = GENL_UNS_ADMIN_PERM,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012715 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12716 NL80211_FLAG_NEED_RTNL,
12717 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053012718 {
12719 .cmd = NL80211_CMD_SET_MAC_ACL,
12720 .doit = nl80211_set_mac_acl,
12721 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012722 .flags = GENL_UNS_ADMIN_PERM,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053012723 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12724 NL80211_FLAG_NEED_RTNL,
12725 },
Simon Wunderlich04f39042013-02-08 18:16:19 +010012726 {
12727 .cmd = NL80211_CMD_RADAR_DETECT,
12728 .doit = nl80211_start_radar_detection,
12729 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012730 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich04f39042013-02-08 18:16:19 +010012731 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12732 NL80211_FLAG_NEED_RTNL,
12733 },
Johannes Berg3713b4e2013-02-14 16:19:38 +010012734 {
12735 .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
12736 .doit = nl80211_get_protocol_features,
12737 .policy = nl80211_policy,
12738 },
Jouni Malinen355199e2013-02-27 17:14:27 +020012739 {
12740 .cmd = NL80211_CMD_UPDATE_FT_IES,
12741 .doit = nl80211_update_ft_ies,
12742 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012743 .flags = GENL_UNS_ADMIN_PERM,
Jouni Malinen355199e2013-02-27 17:14:27 +020012744 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12745 NL80211_FLAG_NEED_RTNL,
12746 },
Arend van Spriel5de17982013-04-18 15:49:00 +020012747 {
12748 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
12749 .doit = nl80211_crit_protocol_start,
12750 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012751 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020012752 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12753 NL80211_FLAG_NEED_RTNL,
12754 },
12755 {
12756 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
12757 .doit = nl80211_crit_protocol_stop,
12758 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012759 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020012760 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12761 NL80211_FLAG_NEED_RTNL,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012762 },
12763 {
12764 .cmd = NL80211_CMD_GET_COALESCE,
12765 .doit = nl80211_get_coalesce,
12766 .policy = nl80211_policy,
12767 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12768 NL80211_FLAG_NEED_RTNL,
12769 },
12770 {
12771 .cmd = NL80211_CMD_SET_COALESCE,
12772 .doit = nl80211_set_coalesce,
12773 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012774 .flags = GENL_UNS_ADMIN_PERM,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012775 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12776 NL80211_FLAG_NEED_RTNL,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020012777 },
12778 {
12779 .cmd = NL80211_CMD_CHANNEL_SWITCH,
12780 .doit = nl80211_channel_switch,
12781 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012782 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020012783 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12784 NL80211_FLAG_NEED_RTNL,
12785 },
Johannes Bergad7e7182013-11-13 13:37:47 +010012786 {
12787 .cmd = NL80211_CMD_VENDOR,
12788 .doit = nl80211_vendor_cmd,
Johannes Berg7bdbe402015-08-15 22:39:49 +030012789 .dumpit = nl80211_vendor_cmd_dump,
Johannes Bergad7e7182013-11-13 13:37:47 +010012790 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012791 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergad7e7182013-11-13 13:37:47 +010012792 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12793 NL80211_FLAG_NEED_RTNL,
12794 },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080012795 {
12796 .cmd = NL80211_CMD_SET_QOS_MAP,
12797 .doit = nl80211_set_qos_map,
12798 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012799 .flags = GENL_UNS_ADMIN_PERM,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080012800 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12801 NL80211_FLAG_NEED_RTNL,
12802 },
Johannes Berg960d01a2014-09-09 22:55:35 +030012803 {
12804 .cmd = NL80211_CMD_ADD_TX_TS,
12805 .doit = nl80211_add_tx_ts,
12806 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012807 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030012808 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12809 NL80211_FLAG_NEED_RTNL,
12810 },
12811 {
12812 .cmd = NL80211_CMD_DEL_TX_TS,
12813 .doit = nl80211_del_tx_ts,
12814 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012815 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030012816 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12817 NL80211_FLAG_NEED_RTNL,
12818 },
Arik Nemtsov1057d352014-11-19 12:54:26 +020012819 {
12820 .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
12821 .doit = nl80211_tdls_channel_switch,
12822 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012823 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020012824 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12825 NL80211_FLAG_NEED_RTNL,
12826 },
12827 {
12828 .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
12829 .doit = nl80211_tdls_cancel_channel_switch,
12830 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012831 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020012832 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12833 NL80211_FLAG_NEED_RTNL,
12834 },
Michael Braunce0ce132016-10-10 19:12:22 +020012835 {
12836 .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
12837 .doit = nl80211_set_multicast_to_unicast,
12838 .policy = nl80211_policy,
12839 .flags = GENL_UNS_ADMIN_PERM,
12840 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12841 NL80211_FLAG_NEED_RTNL,
12842 },
Johannes Berg55682962007-09-20 13:09:35 -040012843};
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012844
Johannes Berg56989f62016-10-24 14:40:05 +020012845static struct genl_family nl80211_fam __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +020012846 .name = NL80211_GENL_NAME, /* have users key off the name instead */
12847 .hdrsize = 0, /* no private header */
12848 .version = 1, /* no particular meaning now */
12849 .maxattr = NL80211_ATTR_MAX,
12850 .netnsok = true,
12851 .pre_doit = nl80211_pre_doit,
12852 .post_doit = nl80211_post_doit,
12853 .module = THIS_MODULE,
12854 .ops = nl80211_ops,
12855 .n_ops = ARRAY_SIZE(nl80211_ops),
12856 .mcgrps = nl80211_mcgrps,
12857 .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
12858};
12859
Johannes Berg55682962007-09-20 13:09:35 -040012860/* notification functions */
12861
Johannes Berg3bb20552014-05-26 13:52:25 +020012862void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
12863 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -040012864{
12865 struct sk_buff *msg;
Johannes Berg86e8cf92013-06-19 10:57:22 +020012866 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -040012867
Johannes Berg3bb20552014-05-26 13:52:25 +020012868 WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
12869 cmd != NL80211_CMD_DEL_WIPHY);
12870
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070012871 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040012872 if (!msg)
12873 return;
12874
Johannes Berg3bb20552014-05-26 13:52:25 +020012875 if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
Johannes Berg55682962007-09-20 13:09:35 -040012876 nlmsg_free(msg);
12877 return;
12878 }
12879
Johannes Berg68eb5502013-11-19 15:19:38 +010012880 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010012881 NL80211_MCGRP_CONFIG, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040012882}
12883
Denis Kenzior896ff062016-08-03 16:58:33 -050012884void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
12885 struct wireless_dev *wdev,
12886 enum nl80211_commands cmd)
12887{
12888 struct sk_buff *msg;
12889
12890 WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
12891 cmd != NL80211_CMD_DEL_INTERFACE);
12892
12893 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12894 if (!msg)
12895 return;
12896
12897 if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
12898 cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
12899 nlmsg_free(msg);
12900 return;
12901 }
12902
12903 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
12904 NL80211_MCGRP_CONFIG, GFP_KERNEL);
12905}
12906
Johannes Berg362a4152009-05-24 16:43:15 +020012907static int nl80211_add_scan_req(struct sk_buff *msg,
12908 struct cfg80211_registered_device *rdev)
12909{
12910 struct cfg80211_scan_request *req = rdev->scan_req;
12911 struct nlattr *nest;
12912 int i;
12913
12914 if (WARN_ON(!req))
12915 return 0;
12916
12917 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
12918 if (!nest)
12919 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040012920 for (i = 0; i < req->n_ssids; i++) {
12921 if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
12922 goto nla_put_failure;
12923 }
Johannes Berg362a4152009-05-24 16:43:15 +020012924 nla_nest_end(msg, nest);
12925
12926 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
12927 if (!nest)
12928 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040012929 for (i = 0; i < req->n_channels; i++) {
12930 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
12931 goto nla_put_failure;
12932 }
Johannes Berg362a4152009-05-24 16:43:15 +020012933 nla_nest_end(msg, nest);
12934
David S. Miller9360ffd2012-03-29 04:41:26 -040012935 if (req->ie &&
12936 nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
12937 goto nla_put_failure;
Johannes Berg362a4152009-05-24 16:43:15 +020012938
Johannes Bergae917c92013-10-25 11:05:22 +020012939 if (req->flags &&
12940 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
12941 goto nla_put_failure;
Sam Lefflered4737712012-10-11 21:03:31 -070012942
Avraham Stern1d762502016-07-05 17:10:13 +030012943 if (req->info.scan_start_tsf &&
12944 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
12945 req->info.scan_start_tsf, NL80211_BSS_PAD) ||
12946 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
12947 req->info.tsf_bssid)))
12948 goto nla_put_failure;
12949
Johannes Berg362a4152009-05-24 16:43:15 +020012950 return 0;
12951 nla_put_failure:
12952 return -ENOBUFS;
12953}
12954
Arend Van Spriel505a2e82016-12-16 11:21:54 +000012955static int nl80211_prep_scan_msg(struct sk_buff *msg,
Johannes Berga538e2d2009-06-16 19:56:42 +020012956 struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020012957 struct wireless_dev *wdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000012958 u32 portid, u32 seq, int flags,
Johannes Berga538e2d2009-06-16 19:56:42 +020012959 u32 cmd)
Johannes Berg2a519312009-02-10 21:25:55 +010012960{
12961 void *hdr;
12962
Eric W. Biederman15e47302012-09-07 20:12:54 +000012963 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg2a519312009-02-10 21:25:55 +010012964 if (!hdr)
12965 return -1;
12966
David S. Miller9360ffd2012-03-29 04:41:26 -040012967 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Bergfd014282012-06-18 19:17:03 +020012968 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
12969 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020012970 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
12971 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040012972 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +010012973
Johannes Berg362a4152009-05-24 16:43:15 +020012974 /* ignore errors and send incomplete event anyway */
12975 nl80211_add_scan_req(msg, rdev);
Johannes Berg2a519312009-02-10 21:25:55 +010012976
Johannes Berg053c0952015-01-16 22:09:00 +010012977 genlmsg_end(msg, hdr);
12978 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +010012979
12980 nla_put_failure:
12981 genlmsg_cancel(msg, hdr);
12982 return -EMSGSIZE;
12983}
12984
Luciano Coelho807f8a82011-05-11 17:09:35 +030012985static int
Arend Van Spriel505a2e82016-12-16 11:21:54 +000012986nl80211_prep_sched_scan_msg(struct sk_buff *msg,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012987 struct cfg80211_registered_device *rdev,
12988 struct net_device *netdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000012989 u32 portid, u32 seq, int flags, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030012990{
12991 void *hdr;
12992
Eric W. Biederman15e47302012-09-07 20:12:54 +000012993 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Luciano Coelho807f8a82011-05-11 17:09:35 +030012994 if (!hdr)
12995 return -1;
12996
David S. Miller9360ffd2012-03-29 04:41:26 -040012997 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
12998 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
12999 goto nla_put_failure;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013000
Johannes Berg053c0952015-01-16 22:09:00 +010013001 genlmsg_end(msg, hdr);
13002 return 0;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013003
13004 nla_put_failure:
13005 genlmsg_cancel(msg, hdr);
13006 return -EMSGSIZE;
13007}
13008
Johannes Berga538e2d2009-06-16 19:56:42 +020013009void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013010 struct wireless_dev *wdev)
Johannes Berga538e2d2009-06-16 19:56:42 +020013011{
13012 struct sk_buff *msg;
13013
Thomas Graf58050fc2012-06-28 03:57:45 +000013014 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013015 if (!msg)
13016 return;
13017
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013018 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Berga538e2d2009-06-16 19:56:42 +020013019 NL80211_CMD_TRIGGER_SCAN) < 0) {
13020 nlmsg_free(msg);
13021 return;
13022 }
13023
Johannes Berg68eb5502013-11-19 15:19:38 +010013024 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013025 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013026}
13027
Johannes Bergf9d15d12014-01-22 11:14:19 +020013028struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
13029 struct wireless_dev *wdev, bool aborted)
Johannes Berg2a519312009-02-10 21:25:55 +010013030{
13031 struct sk_buff *msg;
13032
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013033 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013034 if (!msg)
Johannes Bergf9d15d12014-01-22 11:14:19 +020013035 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013036
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013037 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Bergf9d15d12014-01-22 11:14:19 +020013038 aborted ? NL80211_CMD_SCAN_ABORTED :
13039 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +010013040 nlmsg_free(msg);
Johannes Bergf9d15d12014-01-22 11:14:19 +020013041 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013042 }
13043
Johannes Bergf9d15d12014-01-22 11:14:19 +020013044 return msg;
Johannes Berg2a519312009-02-10 21:25:55 +010013045}
13046
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013047/* send message created by nl80211_build_scan_msg() */
13048void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
13049 struct sk_buff *msg)
Johannes Berg2a519312009-02-10 21:25:55 +010013050{
Johannes Berg2a519312009-02-10 21:25:55 +010013051 if (!msg)
13052 return;
13053
Johannes Berg68eb5502013-11-19 15:19:38 +010013054 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013055 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013056}
13057
Luciano Coelho807f8a82011-05-11 17:09:35 +030013058void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
13059 struct net_device *netdev, u32 cmd)
13060{
13061 struct sk_buff *msg;
13062
Thomas Graf58050fc2012-06-28 03:57:45 +000013063 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013064 if (!msg)
13065 return;
13066
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013067 if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
Luciano Coelho807f8a82011-05-11 17:09:35 +030013068 nlmsg_free(msg);
13069 return;
13070 }
13071
Johannes Berg68eb5502013-11-19 15:19:38 +010013072 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013073 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013074}
13075
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013076static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
13077 struct regulatory_request *request)
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013078{
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013079 /* Userspace can always count this one always being set */
David S. Miller9360ffd2012-03-29 04:41:26 -040013080 if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
13081 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013082
David S. Miller9360ffd2012-03-29 04:41:26 -040013083 if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
13084 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13085 NL80211_REGDOM_TYPE_WORLD))
13086 goto nla_put_failure;
13087 } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
13088 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13089 NL80211_REGDOM_TYPE_CUSTOM_WORLD))
13090 goto nla_put_failure;
13091 } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
13092 request->intersect) {
13093 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13094 NL80211_REGDOM_TYPE_INTERSECTION))
13095 goto nla_put_failure;
13096 } else {
13097 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13098 NL80211_REGDOM_TYPE_COUNTRY) ||
13099 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
13100 request->alpha2))
13101 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013102 }
13103
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013104 if (request->wiphy_idx != WIPHY_IDX_INVALID) {
13105 struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
13106
13107 if (wiphy &&
13108 nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
13109 goto nla_put_failure;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +020013110
13111 if (wiphy &&
13112 wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
13113 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
13114 goto nla_put_failure;
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013115 }
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013116
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013117 return true;
13118
13119nla_put_failure:
13120 return false;
13121}
13122
13123/*
13124 * This can happen on global regulatory changes or device specific settings
13125 * based on custom regulatory domains.
13126 */
13127void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
13128 struct regulatory_request *request)
13129{
13130 struct sk_buff *msg;
13131 void *hdr;
13132
13133 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13134 if (!msg)
13135 return;
13136
13137 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
13138 if (!hdr) {
13139 nlmsg_free(msg);
13140 return;
13141 }
13142
13143 if (nl80211_reg_change_event_fill(msg, request) == false)
13144 goto nla_put_failure;
13145
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013146 genlmsg_end(msg, hdr);
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013147
Johannes Bergbc43b282009-07-25 10:54:13 +020013148 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013149 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013150 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Bergbc43b282009-07-25 10:54:13 +020013151 rcu_read_unlock();
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013152
13153 return;
13154
13155nla_put_failure:
13156 genlmsg_cancel(msg, hdr);
13157 nlmsg_free(msg);
13158}
13159
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013160static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
13161 struct net_device *netdev,
13162 const u8 *buf, size_t len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013163 enum nl80211_commands cmd, gfp_t gfp,
13164 int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013165{
13166 struct sk_buff *msg;
13167 void *hdr;
13168
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013169 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013170 if (!msg)
13171 return;
13172
13173 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13174 if (!hdr) {
13175 nlmsg_free(msg);
13176 return;
13177 }
13178
David S. Miller9360ffd2012-03-29 04:41:26 -040013179 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13180 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13181 nla_put(msg, NL80211_ATTR_FRAME, len, buf))
13182 goto nla_put_failure;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013183
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013184 if (uapsd_queues >= 0) {
13185 struct nlattr *nla_wmm =
13186 nla_nest_start(msg, NL80211_ATTR_STA_WME);
13187 if (!nla_wmm)
13188 goto nla_put_failure;
13189
13190 if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
13191 uapsd_queues))
13192 goto nla_put_failure;
13193
13194 nla_nest_end(msg, nla_wmm);
13195 }
13196
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013197 genlmsg_end(msg, hdr);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013198
Johannes Berg68eb5502013-11-19 15:19:38 +010013199 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013200 NL80211_MCGRP_MLME, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013201 return;
13202
13203 nla_put_failure:
13204 genlmsg_cancel(msg, hdr);
13205 nlmsg_free(msg);
13206}
13207
13208void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013209 struct net_device *netdev, const u8 *buf,
13210 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013211{
13212 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013213 NL80211_CMD_AUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013214}
13215
13216void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
13217 struct net_device *netdev, const u8 *buf,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013218 size_t len, gfp_t gfp, int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013219{
Johannes Berge6d6e342009-07-01 21:26:47 +020013220 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013221 NL80211_CMD_ASSOCIATE, gfp, uapsd_queues);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013222}
13223
Jouni Malinen53b46b82009-03-27 20:53:56 +020013224void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013225 struct net_device *netdev, const u8 *buf,
13226 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013227{
13228 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013229 NL80211_CMD_DEAUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013230}
13231
Jouni Malinen53b46b82009-03-27 20:53:56 +020013232void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
13233 struct net_device *netdev, const u8 *buf,
Johannes Berge6d6e342009-07-01 21:26:47 +020013234 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013235{
13236 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013237 NL80211_CMD_DISASSOCIATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013238}
13239
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013240void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
13241 size_t len)
Jouni Malinencf4e5942010-12-16 00:52:40 +020013242{
Johannes Berg947add32013-02-22 22:05:20 +010013243 struct wireless_dev *wdev = dev->ieee80211_ptr;
13244 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013245 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013246 const struct ieee80211_mgmt *mgmt = (void *)buf;
13247 u32 cmd;
Jouni Malinencf4e5942010-12-16 00:52:40 +020013248
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013249 if (WARN_ON(len < 2))
13250 return;
13251
13252 if (ieee80211_is_deauth(mgmt->frame_control))
13253 cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
13254 else
13255 cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
13256
13257 trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013258 nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013259}
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013260EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013261
Luis R. Rodriguez1b06bb42009-05-02 00:34:48 -040013262static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
13263 struct net_device *netdev, int cmd,
Johannes Berge6d6e342009-07-01 21:26:47 +020013264 const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013265{
13266 struct sk_buff *msg;
13267 void *hdr;
13268
Johannes Berge6d6e342009-07-01 21:26:47 +020013269 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013270 if (!msg)
13271 return;
13272
13273 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13274 if (!hdr) {
13275 nlmsg_free(msg);
13276 return;
13277 }
13278
David S. Miller9360ffd2012-03-29 04:41:26 -040013279 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13280 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13281 nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
13282 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
13283 goto nla_put_failure;
Jouni Malinen1965c852009-04-22 21:38:25 +030013284
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013285 genlmsg_end(msg, hdr);
Jouni Malinen1965c852009-04-22 21:38:25 +030013286
Johannes Berg68eb5502013-11-19 15:19:38 +010013287 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013288 NL80211_MCGRP_MLME, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013289 return;
13290
13291 nla_put_failure:
13292 genlmsg_cancel(msg, hdr);
13293 nlmsg_free(msg);
13294}
13295
13296void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013297 struct net_device *netdev, const u8 *addr,
13298 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013299{
13300 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
Johannes Berge6d6e342009-07-01 21:26:47 +020013301 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013302}
13303
13304void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013305 struct net_device *netdev, const u8 *addr,
13306 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013307{
Johannes Berge6d6e342009-07-01 21:26:47 +020013308 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
13309 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013310}
13311
Samuel Ortizb23aa672009-07-01 21:26:54 +020013312void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
13313 struct net_device *netdev, const u8 *bssid,
13314 const u8 *req_ie, size_t req_ie_len,
13315 const u8 *resp_ie, size_t resp_ie_len,
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020013316 int status,
13317 enum nl80211_timeout_reason timeout_reason,
13318 gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013319{
13320 struct sk_buff *msg;
13321 void *hdr;
13322
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013323 msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013324 if (!msg)
13325 return;
13326
13327 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
13328 if (!hdr) {
13329 nlmsg_free(msg);
13330 return;
13331 }
13332
David S. Miller9360ffd2012-03-29 04:41:26 -040013333 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13334 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13335 (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
Jouni Malinenbf1ecd22016-05-31 00:16:50 +030013336 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
13337 status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
13338 status) ||
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020013339 (status < 0 &&
13340 (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
13341 nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013342 (req_ie &&
13343 nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
13344 (resp_ie &&
13345 nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
13346 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013347
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013348 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013349
Johannes Berg68eb5502013-11-19 15:19:38 +010013350 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013351 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013352 return;
13353
13354 nla_put_failure:
13355 genlmsg_cancel(msg, hdr);
13356 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013357}
13358
13359void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
13360 struct net_device *netdev, const u8 *bssid,
13361 const u8 *req_ie, size_t req_ie_len,
13362 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
13363{
13364 struct sk_buff *msg;
13365 void *hdr;
13366
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013367 msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013368 if (!msg)
13369 return;
13370
13371 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
13372 if (!hdr) {
13373 nlmsg_free(msg);
13374 return;
13375 }
13376
David S. Miller9360ffd2012-03-29 04:41:26 -040013377 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13378 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13379 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
13380 (req_ie &&
13381 nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
13382 (resp_ie &&
13383 nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
13384 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013385
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013386 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013387
Johannes Berg68eb5502013-11-19 15:19:38 +010013388 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013389 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013390 return;
13391
13392 nla_put_failure:
13393 genlmsg_cancel(msg, hdr);
13394 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013395}
13396
13397void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
13398 struct net_device *netdev, u16 reason,
Johannes Berg667503d2009-07-07 03:56:11 +020013399 const u8 *ie, size_t ie_len, bool from_ap)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013400{
13401 struct sk_buff *msg;
13402 void *hdr;
13403
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013404 msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013405 if (!msg)
13406 return;
13407
13408 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
13409 if (!hdr) {
13410 nlmsg_free(msg);
13411 return;
13412 }
13413
David S. Miller9360ffd2012-03-29 04:41:26 -040013414 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13415 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13416 (from_ap && reason &&
13417 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
13418 (from_ap &&
13419 nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
13420 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
13421 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013422
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013423 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013424
Johannes Berg68eb5502013-11-19 15:19:38 +010013425 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013426 NL80211_MCGRP_MLME, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013427 return;
13428
13429 nla_put_failure:
13430 genlmsg_cancel(msg, hdr);
13431 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013432}
13433
Johannes Berg04a773a2009-04-19 21:24:32 +020013434void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
13435 struct net_device *netdev, const u8 *bssid,
13436 gfp_t gfp)
13437{
13438 struct sk_buff *msg;
13439 void *hdr;
13440
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013441 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013442 if (!msg)
13443 return;
13444
13445 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
13446 if (!hdr) {
13447 nlmsg_free(msg);
13448 return;
13449 }
13450
David S. Miller9360ffd2012-03-29 04:41:26 -040013451 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13452 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13453 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
13454 goto nla_put_failure;
Johannes Berg04a773a2009-04-19 21:24:32 +020013455
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013456 genlmsg_end(msg, hdr);
Johannes Berg04a773a2009-04-19 21:24:32 +020013457
Johannes Berg68eb5502013-11-19 15:19:38 +010013458 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013459 NL80211_MCGRP_MLME, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013460 return;
13461
13462 nla_put_failure:
13463 genlmsg_cancel(msg, hdr);
13464 nlmsg_free(msg);
13465}
13466
Johannes Berg947add32013-02-22 22:05:20 +010013467void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
13468 const u8* ie, u8 ie_len, gfp_t gfp)
Javier Cardonac93b5e72011-04-07 15:08:34 -070013469{
Johannes Berg947add32013-02-22 22:05:20 +010013470 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013471 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013472 struct sk_buff *msg;
13473 void *hdr;
13474
Johannes Berg947add32013-02-22 22:05:20 +010013475 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
13476 return;
13477
13478 trace_cfg80211_notify_new_peer_candidate(dev, addr);
13479
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013480 msg = nlmsg_new(100 + ie_len, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013481 if (!msg)
13482 return;
13483
13484 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
13485 if (!hdr) {
13486 nlmsg_free(msg);
13487 return;
13488 }
13489
David S. Miller9360ffd2012-03-29 04:41:26 -040013490 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010013491 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13492 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013493 (ie_len && ie &&
13494 nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
13495 goto nla_put_failure;
Javier Cardonac93b5e72011-04-07 15:08:34 -070013496
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013497 genlmsg_end(msg, hdr);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013498
Johannes Berg68eb5502013-11-19 15:19:38 +010013499 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013500 NL80211_MCGRP_MLME, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013501 return;
13502
13503 nla_put_failure:
13504 genlmsg_cancel(msg, hdr);
13505 nlmsg_free(msg);
13506}
Johannes Berg947add32013-02-22 22:05:20 +010013507EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013508
Jouni Malinena3b8b052009-03-27 21:59:49 +020013509void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
13510 struct net_device *netdev, const u8 *addr,
13511 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +020013512 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +020013513{
13514 struct sk_buff *msg;
13515 void *hdr;
13516
Johannes Berge6d6e342009-07-01 21:26:47 +020013517 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013518 if (!msg)
13519 return;
13520
13521 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
13522 if (!hdr) {
13523 nlmsg_free(msg);
13524 return;
13525 }
13526
David S. Miller9360ffd2012-03-29 04:41:26 -040013527 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13528 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13529 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
13530 nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
13531 (key_id != -1 &&
13532 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
13533 (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
13534 goto nla_put_failure;
Jouni Malinena3b8b052009-03-27 21:59:49 +020013535
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013536 genlmsg_end(msg, hdr);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013537
Johannes Berg68eb5502013-11-19 15:19:38 +010013538 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013539 NL80211_MCGRP_MLME, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013540 return;
13541
13542 nla_put_failure:
13543 genlmsg_cancel(msg, hdr);
13544 nlmsg_free(msg);
13545}
13546
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013547void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
13548 struct ieee80211_channel *channel_before,
13549 struct ieee80211_channel *channel_after)
13550{
13551 struct sk_buff *msg;
13552 void *hdr;
13553 struct nlattr *nl_freq;
13554
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013555 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013556 if (!msg)
13557 return;
13558
13559 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
13560 if (!hdr) {
13561 nlmsg_free(msg);
13562 return;
13563 }
13564
13565 /*
13566 * Since we are applying the beacon hint to a wiphy we know its
13567 * wiphy_idx is valid
13568 */
David S. Miller9360ffd2012-03-29 04:41:26 -040013569 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
13570 goto nla_put_failure;
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013571
13572 /* Before */
13573 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
13574 if (!nl_freq)
13575 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010013576 if (nl80211_msg_put_channel(msg, channel_before, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013577 goto nla_put_failure;
13578 nla_nest_end(msg, nl_freq);
13579
13580 /* After */
13581 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
13582 if (!nl_freq)
13583 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010013584 if (nl80211_msg_put_channel(msg, channel_after, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013585 goto nla_put_failure;
13586 nla_nest_end(msg, nl_freq);
13587
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013588 genlmsg_end(msg, hdr);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013589
Johannes Berg463d0182009-07-14 00:33:35 +020013590 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013591 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013592 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Berg463d0182009-07-14 00:33:35 +020013593 rcu_read_unlock();
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013594
13595 return;
13596
13597nla_put_failure:
13598 genlmsg_cancel(msg, hdr);
13599 nlmsg_free(msg);
13600}
13601
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013602static void nl80211_send_remain_on_chan_event(
13603 int cmd, struct cfg80211_registered_device *rdev,
Johannes Berg71bbc992012-06-15 15:30:18 +020013604 struct wireless_dev *wdev, u64 cookie,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013605 struct ieee80211_channel *chan,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013606 unsigned int duration, gfp_t gfp)
13607{
13608 struct sk_buff *msg;
13609 void *hdr;
13610
13611 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13612 if (!msg)
13613 return;
13614
13615 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13616 if (!hdr) {
13617 nlmsg_free(msg);
13618 return;
13619 }
13620
David S. Miller9360ffd2012-03-29 04:41:26 -040013621 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013622 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13623 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013624 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13625 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013626 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
Johannes Berg42d97a52012-11-08 18:31:02 +010013627 nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
13628 NL80211_CHAN_NO_HT) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013629 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13630 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013631 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013632
David S. Miller9360ffd2012-03-29 04:41:26 -040013633 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
13634 nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
13635 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013636
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013637 genlmsg_end(msg, hdr);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013638
Johannes Berg68eb5502013-11-19 15:19:38 +010013639 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013640 NL80211_MCGRP_MLME, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013641 return;
13642
13643 nla_put_failure:
13644 genlmsg_cancel(msg, hdr);
13645 nlmsg_free(msg);
13646}
13647
Johannes Berg947add32013-02-22 22:05:20 +010013648void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
13649 struct ieee80211_channel *chan,
13650 unsigned int duration, gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013651{
Johannes Berg947add32013-02-22 22:05:20 +010013652 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013653 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010013654
13655 trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013656 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Berg71bbc992012-06-15 15:30:18 +020013657 rdev, wdev, cookie, chan,
Johannes Berg42d97a52012-11-08 18:31:02 +010013658 duration, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013659}
Johannes Berg947add32013-02-22 22:05:20 +010013660EXPORT_SYMBOL(cfg80211_ready_on_channel);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013661
Johannes Berg947add32013-02-22 22:05:20 +010013662void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
13663 struct ieee80211_channel *chan,
13664 gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013665{
Johannes Berg947add32013-02-22 22:05:20 +010013666 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013667 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010013668
13669 trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013670 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Berg42d97a52012-11-08 18:31:02 +010013671 rdev, wdev, cookie, chan, 0, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013672}
Johannes Berg947add32013-02-22 22:05:20 +010013673EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013674
Johannes Berg947add32013-02-22 22:05:20 +010013675void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
13676 struct station_info *sinfo, gfp_t gfp)
Johannes Berg98b62182009-12-23 13:15:44 +010013677{
Johannes Berg947add32013-02-22 22:05:20 +010013678 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013679 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg98b62182009-12-23 13:15:44 +010013680 struct sk_buff *msg;
13681
Johannes Berg947add32013-02-22 22:05:20 +010013682 trace_cfg80211_new_sta(dev, mac_addr, sinfo);
13683
Thomas Graf58050fc2012-06-28 03:57:45 +000013684 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010013685 if (!msg)
13686 return;
13687
Johannes Bergcf5ead82014-11-14 17:14:00 +010013688 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
John W. Linville66266b32012-03-15 13:25:41 -040013689 rdev, dev, mac_addr, sinfo) < 0) {
Johannes Berg98b62182009-12-23 13:15:44 +010013690 nlmsg_free(msg);
13691 return;
13692 }
13693
Johannes Berg68eb5502013-11-19 15:19:38 +010013694 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013695 NL80211_MCGRP_MLME, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010013696}
Johannes Berg947add32013-02-22 22:05:20 +010013697EXPORT_SYMBOL(cfg80211_new_sta);
Johannes Berg98b62182009-12-23 13:15:44 +010013698
Johannes Bergcf5ead82014-11-14 17:14:00 +010013699void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
13700 struct station_info *sinfo, gfp_t gfp)
Jouni Malinenec15e682011-03-23 15:29:52 +020013701{
Johannes Berg947add32013-02-22 22:05:20 +010013702 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013703 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinenec15e682011-03-23 15:29:52 +020013704 struct sk_buff *msg;
Johannes Bergcf5ead82014-11-14 17:14:00 +010013705 struct station_info empty_sinfo = {};
13706
13707 if (!sinfo)
13708 sinfo = &empty_sinfo;
Jouni Malinenec15e682011-03-23 15:29:52 +020013709
Johannes Berg947add32013-02-22 22:05:20 +010013710 trace_cfg80211_del_sta(dev, mac_addr);
13711
Thomas Graf58050fc2012-06-28 03:57:45 +000013712 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020013713 if (!msg)
13714 return;
13715
Johannes Bergcf5ead82014-11-14 17:14:00 +010013716 if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
Johannes Berg57007122015-01-16 21:05:02 +010013717 rdev, dev, mac_addr, sinfo) < 0) {
Jouni Malinenec15e682011-03-23 15:29:52 +020013718 nlmsg_free(msg);
13719 return;
13720 }
13721
Johannes Berg68eb5502013-11-19 15:19:38 +010013722 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013723 NL80211_MCGRP_MLME, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020013724}
Johannes Bergcf5ead82014-11-14 17:14:00 +010013725EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
Jouni Malinenec15e682011-03-23 15:29:52 +020013726
Johannes Berg947add32013-02-22 22:05:20 +010013727void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
13728 enum nl80211_connect_failed_reason reason,
13729 gfp_t gfp)
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013730{
Johannes Berg947add32013-02-22 22:05:20 +010013731 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013732 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013733 struct sk_buff *msg;
13734 void *hdr;
13735
13736 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
13737 if (!msg)
13738 return;
13739
13740 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
13741 if (!hdr) {
13742 nlmsg_free(msg);
13743 return;
13744 }
13745
13746 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13747 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
13748 nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
13749 goto nla_put_failure;
13750
13751 genlmsg_end(msg, hdr);
13752
Johannes Berg68eb5502013-11-19 15:19:38 +010013753 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013754 NL80211_MCGRP_MLME, gfp);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013755 return;
13756
13757 nla_put_failure:
13758 genlmsg_cancel(msg, hdr);
13759 nlmsg_free(msg);
13760}
Johannes Berg947add32013-02-22 22:05:20 +010013761EXPORT_SYMBOL(cfg80211_conn_failed);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013762
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013763static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
13764 const u8 *addr, gfp_t gfp)
Johannes Berg28946da2011-11-04 11:18:12 +010013765{
13766 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013767 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg28946da2011-11-04 11:18:12 +010013768 struct sk_buff *msg;
13769 void *hdr;
Eric W. Biederman15e47302012-09-07 20:12:54 +000013770 u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010013771
Eric W. Biederman15e47302012-09-07 20:12:54 +000013772 if (!nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010013773 return false;
13774
13775 msg = nlmsg_new(100, gfp);
13776 if (!msg)
13777 return true;
13778
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013779 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Johannes Berg28946da2011-11-04 11:18:12 +010013780 if (!hdr) {
13781 nlmsg_free(msg);
13782 return true;
13783 }
13784
David S. Miller9360ffd2012-03-29 04:41:26 -040013785 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13786 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13787 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
13788 goto nla_put_failure;
Johannes Berg28946da2011-11-04 11:18:12 +010013789
Johannes Berg9c90a9f2013-06-04 12:46:03 +020013790 genlmsg_end(msg, hdr);
Eric W. Biederman15e47302012-09-07 20:12:54 +000013791 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010013792 return true;
13793
13794 nla_put_failure:
13795 genlmsg_cancel(msg, hdr);
13796 nlmsg_free(msg);
13797 return true;
13798}
13799
Johannes Berg947add32013-02-22 22:05:20 +010013800bool cfg80211_rx_spurious_frame(struct net_device *dev,
13801 const u8 *addr, gfp_t gfp)
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013802{
Johannes Berg947add32013-02-22 22:05:20 +010013803 struct wireless_dev *wdev = dev->ieee80211_ptr;
13804 bool ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013805
Johannes Berg947add32013-02-22 22:05:20 +010013806 trace_cfg80211_rx_spurious_frame(dev, addr);
13807
13808 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
13809 wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
13810 trace_cfg80211_return_bool(false);
13811 return false;
13812 }
13813 ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
13814 addr, gfp);
13815 trace_cfg80211_return_bool(ret);
13816 return ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013817}
Johannes Berg947add32013-02-22 22:05:20 +010013818EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
13819
13820bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
13821 const u8 *addr, gfp_t gfp)
13822{
13823 struct wireless_dev *wdev = dev->ieee80211_ptr;
13824 bool ret;
13825
13826 trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
13827
13828 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
13829 wdev->iftype != NL80211_IFTYPE_P2P_GO &&
13830 wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
13831 trace_cfg80211_return_bool(false);
13832 return false;
13833 }
13834 ret = __nl80211_unexpected_frame(dev,
13835 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
13836 addr, gfp);
13837 trace_cfg80211_return_bool(ret);
13838 return ret;
13839}
13840EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013841
Johannes Berg2e161f782010-08-12 15:38:38 +020013842int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013843 struct wireless_dev *wdev, u32 nlportid,
Johannes Berg804483e2012-03-05 22:18:41 +010013844 int freq, int sig_dbm,
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030013845 const u8 *buf, size_t len, u32 flags, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020013846{
Johannes Berg71bbc992012-06-15 15:30:18 +020013847 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020013848 struct sk_buff *msg;
13849 void *hdr;
Jouni Malinen026331c2010-02-15 12:53:10 +020013850
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013851 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020013852 if (!msg)
13853 return -ENOMEM;
13854
Johannes Berg2e161f782010-08-12 15:38:38 +020013855 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
Jouni Malinen026331c2010-02-15 12:53:10 +020013856 if (!hdr) {
13857 nlmsg_free(msg);
13858 return -ENOMEM;
13859 }
13860
David S. Miller9360ffd2012-03-29 04:41:26 -040013861 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013862 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13863 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013864 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13865 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013866 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
13867 (sig_dbm &&
13868 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030013869 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
13870 (flags &&
13871 nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
David S. Miller9360ffd2012-03-29 04:41:26 -040013872 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020013873
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013874 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020013875
Eric W. Biederman15e47302012-09-07 20:12:54 +000013876 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Jouni Malinen026331c2010-02-15 12:53:10 +020013877
13878 nla_put_failure:
13879 genlmsg_cancel(msg, hdr);
13880 nlmsg_free(msg);
13881 return -ENOBUFS;
13882}
13883
Johannes Berg947add32013-02-22 22:05:20 +010013884void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
13885 const u8 *buf, size_t len, bool ack, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020013886{
Johannes Berg947add32013-02-22 22:05:20 +010013887 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013888 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg71bbc992012-06-15 15:30:18 +020013889 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020013890 struct sk_buff *msg;
13891 void *hdr;
13892
Johannes Berg947add32013-02-22 22:05:20 +010013893 trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
13894
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013895 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020013896 if (!msg)
13897 return;
13898
Johannes Berg2e161f782010-08-12 15:38:38 +020013899 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
Jouni Malinen026331c2010-02-15 12:53:10 +020013900 if (!hdr) {
13901 nlmsg_free(msg);
13902 return;
13903 }
13904
David S. Miller9360ffd2012-03-29 04:41:26 -040013905 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013906 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13907 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013908 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13909 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013910 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013911 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13912 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013913 (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
13914 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020013915
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013916 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020013917
Johannes Berg68eb5502013-11-19 15:19:38 +010013918 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013919 NL80211_MCGRP_MLME, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020013920 return;
13921
13922 nla_put_failure:
13923 genlmsg_cancel(msg, hdr);
13924 nlmsg_free(msg);
13925}
Johannes Berg947add32013-02-22 22:05:20 +010013926EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
Jouni Malinen026331c2010-02-15 12:53:10 +020013927
Johannes Berg5b97f492014-11-26 12:37:43 +010013928static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
13929 const char *mac, gfp_t gfp)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013930{
Johannes Berg947add32013-02-22 22:05:20 +010013931 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg5b97f492014-11-26 12:37:43 +010013932 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
13933 struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13934 void **cb;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013935
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013936 if (!msg)
Johannes Berg5b97f492014-11-26 12:37:43 +010013937 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013938
Johannes Berg5b97f492014-11-26 12:37:43 +010013939 cb = (void **)msg->cb;
13940
13941 cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
13942 if (!cb[0]) {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013943 nlmsg_free(msg);
Johannes Berg5b97f492014-11-26 12:37:43 +010013944 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013945 }
13946
David S. Miller9360ffd2012-03-29 04:41:26 -040013947 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010013948 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
David S. Miller9360ffd2012-03-29 04:41:26 -040013949 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013950
Johannes Berg5b97f492014-11-26 12:37:43 +010013951 if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013952 goto nla_put_failure;
13953
Johannes Berg5b97f492014-11-26 12:37:43 +010013954 cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM);
13955 if (!cb[1])
13956 goto nla_put_failure;
13957
13958 cb[2] = rdev;
13959
13960 return msg;
13961 nla_put_failure:
13962 nlmsg_free(msg);
13963 return NULL;
13964}
13965
13966static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
13967{
13968 void **cb = (void **)msg->cb;
13969 struct cfg80211_registered_device *rdev = cb[2];
13970
13971 nla_nest_end(msg, cb[1]);
13972 genlmsg_end(msg, cb[0]);
13973
13974 memset(msg->cb, 0, sizeof(msg->cb));
13975
13976 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
13977 NL80211_MCGRP_MLME, gfp);
13978}
13979
13980void cfg80211_cqm_rssi_notify(struct net_device *dev,
13981 enum nl80211_cqm_rssi_threshold_event rssi_event,
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010013982 s32 rssi_level, gfp_t gfp)
Johannes Berg5b97f492014-11-26 12:37:43 +010013983{
13984 struct sk_buff *msg;
13985
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010013986 trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
Johannes Berg5b97f492014-11-26 12:37:43 +010013987
Johannes Berg98f03342014-11-26 12:42:02 +010013988 if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
13989 rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
13990 return;
13991
Johannes Berg5b97f492014-11-26 12:37:43 +010013992 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
13993 if (!msg)
13994 return;
13995
David S. Miller9360ffd2012-03-29 04:41:26 -040013996 if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
13997 rssi_event))
13998 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013999
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014000 if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
14001 rssi_level))
14002 goto nla_put_failure;
14003
Johannes Berg5b97f492014-11-26 12:37:43 +010014004 cfg80211_send_cqm(msg, gfp);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014005
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014006 return;
14007
14008 nla_put_failure:
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014009 nlmsg_free(msg);
14010}
Johannes Berg947add32013-02-22 22:05:20 +010014011EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014012
Johannes Berg5b97f492014-11-26 12:37:43 +010014013void cfg80211_cqm_txe_notify(struct net_device *dev,
14014 const u8 *peer, u32 num_packets,
14015 u32 rate, u32 intvl, gfp_t gfp)
14016{
14017 struct sk_buff *msg;
14018
14019 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14020 if (!msg)
14021 return;
14022
14023 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
14024 goto nla_put_failure;
14025
14026 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
14027 goto nla_put_failure;
14028
14029 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
14030 goto nla_put_failure;
14031
14032 cfg80211_send_cqm(msg, gfp);
14033 return;
14034
14035 nla_put_failure:
14036 nlmsg_free(msg);
14037}
14038EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
14039
14040void cfg80211_cqm_pktloss_notify(struct net_device *dev,
14041 const u8 *peer, u32 num_packets, gfp_t gfp)
14042{
14043 struct sk_buff *msg;
14044
14045 trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
14046
14047 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14048 if (!msg)
14049 return;
14050
14051 if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
14052 goto nla_put_failure;
14053
14054 cfg80211_send_cqm(msg, gfp);
14055 return;
14056
14057 nla_put_failure:
14058 nlmsg_free(msg);
14059}
14060EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
14061
Johannes Berg98f03342014-11-26 12:42:02 +010014062void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
14063{
14064 struct sk_buff *msg;
14065
14066 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14067 if (!msg)
14068 return;
14069
14070 if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
14071 goto nla_put_failure;
14072
14073 cfg80211_send_cqm(msg, gfp);
14074 return;
14075
14076 nla_put_failure:
14077 nlmsg_free(msg);
14078}
14079EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
14080
Johannes Berg947add32013-02-22 22:05:20 +010014081static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
14082 struct net_device *netdev, const u8 *bssid,
14083 const u8 *replay_ctr, gfp_t gfp)
Johannes Berge5497d72011-07-05 16:35:40 +020014084{
14085 struct sk_buff *msg;
14086 struct nlattr *rekey_attr;
14087 void *hdr;
14088
Thomas Graf58050fc2012-06-28 03:57:45 +000014089 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014090 if (!msg)
14091 return;
14092
14093 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
14094 if (!hdr) {
14095 nlmsg_free(msg);
14096 return;
14097 }
14098
David S. Miller9360ffd2012-03-29 04:41:26 -040014099 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14100 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14101 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
14102 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014103
14104 rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
14105 if (!rekey_attr)
14106 goto nla_put_failure;
14107
David S. Miller9360ffd2012-03-29 04:41:26 -040014108 if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
14109 NL80211_REPLAY_CTR_LEN, replay_ctr))
14110 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014111
14112 nla_nest_end(msg, rekey_attr);
14113
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014114 genlmsg_end(msg, hdr);
Johannes Berge5497d72011-07-05 16:35:40 +020014115
Johannes Berg68eb5502013-11-19 15:19:38 +010014116 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014117 NL80211_MCGRP_MLME, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014118 return;
14119
14120 nla_put_failure:
14121 genlmsg_cancel(msg, hdr);
14122 nlmsg_free(msg);
14123}
14124
Johannes Berg947add32013-02-22 22:05:20 +010014125void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
14126 const u8 *replay_ctr, gfp_t gfp)
14127{
14128 struct wireless_dev *wdev = dev->ieee80211_ptr;
14129 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014130 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014131
14132 trace_cfg80211_gtk_rekey_notify(dev, bssid);
14133 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
14134}
14135EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
14136
14137static void
14138nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
14139 struct net_device *netdev, int index,
14140 const u8 *bssid, bool preauth, gfp_t gfp)
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014141{
14142 struct sk_buff *msg;
14143 struct nlattr *attr;
14144 void *hdr;
14145
Thomas Graf58050fc2012-06-28 03:57:45 +000014146 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014147 if (!msg)
14148 return;
14149
14150 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
14151 if (!hdr) {
14152 nlmsg_free(msg);
14153 return;
14154 }
14155
David S. Miller9360ffd2012-03-29 04:41:26 -040014156 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14157 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14158 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014159
14160 attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
14161 if (!attr)
14162 goto nla_put_failure;
14163
David S. Miller9360ffd2012-03-29 04:41:26 -040014164 if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
14165 nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
14166 (preauth &&
14167 nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
14168 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014169
14170 nla_nest_end(msg, attr);
14171
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014172 genlmsg_end(msg, hdr);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014173
Johannes Berg68eb5502013-11-19 15:19:38 +010014174 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014175 NL80211_MCGRP_MLME, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014176 return;
14177
14178 nla_put_failure:
14179 genlmsg_cancel(msg, hdr);
14180 nlmsg_free(msg);
14181}
14182
Johannes Berg947add32013-02-22 22:05:20 +010014183void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
14184 const u8 *bssid, bool preauth, gfp_t gfp)
14185{
14186 struct wireless_dev *wdev = dev->ieee80211_ptr;
14187 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014188 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014189
14190 trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
14191 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
14192}
14193EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
14194
14195static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
14196 struct net_device *netdev,
14197 struct cfg80211_chan_def *chandef,
Luciano Coelhof8d75522014-11-07 14:31:35 +020014198 gfp_t gfp,
14199 enum nl80211_commands notif,
14200 u8 count)
Thomas Pedersen53145262012-04-06 13:35:47 -070014201{
14202 struct sk_buff *msg;
14203 void *hdr;
14204
Thomas Graf58050fc2012-06-28 03:57:45 +000014205 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014206 if (!msg)
14207 return;
14208
Luciano Coelhof8d75522014-11-07 14:31:35 +020014209 hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
Thomas Pedersen53145262012-04-06 13:35:47 -070014210 if (!hdr) {
14211 nlmsg_free(msg);
14212 return;
14213 }
14214
Johannes Berg683b6d32012-11-08 21:25:48 +010014215 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14216 goto nla_put_failure;
14217
14218 if (nl80211_send_chandef(msg, chandef))
John W. Linville7eab0f62012-04-12 14:25:14 -040014219 goto nla_put_failure;
Thomas Pedersen53145262012-04-06 13:35:47 -070014220
Luciano Coelhof8d75522014-11-07 14:31:35 +020014221 if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
14222 (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
14223 goto nla_put_failure;
14224
Thomas Pedersen53145262012-04-06 13:35:47 -070014225 genlmsg_end(msg, hdr);
14226
Johannes Berg68eb5502013-11-19 15:19:38 +010014227 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014228 NL80211_MCGRP_MLME, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014229 return;
14230
14231 nla_put_failure:
14232 genlmsg_cancel(msg, hdr);
14233 nlmsg_free(msg);
14234}
14235
Johannes Berg947add32013-02-22 22:05:20 +010014236void cfg80211_ch_switch_notify(struct net_device *dev,
14237 struct cfg80211_chan_def *chandef)
Thomas Pedersen84f10702012-07-12 16:17:33 -070014238{
Johannes Berg947add32013-02-22 22:05:20 +010014239 struct wireless_dev *wdev = dev->ieee80211_ptr;
14240 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014241 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014242
Simon Wunderliche487eae2013-11-21 18:19:51 +010014243 ASSERT_WDEV_LOCK(wdev);
Johannes Berg947add32013-02-22 22:05:20 +010014244
Simon Wunderliche487eae2013-11-21 18:19:51 +010014245 trace_cfg80211_ch_switch_notify(dev, chandef);
Johannes Berg947add32013-02-22 22:05:20 +010014246
Michal Kazior9e0e2962014-01-29 14:22:27 +010014247 wdev->chandef = *chandef;
Janusz Dziedzic96f55f12014-01-24 14:29:21 +010014248 wdev->preset_chandef = *chandef;
Luciano Coelhof8d75522014-11-07 14:31:35 +020014249 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14250 NL80211_CMD_CH_SWITCH_NOTIFY, 0);
Johannes Berg947add32013-02-22 22:05:20 +010014251}
14252EXPORT_SYMBOL(cfg80211_ch_switch_notify);
14253
Luciano Coelhof8d75522014-11-07 14:31:35 +020014254void cfg80211_ch_switch_started_notify(struct net_device *dev,
14255 struct cfg80211_chan_def *chandef,
14256 u8 count)
14257{
14258 struct wireless_dev *wdev = dev->ieee80211_ptr;
14259 struct wiphy *wiphy = wdev->wiphy;
14260 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
14261
14262 trace_cfg80211_ch_switch_started_notify(dev, chandef);
14263
14264 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14265 NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
14266}
14267EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
14268
Thomas Pedersen84f10702012-07-12 16:17:33 -070014269void
Simon Wunderlich04f39042013-02-08 18:16:19 +010014270nl80211_radar_notify(struct cfg80211_registered_device *rdev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +010014271 const struct cfg80211_chan_def *chandef,
Simon Wunderlich04f39042013-02-08 18:16:19 +010014272 enum nl80211_radar_event event,
14273 struct net_device *netdev, gfp_t gfp)
14274{
14275 struct sk_buff *msg;
14276 void *hdr;
14277
14278 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14279 if (!msg)
14280 return;
14281
14282 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
14283 if (!hdr) {
14284 nlmsg_free(msg);
14285 return;
14286 }
14287
14288 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
14289 goto nla_put_failure;
14290
14291 /* NOP and radar events don't need a netdev parameter */
14292 if (netdev) {
14293 struct wireless_dev *wdev = netdev->ieee80211_ptr;
14294
14295 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014296 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14297 NL80211_ATTR_PAD))
Simon Wunderlich04f39042013-02-08 18:16:19 +010014298 goto nla_put_failure;
14299 }
14300
14301 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
14302 goto nla_put_failure;
14303
14304 if (nl80211_send_chandef(msg, chandef))
14305 goto nla_put_failure;
14306
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014307 genlmsg_end(msg, hdr);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014308
Johannes Berg68eb5502013-11-19 15:19:38 +010014309 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014310 NL80211_MCGRP_MLME, gfp);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014311 return;
14312
14313 nla_put_failure:
14314 genlmsg_cancel(msg, hdr);
14315 nlmsg_free(msg);
14316}
14317
Johannes Berg7f6cf312011-11-04 11:18:15 +010014318void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
14319 u64 cookie, bool acked, gfp_t gfp)
14320{
14321 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014322 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014323 struct sk_buff *msg;
14324 void *hdr;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014325
Beni Lev4ee3e062012-08-27 12:49:39 +030014326 trace_cfg80211_probe_status(dev, addr, cookie, acked);
14327
Thomas Graf58050fc2012-06-28 03:57:45 +000014328 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Beni Lev4ee3e062012-08-27 12:49:39 +030014329
Johannes Berg7f6cf312011-11-04 11:18:15 +010014330 if (!msg)
14331 return;
14332
14333 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
14334 if (!hdr) {
14335 nlmsg_free(msg);
14336 return;
14337 }
14338
David S. Miller9360ffd2012-03-29 04:41:26 -040014339 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14340 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14341 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014342 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14343 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014344 (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
14345 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014346
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014347 genlmsg_end(msg, hdr);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014348
Johannes Berg68eb5502013-11-19 15:19:38 +010014349 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014350 NL80211_MCGRP_MLME, gfp);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014351 return;
14352
14353 nla_put_failure:
14354 genlmsg_cancel(msg, hdr);
14355 nlmsg_free(msg);
14356}
14357EXPORT_SYMBOL(cfg80211_probe_status);
14358
Johannes Berg5e760232011-11-04 11:18:17 +010014359void cfg80211_report_obss_beacon(struct wiphy *wiphy,
14360 const u8 *frame, size_t len,
Ben Greear37c73b52012-10-26 14:49:25 -070014361 int freq, int sig_dbm)
Johannes Berg5e760232011-11-04 11:18:17 +010014362{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014363 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg5e760232011-11-04 11:18:17 +010014364 struct sk_buff *msg;
14365 void *hdr;
Ben Greear37c73b52012-10-26 14:49:25 -070014366 struct cfg80211_beacon_registration *reg;
Johannes Berg5e760232011-11-04 11:18:17 +010014367
Beni Lev4ee3e062012-08-27 12:49:39 +030014368 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
14369
Ben Greear37c73b52012-10-26 14:49:25 -070014370 spin_lock_bh(&rdev->beacon_registrations_lock);
14371 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
14372 msg = nlmsg_new(len + 100, GFP_ATOMIC);
14373 if (!msg) {
14374 spin_unlock_bh(&rdev->beacon_registrations_lock);
14375 return;
14376 }
Johannes Berg5e760232011-11-04 11:18:17 +010014377
Ben Greear37c73b52012-10-26 14:49:25 -070014378 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
14379 if (!hdr)
14380 goto nla_put_failure;
Johannes Berg5e760232011-11-04 11:18:17 +010014381
Ben Greear37c73b52012-10-26 14:49:25 -070014382 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14383 (freq &&
14384 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
14385 (sig_dbm &&
14386 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
14387 nla_put(msg, NL80211_ATTR_FRAME, len, frame))
14388 goto nla_put_failure;
14389
14390 genlmsg_end(msg, hdr);
14391
14392 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
Johannes Berg5e760232011-11-04 11:18:17 +010014393 }
Ben Greear37c73b52012-10-26 14:49:25 -070014394 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010014395 return;
14396
14397 nla_put_failure:
Ben Greear37c73b52012-10-26 14:49:25 -070014398 spin_unlock_bh(&rdev->beacon_registrations_lock);
14399 if (hdr)
14400 genlmsg_cancel(msg, hdr);
Johannes Berg5e760232011-11-04 11:18:17 +010014401 nlmsg_free(msg);
14402}
14403EXPORT_SYMBOL(cfg80211_report_obss_beacon);
14404
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014405#ifdef CONFIG_PM
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014406static int cfg80211_net_detect_results(struct sk_buff *msg,
14407 struct cfg80211_wowlan_wakeup *wakeup)
14408{
14409 struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
14410 struct nlattr *nl_results, *nl_match, *nl_freqs;
14411 int i, j;
14412
14413 nl_results = nla_nest_start(
14414 msg, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
14415 if (!nl_results)
14416 return -EMSGSIZE;
14417
14418 for (i = 0; i < nd->n_matches; i++) {
14419 struct cfg80211_wowlan_nd_match *match = nd->matches[i];
14420
14421 nl_match = nla_nest_start(msg, i);
14422 if (!nl_match)
14423 break;
14424
14425 /* The SSID attribute is optional in nl80211, but for
14426 * simplicity reasons it's always present in the
14427 * cfg80211 structure. If a driver can't pass the
14428 * SSID, that needs to be changed. A zero length SSID
14429 * is still a valid SSID (wildcard), so it cannot be
14430 * used for this purpose.
14431 */
14432 if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
14433 match->ssid.ssid)) {
14434 nla_nest_cancel(msg, nl_match);
14435 goto out;
14436 }
14437
14438 if (match->n_channels) {
14439 nl_freqs = nla_nest_start(
14440 msg, NL80211_ATTR_SCAN_FREQUENCIES);
14441 if (!nl_freqs) {
14442 nla_nest_cancel(msg, nl_match);
14443 goto out;
14444 }
14445
14446 for (j = 0; j < match->n_channels; j++) {
Samuel Tan5528fae82015-02-09 21:29:15 +020014447 if (nla_put_u32(msg, j, match->channels[j])) {
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014448 nla_nest_cancel(msg, nl_freqs);
14449 nla_nest_cancel(msg, nl_match);
14450 goto out;
14451 }
14452 }
14453
14454 nla_nest_end(msg, nl_freqs);
14455 }
14456
14457 nla_nest_end(msg, nl_match);
14458 }
14459
14460out:
14461 nla_nest_end(msg, nl_results);
14462 return 0;
14463}
14464
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014465void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
14466 struct cfg80211_wowlan_wakeup *wakeup,
14467 gfp_t gfp)
14468{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014469 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014470 struct sk_buff *msg;
14471 void *hdr;
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014472 int size = 200;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014473
14474 trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
14475
14476 if (wakeup)
14477 size += wakeup->packet_present_len;
14478
14479 msg = nlmsg_new(size, gfp);
14480 if (!msg)
14481 return;
14482
14483 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
14484 if (!hdr)
14485 goto free_msg;
14486
14487 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014488 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14489 NL80211_ATTR_PAD))
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014490 goto free_msg;
14491
14492 if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14493 wdev->netdev->ifindex))
14494 goto free_msg;
14495
14496 if (wakeup) {
14497 struct nlattr *reasons;
14498
14499 reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Berg7fa322c2013-10-25 11:16:58 +020014500 if (!reasons)
14501 goto free_msg;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014502
14503 if (wakeup->disconnect &&
14504 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
14505 goto free_msg;
14506 if (wakeup->magic_pkt &&
14507 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
14508 goto free_msg;
14509 if (wakeup->gtk_rekey_failure &&
14510 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
14511 goto free_msg;
14512 if (wakeup->eap_identity_req &&
14513 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
14514 goto free_msg;
14515 if (wakeup->four_way_handshake &&
14516 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
14517 goto free_msg;
14518 if (wakeup->rfkill_release &&
14519 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
14520 goto free_msg;
14521
14522 if (wakeup->pattern_idx >= 0 &&
14523 nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
14524 wakeup->pattern_idx))
14525 goto free_msg;
14526
Johannes Bergae917c92013-10-25 11:05:22 +020014527 if (wakeup->tcp_match &&
14528 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
14529 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014530
Johannes Bergae917c92013-10-25 11:05:22 +020014531 if (wakeup->tcp_connlost &&
14532 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
14533 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014534
Johannes Bergae917c92013-10-25 11:05:22 +020014535 if (wakeup->tcp_nomoretokens &&
14536 nla_put_flag(msg,
14537 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
14538 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014539
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014540 if (wakeup->packet) {
14541 u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
14542 u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
14543
14544 if (!wakeup->packet_80211) {
14545 pkt_attr =
14546 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
14547 len_attr =
14548 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
14549 }
14550
14551 if (wakeup->packet_len &&
14552 nla_put_u32(msg, len_attr, wakeup->packet_len))
14553 goto free_msg;
14554
14555 if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
14556 wakeup->packet))
14557 goto free_msg;
14558 }
14559
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014560 if (wakeup->net_detect &&
14561 cfg80211_net_detect_results(msg, wakeup))
14562 goto free_msg;
14563
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014564 nla_nest_end(msg, reasons);
14565 }
14566
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014567 genlmsg_end(msg, hdr);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014568
Johannes Berg68eb5502013-11-19 15:19:38 +010014569 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014570 NL80211_MCGRP_MLME, gfp);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014571 return;
14572
14573 free_msg:
14574 nlmsg_free(msg);
14575}
14576EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
14577#endif
14578
Jouni Malinen3475b092012-11-16 22:49:57 +020014579void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
14580 enum nl80211_tdls_operation oper,
14581 u16 reason_code, gfp_t gfp)
14582{
14583 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014584 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Jouni Malinen3475b092012-11-16 22:49:57 +020014585 struct sk_buff *msg;
14586 void *hdr;
Jouni Malinen3475b092012-11-16 22:49:57 +020014587
14588 trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
14589 reason_code);
14590
14591 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14592 if (!msg)
14593 return;
14594
14595 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
14596 if (!hdr) {
14597 nlmsg_free(msg);
14598 return;
14599 }
14600
14601 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14602 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14603 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
14604 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
14605 (reason_code > 0 &&
14606 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
14607 goto nla_put_failure;
14608
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014609 genlmsg_end(msg, hdr);
Jouni Malinen3475b092012-11-16 22:49:57 +020014610
Johannes Berg68eb5502013-11-19 15:19:38 +010014611 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014612 NL80211_MCGRP_MLME, gfp);
Jouni Malinen3475b092012-11-16 22:49:57 +020014613 return;
14614
14615 nla_put_failure:
14616 genlmsg_cancel(msg, hdr);
14617 nlmsg_free(msg);
14618}
14619EXPORT_SYMBOL(cfg80211_tdls_oper_request);
14620
Jouni Malinen026331c2010-02-15 12:53:10 +020014621static int nl80211_netlink_notify(struct notifier_block * nb,
14622 unsigned long state,
14623 void *_notify)
14624{
14625 struct netlink_notify *notify = _notify;
14626 struct cfg80211_registered_device *rdev;
14627 struct wireless_dev *wdev;
Ben Greear37c73b52012-10-26 14:49:25 -070014628 struct cfg80211_beacon_registration *reg, *tmp;
Jouni Malinen026331c2010-02-15 12:53:10 +020014629
Dmitry Ivanov8f815cd2016-04-06 17:23:18 +030014630 if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
Jouni Malinen026331c2010-02-15 12:53:10 +020014631 return NOTIFY_DONE;
14632
14633 rcu_read_lock();
14634
Johannes Berg5e760232011-11-04 11:18:17 +010014635 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
Johannes Berg78f22b62014-03-24 17:57:27 +010014636 bool schedule_destroy_work = false;
Jukka Rissanen93a1e862014-12-15 13:25:39 +020014637 struct cfg80211_sched_scan_request *sched_scan_req =
14638 rcu_dereference(rdev->sched_scan_req);
14639
14640 if (sched_scan_req && notify->portid &&
Johannes Berg753aacf2017-01-05 10:57:14 +010014641 sched_scan_req->owner_nlportid == notify->portid) {
14642 sched_scan_req->owner_nlportid = 0;
14643
14644 if (rdev->ops->sched_scan_stop &&
14645 rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
14646 schedule_work(&rdev->sched_scan_stop_wk);
14647 }
Johannes Berg78f22b62014-03-24 17:57:27 +010014648
Johannes Berg53873f12016-05-03 16:52:04 +030014649 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000014650 cfg80211_mlme_unregister_socket(wdev, notify->portid);
Ben Greear37c73b52012-10-26 14:49:25 -070014651
Johannes Berg78f22b62014-03-24 17:57:27 +010014652 if (wdev->owner_nlportid == notify->portid)
14653 schedule_destroy_work = true;
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050014654 else if (wdev->conn_owner_nlportid == notify->portid)
14655 schedule_work(&wdev->disconnect_wk);
Johannes Berg78f22b62014-03-24 17:57:27 +010014656 }
14657
Ben Greear37c73b52012-10-26 14:49:25 -070014658 spin_lock_bh(&rdev->beacon_registrations_lock);
14659 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
14660 list) {
14661 if (reg->nlportid == notify->portid) {
14662 list_del(&reg->list);
14663 kfree(reg);
14664 break;
14665 }
14666 }
14667 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg78f22b62014-03-24 17:57:27 +010014668
14669 if (schedule_destroy_work) {
14670 struct cfg80211_iface_destroy *destroy;
14671
14672 destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC);
14673 if (destroy) {
14674 destroy->nlportid = notify->portid;
14675 spin_lock(&rdev->destroy_list_lock);
14676 list_add(&destroy->list, &rdev->destroy_list);
14677 spin_unlock(&rdev->destroy_list_lock);
14678 schedule_work(&rdev->destroy_work);
14679 }
14680 }
Johannes Berg5e760232011-11-04 11:18:17 +010014681 }
Jouni Malinen026331c2010-02-15 12:53:10 +020014682
14683 rcu_read_unlock();
14684
Ilan peer05050752015-03-04 00:32:06 -050014685 /*
14686 * It is possible that the user space process that is controlling the
14687 * indoor setting disappeared, so notify the regulatory core.
14688 */
14689 regulatory_netlink_notify(notify->portid);
Zhao, Gang6784c7d2014-04-21 12:53:04 +080014690 return NOTIFY_OK;
Jouni Malinen026331c2010-02-15 12:53:10 +020014691}
14692
14693static struct notifier_block nl80211_netlink_notifier = {
14694 .notifier_call = nl80211_netlink_notify,
14695};
14696
Jouni Malinen355199e2013-02-27 17:14:27 +020014697void cfg80211_ft_event(struct net_device *netdev,
14698 struct cfg80211_ft_event_params *ft_event)
14699{
14700 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014701 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinen355199e2013-02-27 17:14:27 +020014702 struct sk_buff *msg;
14703 void *hdr;
Jouni Malinen355199e2013-02-27 17:14:27 +020014704
14705 trace_cfg80211_ft_event(wiphy, netdev, ft_event);
14706
14707 if (!ft_event->target_ap)
14708 return;
14709
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014710 msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
Jouni Malinen355199e2013-02-27 17:14:27 +020014711 if (!msg)
14712 return;
14713
14714 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
Johannes Bergae917c92013-10-25 11:05:22 +020014715 if (!hdr)
14716 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020014717
Johannes Bergae917c92013-10-25 11:05:22 +020014718 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14719 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14720 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
14721 goto out;
14722
14723 if (ft_event->ies &&
14724 nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
14725 goto out;
14726 if (ft_event->ric_ies &&
14727 nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
14728 ft_event->ric_ies))
14729 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020014730
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014731 genlmsg_end(msg, hdr);
Jouni Malinen355199e2013-02-27 17:14:27 +020014732
Johannes Berg68eb5502013-11-19 15:19:38 +010014733 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014734 NL80211_MCGRP_MLME, GFP_KERNEL);
Johannes Bergae917c92013-10-25 11:05:22 +020014735 return;
14736 out:
14737 nlmsg_free(msg);
Jouni Malinen355199e2013-02-27 17:14:27 +020014738}
14739EXPORT_SYMBOL(cfg80211_ft_event);
14740
Arend van Spriel5de17982013-04-18 15:49:00 +020014741void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
14742{
14743 struct cfg80211_registered_device *rdev;
14744 struct sk_buff *msg;
14745 void *hdr;
14746 u32 nlportid;
14747
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014748 rdev = wiphy_to_rdev(wdev->wiphy);
Arend van Spriel5de17982013-04-18 15:49:00 +020014749 if (!rdev->crit_proto_nlportid)
14750 return;
14751
14752 nlportid = rdev->crit_proto_nlportid;
14753 rdev->crit_proto_nlportid = 0;
14754
14755 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14756 if (!msg)
14757 return;
14758
14759 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
14760 if (!hdr)
14761 goto nla_put_failure;
14762
14763 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014764 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14765 NL80211_ATTR_PAD))
Arend van Spriel5de17982013-04-18 15:49:00 +020014766 goto nla_put_failure;
14767
14768 genlmsg_end(msg, hdr);
14769
14770 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
14771 return;
14772
14773 nla_put_failure:
14774 if (hdr)
14775 genlmsg_cancel(msg, hdr);
14776 nlmsg_free(msg);
Arend van Spriel5de17982013-04-18 15:49:00 +020014777}
14778EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
14779
Johannes Berg348baf02014-01-24 14:06:29 +010014780void nl80211_send_ap_stopped(struct wireless_dev *wdev)
14781{
14782 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014783 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg348baf02014-01-24 14:06:29 +010014784 struct sk_buff *msg;
14785 void *hdr;
14786
14787 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14788 if (!msg)
14789 return;
14790
14791 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
14792 if (!hdr)
14793 goto out;
14794
14795 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14796 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014797 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14798 NL80211_ATTR_PAD))
Johannes Berg348baf02014-01-24 14:06:29 +010014799 goto out;
14800
14801 genlmsg_end(msg, hdr);
14802
14803 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
14804 NL80211_MCGRP_MLME, GFP_KERNEL);
14805 return;
14806 out:
14807 nlmsg_free(msg);
14808}
14809
Johannes Berg55682962007-09-20 13:09:35 -040014810/* initialisation/exit functions */
14811
Johannes Berg56989f62016-10-24 14:40:05 +020014812int __init nl80211_init(void)
Johannes Berg55682962007-09-20 13:09:35 -040014813{
Michał Mirosław0d63cbb2009-05-21 10:34:06 +000014814 int err;
Johannes Berg55682962007-09-20 13:09:35 -040014815
Johannes Berg489111e2016-10-24 14:40:03 +020014816 err = genl_register_family(&nl80211_fam);
Johannes Berg55682962007-09-20 13:09:35 -040014817 if (err)
14818 return err;
14819
Jouni Malinen026331c2010-02-15 12:53:10 +020014820 err = netlink_register_notifier(&nl80211_netlink_notifier);
14821 if (err)
14822 goto err_out;
14823
Johannes Berg55682962007-09-20 13:09:35 -040014824 return 0;
14825 err_out:
14826 genl_unregister_family(&nl80211_fam);
14827 return err;
14828}
14829
14830void nl80211_exit(void)
14831{
Jouni Malinen026331c2010-02-15 12:53:10 +020014832 netlink_unregister_notifier(&nl80211_netlink_notifier);
Johannes Berg55682962007-09-20 13:09:35 -040014833 genl_unregister_family(&nl80211_fam);
14834}