blob: e6b916b49ef7b8804426932a300f440d1f703454 [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
Beni Lev0c9ca112016-02-17 20:30:00 +02006 * Copyright 2015-2016 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>
Dan Williams0781a502018-01-29 17:03:15 -080019#include <linux/nospec.h>
Johannes Berg2a519312009-02-10 21:25:55 +010020#include <linux/etherdevice.h>
Johannes Berg463d0182009-07-14 00:33:35 +020021#include <net/net_namespace.h>
Johannes Berg55682962007-09-20 13:09:35 -040022#include <net/genetlink.h>
23#include <net/cfg80211.h>
Johannes Berg463d0182009-07-14 00:33:35 +020024#include <net/sock.h>
Johannes Berg2a0e0472013-01-23 22:57:40 +010025#include <net/inet_connection_sock.h>
Johannes Berg55682962007-09-20 13:09:35 -040026#include "core.h"
27#include "nl80211.h"
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070028#include "reg.h"
Hila Gonene35e4d22012-06-27 17:19:42 +030029#include "rdev-ops.h"
Johannes Berg55682962007-09-20 13:09:35 -040030
Jouni Malinen5fb628e2011-08-10 23:54:35 +030031static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
32 struct genl_info *info,
33 struct cfg80211_crypto_settings *settings,
34 int cipher_limit);
35
Johannes Bergf84f7712013-11-14 17:14:45 +010036static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020037 struct genl_info *info);
Johannes Bergf84f7712013-11-14 17:14:45 +010038static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020039 struct genl_info *info);
40
Johannes Berg55682962007-09-20 13:09:35 -040041/* the netlink family */
42static struct genl_family nl80211_fam = {
Marcel Holtmannfb4e1562013-04-28 16:22:06 -070043 .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
44 .name = NL80211_GENL_NAME, /* have users key off the name instead */
45 .hdrsize = 0, /* no private header */
46 .version = 1, /* no particular meaning now */
Johannes Berg55682962007-09-20 13:09:35 -040047 .maxattr = NL80211_ATTR_MAX,
Johannes Berg463d0182009-07-14 00:33:35 +020048 .netnsok = true,
Johannes Berg4c476992010-10-04 21:36:35 +020049 .pre_doit = nl80211_pre_doit,
50 .post_doit = nl80211_post_doit,
Johannes Berg55682962007-09-20 13:09:35 -040051};
52
Johannes Berg2a94fe42013-11-19 15:19:39 +010053/* multicast groups */
54enum nl80211_multicast_groups {
55 NL80211_MCGRP_CONFIG,
56 NL80211_MCGRP_SCAN,
57 NL80211_MCGRP_REGULATORY,
58 NL80211_MCGRP_MLME,
Johannes Berg567ffc32013-12-18 14:43:31 +010059 NL80211_MCGRP_VENDOR,
Ayala Beker50bcd312016-09-20 17:31:17 +030060 NL80211_MCGRP_NAN,
Johannes Berg2a94fe42013-11-19 15:19:39 +010061 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
62};
63
64static const struct genl_multicast_group nl80211_mcgrps[] = {
Johannes Berg71b836e2014-12-23 17:17:38 +010065 [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG },
66 [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN },
67 [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG },
68 [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME },
69 [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
Ayala Beker50bcd312016-09-20 17:31:17 +030070 [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN },
Johannes Berg2a94fe42013-11-19 15:19:39 +010071#ifdef CONFIG_NL80211_TESTMODE
Johannes Berg71b836e2014-12-23 17:17:38 +010072 [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
Johannes Berg2a94fe42013-11-19 15:19:39 +010073#endif
74};
75
Johannes Berg89a54e42012-06-15 14:33:17 +020076/* returns ERR_PTR values */
77static struct wireless_dev *
78__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berg55682962007-09-20 13:09:35 -040079{
Johannes Berg89a54e42012-06-15 14:33:17 +020080 struct cfg80211_registered_device *rdev;
81 struct wireless_dev *result = NULL;
82 bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
83 bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
84 u64 wdev_id;
85 int wiphy_idx = -1;
86 int ifidx = -1;
Johannes Berg55682962007-09-20 13:09:35 -040087
Johannes Berg5fe231e2013-05-08 21:45:15 +020088 ASSERT_RTNL();
Johannes Berg55682962007-09-20 13:09:35 -040089
Johannes Berg89a54e42012-06-15 14:33:17 +020090 if (!have_ifidx && !have_wdev_id)
91 return ERR_PTR(-EINVAL);
Johannes Berg55682962007-09-20 13:09:35 -040092
Johannes Berg89a54e42012-06-15 14:33:17 +020093 if (have_ifidx)
94 ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
95 if (have_wdev_id) {
96 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
97 wiphy_idx = wdev_id >> 32;
Johannes Berg55682962007-09-20 13:09:35 -040098 }
99
Johannes Berg89a54e42012-06-15 14:33:17 +0200100 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
101 struct wireless_dev *wdev;
102
103 if (wiphy_net(&rdev->wiphy) != netns)
104 continue;
105
106 if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
107 continue;
108
Johannes Berg53873f12016-05-03 16:52:04 +0300109 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +0200110 if (have_ifidx && wdev->netdev &&
111 wdev->netdev->ifindex == ifidx) {
112 result = wdev;
113 break;
114 }
115 if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
116 result = wdev;
117 break;
118 }
119 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200120
121 if (result)
122 break;
123 }
124
125 if (result)
126 return result;
127 return ERR_PTR(-ENODEV);
Johannes Berg55682962007-09-20 13:09:35 -0400128}
129
Johannes Berga9455402012-06-15 13:32:49 +0200130static struct cfg80211_registered_device *
Johannes Berg878d9ec2012-06-15 14:18:32 +0200131__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berga9455402012-06-15 13:32:49 +0200132{
Johannes Berg7fee4772012-06-15 14:09:58 +0200133 struct cfg80211_registered_device *rdev = NULL, *tmp;
134 struct net_device *netdev;
Johannes Berga9455402012-06-15 13:32:49 +0200135
Johannes Berg5fe231e2013-05-08 21:45:15 +0200136 ASSERT_RTNL();
Johannes Berga9455402012-06-15 13:32:49 +0200137
Johannes Berg878d9ec2012-06-15 14:18:32 +0200138 if (!attrs[NL80211_ATTR_WIPHY] &&
Johannes Berg89a54e42012-06-15 14:33:17 +0200139 !attrs[NL80211_ATTR_IFINDEX] &&
140 !attrs[NL80211_ATTR_WDEV])
Johannes Berg7fee4772012-06-15 14:09:58 +0200141 return ERR_PTR(-EINVAL);
142
Johannes Berg878d9ec2012-06-15 14:18:32 +0200143 if (attrs[NL80211_ATTR_WIPHY])
Johannes Berg7fee4772012-06-15 14:09:58 +0200144 rdev = cfg80211_rdev_by_wiphy_idx(
Johannes Berg878d9ec2012-06-15 14:18:32 +0200145 nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
Johannes Berga9455402012-06-15 13:32:49 +0200146
Johannes Berg89a54e42012-06-15 14:33:17 +0200147 if (attrs[NL80211_ATTR_WDEV]) {
148 u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
149 struct wireless_dev *wdev;
150 bool found = false;
151
152 tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
153 if (tmp) {
154 /* make sure wdev exists */
Johannes Berg53873f12016-05-03 16:52:04 +0300155 list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +0200156 if (wdev->identifier != (u32)wdev_id)
157 continue;
158 found = true;
159 break;
160 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200161
162 if (!found)
163 tmp = NULL;
164
165 if (rdev && tmp != rdev)
166 return ERR_PTR(-EINVAL);
167 rdev = tmp;
168 }
169 }
170
Johannes Berg878d9ec2012-06-15 14:18:32 +0200171 if (attrs[NL80211_ATTR_IFINDEX]) {
172 int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700173
Ying Xue7f2b8562014-01-15 10:23:45 +0800174 netdev = __dev_get_by_index(netns, ifindex);
Johannes Berg7fee4772012-06-15 14:09:58 +0200175 if (netdev) {
176 if (netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800177 tmp = wiphy_to_rdev(
178 netdev->ieee80211_ptr->wiphy);
Johannes Berg7fee4772012-06-15 14:09:58 +0200179 else
180 tmp = NULL;
181
Johannes Berg7fee4772012-06-15 14:09:58 +0200182 /* not wireless device -- return error */
183 if (!tmp)
184 return ERR_PTR(-EINVAL);
185
186 /* mismatch -- return error */
187 if (rdev && tmp != rdev)
188 return ERR_PTR(-EINVAL);
189
190 rdev = tmp;
Johannes Berga9455402012-06-15 13:32:49 +0200191 }
Johannes Berga9455402012-06-15 13:32:49 +0200192 }
193
Johannes Berg4f7eff12012-06-15 14:14:22 +0200194 if (!rdev)
195 return ERR_PTR(-ENODEV);
Johannes Berga9455402012-06-15 13:32:49 +0200196
Johannes Berg4f7eff12012-06-15 14:14:22 +0200197 if (netns != wiphy_net(&rdev->wiphy))
198 return ERR_PTR(-ENODEV);
199
200 return rdev;
Johannes Berga9455402012-06-15 13:32:49 +0200201}
202
203/*
204 * This function returns a pointer to the driver
205 * that the genl_info item that is passed refers to.
Johannes Berga9455402012-06-15 13:32:49 +0200206 *
207 * The result of this can be a PTR_ERR and hence must
208 * be checked with IS_ERR() for errors.
209 */
210static struct cfg80211_registered_device *
Johannes Berg4f7eff12012-06-15 14:14:22 +0200211cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
Johannes Berga9455402012-06-15 13:32:49 +0200212{
Johannes Berg5fe231e2013-05-08 21:45:15 +0200213 return __cfg80211_rdev_from_attrs(netns, info->attrs);
Johannes Berga9455402012-06-15 13:32:49 +0200214}
215
Johannes Berg55682962007-09-20 13:09:35 -0400216/* policy for the attributes */
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300217static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
Johannes Berg55682962007-09-20 13:09:35 -0400218 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
219 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
David S. Miller079e24e2009-05-26 21:15:00 -0700220 .len = 20-1 },
Jouni Malinen31888482008-10-30 16:59:24 +0200221 [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100222
Jouni Malinen72bdcf32008-11-26 16:15:24 +0200223 [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
Sujith094d05d2008-12-12 11:57:43 +0530224 [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100225 [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
226 [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
227 [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
228
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200229 [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
230 [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
231 [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
232 [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
Lukáš Turek81077e82009-12-21 22:50:47 +0100233 [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +0200234 [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG },
Johannes Berg55682962007-09-20 13:09:35 -0400235
236 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
237 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
238 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
Johannes Berg41ade002007-12-19 02:03:29 +0100239
Eliad Pellere007b852011-11-24 18:13:56 +0200240 [NL80211_ATTR_MAC] = { .len = ETH_ALEN },
241 [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN },
Johannes Berg41ade002007-12-19 02:03:29 +0100242
Johannes Bergb9454e82009-07-08 13:29:08 +0200243 [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
Johannes Berg41ade002007-12-19 02:03:29 +0100244 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
245 .len = WLAN_MAX_KEY_LEN },
246 [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
247 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
248 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
Jouni Malinen81962262011-11-02 23:36:31 +0200249 [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Berge31b8212010-10-05 19:39:30 +0200250 [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
Johannes Berged1b6cc2007-12-19 02:03:32 +0100251
252 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
253 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
254 [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
255 .len = IEEE80211_MAX_DATA_LEN },
256 [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
257 .len = IEEE80211_MAX_DATA_LEN },
Johannes Berg5727ef12007-12-19 02:03:34 +0100258 [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
259 [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
260 [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
261 [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
262 .len = NL80211_MAX_SUPP_RATES },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100263 [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
Johannes Berg5727ef12007-12-19 02:03:34 +0100264 [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
Johannes Berg0a9542e2008-10-15 11:54:04 +0200265 [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100266 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +0800267 .len = IEEE80211_MAX_MESH_ID_LEN },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100268 [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300269
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700270 [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
271 [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
272
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300273 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
274 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
275 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
Jouni Malinen90c97a02008-10-30 16:59:22 +0200276 [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
277 .len = NL80211_MAX_SUPP_RATES },
Helmut Schaa50b12f52010-11-19 12:40:25 +0100278 [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },
Jouni Malinen36aedc902008-08-25 11:58:58 +0300279
Javier Cardona24bdd9f2010-12-16 17:37:48 -0800280 [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
Javier Cardona15d5dda2011-04-07 15:08:28 -0700281 [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -0700282
Johannes Berg6c739412011-11-03 09:27:01 +0100283 [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +0200284
285 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
286 [NL80211_ATTR_IE] = { .type = NLA_BINARY,
287 .len = IEEE80211_MAX_DATA_LEN },
Johannes Berg2a519312009-02-10 21:25:55 +0100288 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
289 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
Jouni Malinen636a5d32009-03-19 13:39:22 +0200290
291 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
292 .len = IEEE80211_MAX_SSID_LEN },
293 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
294 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
Johannes Berg04a773a2009-04-19 21:24:32 +0200295 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
Jouni Malinen1965c852009-04-22 21:38:25 +0300296 [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
Jouni Malinendc6382c2009-05-06 22:09:37 +0300297 [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 },
Johannes Bergeccb8e82009-05-11 21:57:56 +0300298 [NL80211_ATTR_STA_FLAGS2] = {
299 .len = sizeof(struct nl80211_sta_flag_update),
300 },
Jouni Malinen3f77316c2009-05-11 21:57:57 +0300301 [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
Johannes Bergc0692b82010-08-27 14:26:53 +0300302 [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
303 [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
Samuel Ortizb23aa672009-07-01 21:26:54 +0200304 [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
305 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
306 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
Johannes Berg463d0182009-07-14 00:33:35 +0200307 [NL80211_ATTR_PID] = { .type = NLA_U32 },
Felix Fietkau8b787642009-11-10 18:53:10 +0100308 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
Srinivas Dasari7e9e9632017-07-07 01:43:39 +0300309 [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN },
Jouni Malinen9588bbd2009-12-23 13:15:41 +0100310 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
311 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +0200312 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
Jouni Malinen026331c2010-02-15 12:53:10 +0200313 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
314 .len = IEEE80211_MAX_DATA_LEN },
315 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
Kalle Valoffb9eb32010-02-17 17:58:10 +0200316 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +0200317 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
Jouni Malinend5cdfac2010-04-04 09:37:19 +0300318 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +0200319 [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +0300320 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
321 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
Johannes Berg2e161f72010-08-12 15:38:38 +0200322 [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
Bruno Randolfafe0cbf2010-11-10 12:50:50 +0900323 [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
324 [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
Felix Fietkau885a46d2010-11-11 15:07:22 +0100325 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
Johannes Bergf7ca38d2010-11-25 10:02:29 +0100326 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100327 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200328 [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
Javier Cardona9c3990a2011-05-03 16:57:11 -0700329 [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
Luciano Coelhobbe6ad62011-05-11 17:09:37 +0300330 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
Johannes Berge5497d72011-07-05 16:35:40 +0200331 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
Johannes Berg34850ab2011-07-18 18:08:35 +0200332 [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
Jouni Malinen32e9de82011-08-10 23:53:31 +0300333 [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
Jouni Malinen9946ecf2011-08-10 23:55:56 +0300334 [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
335 .len = IEEE80211_MAX_DATA_LEN },
336 [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
337 .len = IEEE80211_MAX_DATA_LEN },
Vivek Natarajanf4b34b52011-08-29 14:23:03 +0530338 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300339 [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +0530340 [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
Arik Nemtsov109086c2011-09-28 14:12:50 +0300341 [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
342 [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
343 [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
344 [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
345 [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
Arik Nemtsov31fa97c2014-06-11 17:18:21 +0300346 [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
Johannes Berge247bd902011-11-04 11:18:21 +0100347 [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
Arik Nemtsov00f740e2011-11-10 11:28:56 +0200348 [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
349 .len = IEEE80211_MAX_DATA_LEN },
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -0700350 [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
Ben Greear7e7c8922011-11-18 11:31:59 -0800351 [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
352 [NL80211_ATTR_HT_CAPABILITY_MASK] = {
353 .len = NL80211_HT_CAPABILITY_LEN
354 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +0100355 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +0530356 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
Bala Shanmugam4486ea92012-03-07 17:27:12 +0530357 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
Johannes Berg89a54e42012-06-15 14:33:17 +0200358 [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -0700359 [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
Jouni Malinen3255b4a2016-10-27 00:41:58 +0300360 [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +0000361 [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
Sam Lefflered4737712012-10-11 21:03:31 -0700362 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
Johannes Berg53cabad2012-11-14 15:17:28 +0100363 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
364 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
Srinivas Dasarib68aa7d2017-07-07 01:43:41 +0300365 [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +0530366 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
367 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
Jouni Malinen9d62a982013-02-14 21:10:13 +0200368 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
369 [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
Johannes Berg3713b4e2013-02-14 16:19:38 +0100370 [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
Johannes Bergee2aca32013-02-21 17:36:01 +0100371 [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
372 [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
373 .len = NL80211_VHT_CAPABILITY_LEN,
374 },
Jouni Malinen355199e2013-02-27 17:14:27 +0200375 [NL80211_ATTR_MDID] = { .type = NLA_U16 },
376 [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
377 .len = IEEE80211_MAX_DATA_LEN },
Jouni Malinen5e4b6f52013-05-16 20:11:08 +0300378 [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +0200379 [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
380 [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
381 [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +0300382 [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY },
383 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY },
Sunil Duttc01fc9a2013-10-09 20:45:21 +0530384 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
385 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
Simon Wunderlich5336fa82013-10-07 18:41:05 +0200386 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +0100387 [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
Johannes Bergad7e7182013-11-13 13:37:47 +0100388 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
389 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
390 [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -0800391 [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
392 .len = IEEE80211_QOS_MAP_LEN_MAX },
Jouni Malinen1df4a512014-01-15 00:00:47 +0200393 [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
394 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +0530395 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
Jukka Rissanen18e5ca62014-11-13 17:25:14 +0200396 [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +0300397 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
Assaf Kraussbab5ab72014-09-03 15:25:01 +0300398 [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
Johannes Berg960d01a2014-09-09 22:55:35 +0300399 [NL80211_ATTR_TSID] = { .type = NLA_U8 },
400 [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
401 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
Eliad Peller18998c32014-09-10 14:07:34 +0300402 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
Johannes Bergad2b26a2014-06-12 21:39:05 +0200403 [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
Arik Nemtsov1bdd7162014-12-15 19:26:01 +0200404 [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
Vadim Kochan4b681c82015-01-12 16:34:05 +0200405 [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
Luciano Coelho9c748932015-01-16 16:04:09 +0200406 [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
Ilan peer05050752015-03-04 00:32:06 -0500407 [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
Lior David34d50512016-01-28 10:58:25 +0200408 [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
Arend van Spriel38de03d2016-03-02 20:37:18 +0100409 [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
Ayala Beker17b94242016-03-17 15:41:38 +0200410 [NL80211_ATTR_STA_SUPPORT_P2P_PS] = { .type = NLA_U8 },
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +0300411 [NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
412 .len = VHT_MUMIMO_GROUPS_DATA_LEN
413 },
414 [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN },
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300415 [NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
416 [NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 },
Ayala Bekera442b762016-09-20 17:31:15 +0300417 [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
Jouni Malinenc9a63622016-10-27 00:42:03 +0300418 [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
419 .len = FILS_MAX_KEK_LEN },
420 [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
Michael Braund757efc2016-10-10 19:12:22 +0200421 [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
Vamsi Krishna45816392016-12-02 23:59:08 +0200422 [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
vamsi krishnaf4f1a542017-01-13 01:12:20 +0200423 [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
424 [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
425 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
426 },
Purushottam Kushwahadf935062017-01-13 01:12:21 +0200427 [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
Vidyullatha Kanchanapally36eabf62017-03-31 00:22:34 +0300428 [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
429 .len = FILS_ERP_MAX_USERNAME_LEN },
430 [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
431 .len = FILS_ERP_MAX_REALM_LEN },
432 [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
433 [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
434 .len = FILS_ERP_MAX_RRK_LEN },
435 [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
436 [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
Johannes Berg55682962007-09-20 13:09:35 -0400437};
438
Johannes Berge31b8212010-10-05 19:39:30 +0200439/* policy for the key attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000440static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
Johannes Bergfffd0932009-07-08 14:22:54 +0200441 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
Johannes Bergb9454e82009-07-08 13:29:08 +0200442 [NL80211_KEY_IDX] = { .type = NLA_U8 },
443 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
Jouni Malinen81962262011-11-02 23:36:31 +0200444 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergb9454e82009-07-08 13:29:08 +0200445 [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
446 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
Johannes Berge31b8212010-10-05 19:39:30 +0200447 [NL80211_KEY_TYPE] = { .type = NLA_U32 },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100448 [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
449};
450
451/* policy for the key default flags */
452static const struct nla_policy
453nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
454 [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
455 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
Johannes Bergb9454e82009-07-08 13:29:08 +0200456};
457
Johannes Bergff1b6e62011-05-04 15:37:28 +0200458/* policy for WoWLAN attributes */
459static const struct nla_policy
460nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
461 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
462 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
463 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
464 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
Johannes Berg77dbbb12011-07-13 10:48:55 +0200465 [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
466 [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
467 [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
468 [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100469 [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300470 [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100471};
472
473static const struct nla_policy
474nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
475 [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
476 [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
477 [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN },
478 [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
479 [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
480 [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 },
481 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
482 .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
483 },
484 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
485 .len = sizeof(struct nl80211_wowlan_tcp_data_token)
486 },
487 [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
488 [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
489 [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200490};
491
Amitkumar Karwarbe29b992013-06-28 11:51:26 -0700492/* policy for coalesce rule attributes */
493static const struct nla_policy
494nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
495 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
496 [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
497 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
498};
499
Johannes Berge5497d72011-07-05 16:35:40 +0200500/* policy for GTK rekey offload attributes */
501static const struct nla_policy
502nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
Vidyullatha Kanchanapally84aa3ba2017-05-25 20:20:41 +0530503 [NL80211_REKEY_DATA_KEK] = { .type = NLA_BINARY,
504 .len = FILS_MAX_KEK_LEN },
Johannes Berge5497d72011-07-05 16:35:40 +0200505 [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
506 [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
507};
508
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300509static const struct nla_policy
510nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
Johannes Berg4a4ab0d2012-06-13 11:17:11 +0200511 [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300512 .len = IEEE80211_MAX_SSID_LEN },
Thomas Pedersen88e920b2012-06-21 11:09:54 -0700513 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300514};
515
Avraham Stern3b06d272015-10-12 09:51:34 +0300516static const struct nla_policy
517nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
518 [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
519 [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
520};
521
Arend van Spriel38de03d2016-03-02 20:37:18 +0100522static const struct nla_policy
523nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
524 [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
525 [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
526 [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
527 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
528 },
529};
530
Ayala Bekera442b762016-09-20 17:31:15 +0300531/* policy for NAN function attributes */
532static const struct nla_policy
533nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
534 [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
Srinivas Dasari6a90f812017-07-07 01:43:40 +0300535 [NL80211_NAN_FUNC_SERVICE_ID] = {
Ayala Bekera442b762016-09-20 17:31:15 +0300536 .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
537 [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
538 [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
539 [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
540 [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
541 [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
542 [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { .len = ETH_ALEN },
543 [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
544 [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
545 [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
546 .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
547 [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
548 [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
549 [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
550 [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
551 [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
552};
553
554/* policy for Service Response Filter attributes */
555static const struct nla_policy
556nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
557 [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
558 [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
559 .len = NL80211_NAN_FUNC_SRF_MAX_LEN },
560 [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
561 [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
562};
563
Peng Xu4ec90fd2017-10-10 13:56:53 -0700564/* policy for packet pattern attributes */
565static const struct nla_policy
566nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
567 [NL80211_PKTPAT_MASK] = { .type = NLA_BINARY, },
568 [NL80211_PKTPAT_PATTERN] = { .type = NLA_BINARY, },
569 [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
570};
571
Johannes Berg97990a02013-04-19 01:02:55 +0200572static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
573 struct netlink_callback *cb,
574 struct cfg80211_registered_device **rdev,
575 struct wireless_dev **wdev)
Holger Schuriga0438972009-11-11 11:30:02 +0100576{
Johannes Berg67748892010-10-04 21:14:06 +0200577 int err;
578
Johannes Berg97990a02013-04-19 01:02:55 +0200579 if (!cb->args[0]) {
580 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
581 nl80211_fam.attrbuf, nl80211_fam.maxattr,
582 nl80211_policy);
583 if (err)
Johannes Berg56769e72017-03-15 14:26:04 +0100584 return err;
Johannes Berg97990a02013-04-19 01:02:55 +0200585
586 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
587 nl80211_fam.attrbuf);
Johannes Berg56769e72017-03-15 14:26:04 +0100588 if (IS_ERR(*wdev))
589 return PTR_ERR(*wdev);
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800590 *rdev = wiphy_to_rdev((*wdev)->wiphy);
Johannes Bergc319d502013-07-30 22:34:28 +0200591 /* 0 is the first index - add 1 to parse only once */
592 cb->args[0] = (*rdev)->wiphy_idx + 1;
Johannes Berg97990a02013-04-19 01:02:55 +0200593 cb->args[1] = (*wdev)->identifier;
594 } else {
Johannes Bergc319d502013-07-30 22:34:28 +0200595 /* subtract the 1 again here */
596 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
Johannes Berg97990a02013-04-19 01:02:55 +0200597 struct wireless_dev *tmp;
598
Johannes Berg56769e72017-03-15 14:26:04 +0100599 if (!wiphy)
600 return -ENODEV;
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800601 *rdev = wiphy_to_rdev(wiphy);
Johannes Berg97990a02013-04-19 01:02:55 +0200602 *wdev = NULL;
603
Johannes Berg53873f12016-05-03 16:52:04 +0300604 list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
Johannes Berg97990a02013-04-19 01:02:55 +0200605 if (tmp->identifier == cb->args[1]) {
606 *wdev = tmp;
607 break;
608 }
609 }
Johannes Berg97990a02013-04-19 01:02:55 +0200610
Johannes Berg56769e72017-03-15 14:26:04 +0100611 if (!*wdev)
612 return -ENODEV;
Johannes Berg67748892010-10-04 21:14:06 +0200613 }
614
Johannes Berg67748892010-10-04 21:14:06 +0200615 return 0;
Johannes Berg67748892010-10-04 21:14:06 +0200616}
617
Johannes Bergf4a11bb2009-03-27 12:40:28 +0100618/* IE validation */
619static bool is_valid_ie_attr(const struct nlattr *attr)
620{
621 const u8 *pos;
622 int len;
623
624 if (!attr)
625 return true;
626
627 pos = nla_data(attr);
628 len = nla_len(attr);
629
630 while (len) {
631 u8 elemlen;
632
633 if (len < 2)
634 return false;
635 len -= 2;
636
637 elemlen = pos[1];
638 if (elemlen > len)
639 return false;
640
641 len -= elemlen;
642 pos += 2 + elemlen;
643 }
644
645 return true;
646}
647
Johannes Berg55682962007-09-20 13:09:35 -0400648/* message building helper */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000649static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
Johannes Berg55682962007-09-20 13:09:35 -0400650 int flags, u8 cmd)
651{
652 /* since there is no private header just add the generic one */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000653 return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -0400654}
655
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400656static int nl80211_msg_put_channel(struct sk_buff *msg,
Johannes Bergcdc89b92013-02-18 23:54:36 +0100657 struct ieee80211_channel *chan,
658 bool large)
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400659{
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200660 /* Some channels must be completely excluded from the
661 * list to protect old user-space tools from breaking
662 */
663 if (!large && chan->flags &
664 (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
665 return 0;
666
David S. Miller9360ffd2012-03-29 04:41:26 -0400667 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
668 chan->center_freq))
669 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400670
David S. Miller9360ffd2012-03-29 04:41:26 -0400671 if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
672 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
673 goto nla_put_failure;
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200674 if (chan->flags & IEEE80211_CHAN_NO_IR) {
675 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
676 goto nla_put_failure;
677 if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
678 goto nla_put_failure;
679 }
Johannes Bergcdc89b92013-02-18 23:54:36 +0100680 if (chan->flags & IEEE80211_CHAN_RADAR) {
681 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
682 goto nla_put_failure;
683 if (large) {
684 u32 time;
685
686 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
687
688 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
689 chan->dfs_state))
690 goto nla_put_failure;
691 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
692 time))
693 goto nla_put_failure;
Janusz Dziedzic089027e2014-02-21 19:46:12 +0100694 if (nla_put_u32(msg,
695 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
696 chan->dfs_cac_ms))
697 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +0100698 }
699 }
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400700
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100701 if (large) {
702 if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
703 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
704 goto nla_put_failure;
705 if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
706 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
707 goto nla_put_failure;
708 if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
709 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
710 goto nla_put_failure;
711 if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
712 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
713 goto nla_put_failure;
David Spinadel570dbde2014-02-23 09:12:59 +0200714 if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
715 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
716 goto nla_put_failure;
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300717 if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
718 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
David Spinadel570dbde2014-02-23 09:12:59 +0200719 goto nla_put_failure;
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200720 if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
721 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
722 goto nla_put_failure;
723 if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
724 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
725 goto nla_put_failure;
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100726 }
727
David S. Miller9360ffd2012-03-29 04:41:26 -0400728 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
729 DBM_TO_MBM(chan->max_power)))
730 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400731
732 return 0;
733
734 nla_put_failure:
735 return -ENOBUFS;
736}
737
Johannes Berg55682962007-09-20 13:09:35 -0400738/* netlink command implementations */
739
Johannes Bergb9454e82009-07-08 13:29:08 +0200740struct key_parse {
741 struct key_params p;
742 int idx;
Johannes Berge31b8212010-10-05 19:39:30 +0200743 int type;
Johannes Bergb9454e82009-07-08 13:29:08 +0200744 bool def, defmgmt;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100745 bool def_uni, def_multi;
Johannes Bergb9454e82009-07-08 13:29:08 +0200746};
747
748static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
749{
750 struct nlattr *tb[NL80211_KEY_MAX + 1];
751 int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
752 nl80211_key_policy);
753 if (err)
754 return err;
755
756 k->def = !!tb[NL80211_KEY_DEFAULT];
757 k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
758
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100759 if (k->def) {
760 k->def_uni = true;
761 k->def_multi = true;
762 }
763 if (k->defmgmt)
764 k->def_multi = true;
765
Johannes Bergb9454e82009-07-08 13:29:08 +0200766 if (tb[NL80211_KEY_IDX])
767 k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
768
769 if (tb[NL80211_KEY_DATA]) {
770 k->p.key = nla_data(tb[NL80211_KEY_DATA]);
771 k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
772 }
773
774 if (tb[NL80211_KEY_SEQ]) {
775 k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
776 k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
777 }
778
779 if (tb[NL80211_KEY_CIPHER])
780 k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
781
Johannes Berge31b8212010-10-05 19:39:30 +0200782 if (tb[NL80211_KEY_TYPE]) {
783 k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
784 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
785 return -EINVAL;
786 }
787
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100788 if (tb[NL80211_KEY_DEFAULT_TYPES]) {
789 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700790
Johannes Berg2da8f412012-01-20 13:52:37 +0100791 err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
792 tb[NL80211_KEY_DEFAULT_TYPES],
793 nl80211_key_default_policy);
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100794 if (err)
795 return err;
796
797 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
798 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
799 }
800
Johannes Bergb9454e82009-07-08 13:29:08 +0200801 return 0;
802}
803
804static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
805{
806 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
807 k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
808 k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
809 }
810
811 if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
812 k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
813 k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
814 }
815
816 if (info->attrs[NL80211_ATTR_KEY_IDX])
817 k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
818
819 if (info->attrs[NL80211_ATTR_KEY_CIPHER])
820 k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
821
822 k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
823 k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
824
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100825 if (k->def) {
826 k->def_uni = true;
827 k->def_multi = true;
828 }
829 if (k->defmgmt)
830 k->def_multi = true;
831
Johannes Berge31b8212010-10-05 19:39:30 +0200832 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
833 k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
834 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
835 return -EINVAL;
836 }
837
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100838 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
839 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
840 int err = nla_parse_nested(
841 kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
842 info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
843 nl80211_key_default_policy);
844 if (err)
845 return err;
846
847 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
848 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
849 }
850
Johannes Bergb9454e82009-07-08 13:29:08 +0200851 return 0;
852}
853
854static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
855{
856 int err;
857
858 memset(k, 0, sizeof(*k));
859 k->idx = -1;
Johannes Berge31b8212010-10-05 19:39:30 +0200860 k->type = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +0200861
862 if (info->attrs[NL80211_ATTR_KEY])
863 err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
864 else
865 err = nl80211_parse_key_old(info, k);
866
867 if (err)
868 return err;
869
870 if (k->def && k->defmgmt)
871 return -EINVAL;
872
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100873 if (k->defmgmt) {
874 if (k->def_uni || !k->def_multi)
875 return -EINVAL;
876 }
877
Johannes Bergb9454e82009-07-08 13:29:08 +0200878 if (k->idx != -1) {
879 if (k->defmgmt) {
880 if (k->idx < 4 || k->idx > 5)
881 return -EINVAL;
882 } else if (k->def) {
883 if (k->idx < 0 || k->idx > 3)
884 return -EINVAL;
885 } else {
886 if (k->idx < 0 || k->idx > 5)
887 return -EINVAL;
888 }
889 }
890
891 return 0;
892}
893
Johannes Bergfffd0932009-07-08 14:22:54 +0200894static struct cfg80211_cached_keys *
895nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +0530896 struct nlattr *keys, bool *no_ht)
Johannes Bergfffd0932009-07-08 14:22:54 +0200897{
898 struct key_parse parse;
899 struct nlattr *key;
900 struct cfg80211_cached_keys *result;
901 int rem, err, def = 0;
Johannes Bergf1c1f172016-09-13 17:08:23 +0200902 bool have_key = false;
903
904 nla_for_each_nested(key, keys, rem) {
905 have_key = true;
906 break;
907 }
908
909 if (!have_key)
910 return NULL;
Johannes Bergfffd0932009-07-08 14:22:54 +0200911
912 result = kzalloc(sizeof(*result), GFP_KERNEL);
913 if (!result)
914 return ERR_PTR(-ENOMEM);
915
916 result->def = -1;
Johannes Bergfffd0932009-07-08 14:22:54 +0200917
918 nla_for_each_nested(key, keys, rem) {
919 memset(&parse, 0, sizeof(parse));
920 parse.idx = -1;
921
922 err = nl80211_parse_key_new(key, &parse);
923 if (err)
924 goto error;
925 err = -EINVAL;
926 if (!parse.p.key)
927 goto error;
Johannes Berg42ee2312016-09-13 15:51:03 +0200928 if (parse.idx < 0 || parse.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +0200929 goto error;
930 if (parse.def) {
931 if (def)
932 goto error;
933 def = 1;
934 result->def = parse.idx;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100935 if (!parse.def_uni || !parse.def_multi)
936 goto error;
Johannes Bergfffd0932009-07-08 14:22:54 +0200937 } else if (parse.defmgmt)
938 goto error;
939 err = cfg80211_validate_key_settings(rdev, &parse.p,
Johannes Berge31b8212010-10-05 19:39:30 +0200940 parse.idx, false, NULL);
Johannes Bergfffd0932009-07-08 14:22:54 +0200941 if (err)
942 goto error;
Johannes Berg386b1f22016-09-13 16:10:02 +0200943 if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
944 parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
945 err = -EINVAL;
946 goto error;
947 }
Johannes Bergfffd0932009-07-08 14:22:54 +0200948 result->params[parse.idx].cipher = parse.p.cipher;
949 result->params[parse.idx].key_len = parse.p.key_len;
950 result->params[parse.idx].key = result->data[parse.idx];
951 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
Sujith Manoharande7044e2012-10-18 10:19:28 +0530952
Johannes Berg386b1f22016-09-13 16:10:02 +0200953 /* must be WEP key if we got here */
954 if (no_ht)
955 *no_ht = true;
Johannes Bergfffd0932009-07-08 14:22:54 +0200956 }
957
Johannes Bergf1c1f172016-09-13 17:08:23 +0200958 if (result->def < 0) {
959 err = -EINVAL;
960 goto error;
961 }
962
Johannes Bergfffd0932009-07-08 14:22:54 +0200963 return result;
964 error:
965 kfree(result);
966 return ERR_PTR(err);
967}
968
969static int nl80211_key_allowed(struct wireless_dev *wdev)
970{
971 ASSERT_WDEV_LOCK(wdev);
972
Johannes Bergfffd0932009-07-08 14:22:54 +0200973 switch (wdev->iftype) {
974 case NL80211_IFTYPE_AP:
975 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +0200976 case NL80211_IFTYPE_P2P_GO:
Thomas Pedersenff973af2011-05-03 16:57:12 -0700977 case NL80211_IFTYPE_MESH_POINT:
Johannes Bergfffd0932009-07-08 14:22:54 +0200978 break;
979 case NL80211_IFTYPE_ADHOC:
Johannes Bergfffd0932009-07-08 14:22:54 +0200980 case NL80211_IFTYPE_STATION:
Johannes Berg074ac8d2010-09-16 14:58:22 +0200981 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Bergceca7b72013-05-16 00:55:45 +0200982 if (!wdev->current_bss)
Johannes Bergfffd0932009-07-08 14:22:54 +0200983 return -ENOLINK;
984 break;
Johannes Bergde4fcba2014-10-31 14:16:12 +0100985 case NL80211_IFTYPE_UNSPECIFIED:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100986 case NL80211_IFTYPE_OCB:
Johannes Bergde4fcba2014-10-31 14:16:12 +0100987 case NL80211_IFTYPE_MONITOR:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300988 case NL80211_IFTYPE_NAN:
Johannes Bergde4fcba2014-10-31 14:16:12 +0100989 case NL80211_IFTYPE_P2P_DEVICE:
990 case NL80211_IFTYPE_WDS:
991 case NUM_NL80211_IFTYPES:
Johannes Bergfffd0932009-07-08 14:22:54 +0200992 return -EINVAL;
993 }
994
995 return 0;
996}
997
Jouni Malinen664834d2014-01-15 00:01:44 +0200998static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
999 struct nlattr *tb)
1000{
1001 struct ieee80211_channel *chan;
1002
1003 if (tb == NULL)
1004 return NULL;
1005 chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
1006 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
1007 return NULL;
1008 return chan;
1009}
1010
Johannes Berg7527a782011-05-13 10:58:57 +02001011static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
1012{
1013 struct nlattr *nl_modes = nla_nest_start(msg, attr);
1014 int i;
1015
1016 if (!nl_modes)
1017 goto nla_put_failure;
1018
1019 i = 0;
1020 while (ifmodes) {
David S. Miller9360ffd2012-03-29 04:41:26 -04001021 if ((ifmodes & 1) && nla_put_flag(msg, i))
1022 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001023 ifmodes >>= 1;
1024 i++;
1025 }
1026
1027 nla_nest_end(msg, nl_modes);
1028 return 0;
1029
1030nla_put_failure:
1031 return -ENOBUFS;
1032}
1033
1034static int nl80211_put_iface_combinations(struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +01001035 struct sk_buff *msg,
1036 bool large)
Johannes Berg7527a782011-05-13 10:58:57 +02001037{
1038 struct nlattr *nl_combis;
1039 int i, j;
1040
1041 nl_combis = nla_nest_start(msg,
1042 NL80211_ATTR_INTERFACE_COMBINATIONS);
1043 if (!nl_combis)
1044 goto nla_put_failure;
1045
1046 for (i = 0; i < wiphy->n_iface_combinations; i++) {
1047 const struct ieee80211_iface_combination *c;
1048 struct nlattr *nl_combi, *nl_limits;
1049
1050 c = &wiphy->iface_combinations[i];
1051
1052 nl_combi = nla_nest_start(msg, i + 1);
1053 if (!nl_combi)
1054 goto nla_put_failure;
1055
1056 nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS);
1057 if (!nl_limits)
1058 goto nla_put_failure;
1059
1060 for (j = 0; j < c->n_limits; j++) {
1061 struct nlattr *nl_limit;
1062
1063 nl_limit = nla_nest_start(msg, j + 1);
1064 if (!nl_limit)
1065 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04001066 if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
1067 c->limits[j].max))
1068 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001069 if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
1070 c->limits[j].types))
1071 goto nla_put_failure;
1072 nla_nest_end(msg, nl_limit);
1073 }
1074
1075 nla_nest_end(msg, nl_limits);
1076
David S. Miller9360ffd2012-03-29 04:41:26 -04001077 if (c->beacon_int_infra_match &&
1078 nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
1079 goto nla_put_failure;
1080 if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
1081 c->num_different_channels) ||
1082 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
1083 c->max_interfaces))
1084 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +01001085 if (large &&
Felix Fietkau8c48b502014-05-05 11:48:40 +02001086 (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
1087 c->radar_detect_widths) ||
1088 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
1089 c->radar_detect_regions)))
Johannes Bergcdc89b92013-02-18 23:54:36 +01001090 goto nla_put_failure;
Purushottam Kushwahac6800ff2016-10-12 18:26:51 +05301091 if (c->beacon_int_min_gcd &&
1092 nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
1093 c->beacon_int_min_gcd))
1094 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001095
1096 nla_nest_end(msg, nl_combi);
1097 }
1098
1099 nla_nest_end(msg, nl_combis);
1100
1101 return 0;
1102nla_put_failure:
1103 return -ENOBUFS;
1104}
1105
Johannes Berg3713b4e2013-02-14 16:19:38 +01001106#ifdef CONFIG_PM
Johannes Bergb56cf722013-02-20 01:02:38 +01001107static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
1108 struct sk_buff *msg)
1109{
Johannes Berg964dc9e2013-06-03 17:25:34 +02001110 const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
Johannes Bergb56cf722013-02-20 01:02:38 +01001111 struct nlattr *nl_tcp;
1112
1113 if (!tcp)
1114 return 0;
1115
1116 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
1117 if (!nl_tcp)
1118 return -ENOBUFS;
1119
1120 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1121 tcp->data_payload_max))
1122 return -ENOBUFS;
1123
1124 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1125 tcp->data_payload_max))
1126 return -ENOBUFS;
1127
1128 if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
1129 return -ENOBUFS;
1130
1131 if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
1132 sizeof(*tcp->tok), tcp->tok))
1133 return -ENOBUFS;
1134
1135 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
1136 tcp->data_interval_max))
1137 return -ENOBUFS;
1138
1139 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
1140 tcp->wake_payload_max))
1141 return -ENOBUFS;
1142
1143 nla_nest_end(msg, nl_tcp);
1144 return 0;
1145}
1146
Johannes Berg3713b4e2013-02-14 16:19:38 +01001147static int nl80211_send_wowlan(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001148 struct cfg80211_registered_device *rdev,
Johannes Bergb56cf722013-02-20 01:02:38 +01001149 bool large)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001150{
1151 struct nlattr *nl_wowlan;
1152
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001153 if (!rdev->wiphy.wowlan)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001154 return 0;
1155
1156 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
1157 if (!nl_wowlan)
1158 return -ENOBUFS;
1159
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001160 if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001161 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001162 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001163 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001164 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001165 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001166 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001167 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001168 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001169 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001170 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001171 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001172 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001173 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001174 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001175 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1176 return -ENOBUFS;
1177
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001178 if (rdev->wiphy.wowlan->n_patterns) {
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07001179 struct nl80211_pattern_support pat = {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001180 .max_patterns = rdev->wiphy.wowlan->n_patterns,
1181 .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
1182 .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
1183 .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001184 };
1185
1186 if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1187 sizeof(pat), &pat))
1188 return -ENOBUFS;
1189 }
1190
Luciano Coelho75453cc2015-01-09 14:06:37 +02001191 if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
1192 nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
1193 rdev->wiphy.wowlan->max_nd_match_sets))
1194 return -ENOBUFS;
1195
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001196 if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
Johannes Bergb56cf722013-02-20 01:02:38 +01001197 return -ENOBUFS;
1198
Johannes Berg3713b4e2013-02-14 16:19:38 +01001199 nla_nest_end(msg, nl_wowlan);
1200
1201 return 0;
1202}
1203#endif
1204
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001205static int nl80211_send_coalesce(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001206 struct cfg80211_registered_device *rdev)
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001207{
1208 struct nl80211_coalesce_rule_support rule;
1209
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001210 if (!rdev->wiphy.coalesce)
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001211 return 0;
1212
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001213 rule.max_rules = rdev->wiphy.coalesce->n_rules;
1214 rule.max_delay = rdev->wiphy.coalesce->max_delay;
1215 rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
1216 rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
1217 rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
1218 rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001219
1220 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1221 return -ENOBUFS;
1222
1223 return 0;
1224}
1225
Johannes Berg3713b4e2013-02-14 16:19:38 +01001226static int nl80211_send_band_rateinfo(struct sk_buff *msg,
1227 struct ieee80211_supported_band *sband)
1228{
1229 struct nlattr *nl_rates, *nl_rate;
1230 struct ieee80211_rate *rate;
1231 int i;
1232
1233 /* add HT info */
1234 if (sband->ht_cap.ht_supported &&
1235 (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1236 sizeof(sband->ht_cap.mcs),
1237 &sband->ht_cap.mcs) ||
1238 nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1239 sband->ht_cap.cap) ||
1240 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1241 sband->ht_cap.ampdu_factor) ||
1242 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1243 sband->ht_cap.ampdu_density)))
1244 return -ENOBUFS;
1245
1246 /* add VHT info */
1247 if (sband->vht_cap.vht_supported &&
1248 (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1249 sizeof(sband->vht_cap.vht_mcs),
1250 &sband->vht_cap.vht_mcs) ||
1251 nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1252 sband->vht_cap.cap)))
1253 return -ENOBUFS;
1254
1255 /* add bitrates */
1256 nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
1257 if (!nl_rates)
1258 return -ENOBUFS;
1259
1260 for (i = 0; i < sband->n_bitrates; i++) {
1261 nl_rate = nla_nest_start(msg, i);
1262 if (!nl_rate)
1263 return -ENOBUFS;
1264
1265 rate = &sband->bitrates[i];
1266 if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1267 rate->bitrate))
1268 return -ENOBUFS;
1269 if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1270 nla_put_flag(msg,
1271 NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1272 return -ENOBUFS;
1273
1274 nla_nest_end(msg, nl_rate);
1275 }
1276
1277 nla_nest_end(msg, nl_rates);
1278
1279 return 0;
1280}
1281
1282static int
1283nl80211_send_mgmt_stypes(struct sk_buff *msg,
1284 const struct ieee80211_txrx_stypes *mgmt_stypes)
1285{
1286 u16 stypes;
1287 struct nlattr *nl_ftypes, *nl_ifs;
1288 enum nl80211_iftype ift;
1289 int i;
1290
1291 if (!mgmt_stypes)
1292 return 0;
1293
1294 nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
1295 if (!nl_ifs)
1296 return -ENOBUFS;
1297
1298 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1299 nl_ftypes = nla_nest_start(msg, ift);
1300 if (!nl_ftypes)
1301 return -ENOBUFS;
1302 i = 0;
1303 stypes = mgmt_stypes[ift].tx;
1304 while (stypes) {
1305 if ((stypes & 1) &&
1306 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1307 (i << 4) | IEEE80211_FTYPE_MGMT))
1308 return -ENOBUFS;
1309 stypes >>= 1;
1310 i++;
1311 }
1312 nla_nest_end(msg, nl_ftypes);
1313 }
1314
1315 nla_nest_end(msg, nl_ifs);
1316
1317 nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
1318 if (!nl_ifs)
1319 return -ENOBUFS;
1320
1321 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1322 nl_ftypes = nla_nest_start(msg, ift);
1323 if (!nl_ftypes)
1324 return -ENOBUFS;
1325 i = 0;
1326 stypes = mgmt_stypes[ift].rx;
1327 while (stypes) {
1328 if ((stypes & 1) &&
1329 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1330 (i << 4) | IEEE80211_FTYPE_MGMT))
1331 return -ENOBUFS;
1332 stypes >>= 1;
1333 i++;
1334 }
1335 nla_nest_end(msg, nl_ftypes);
1336 }
1337 nla_nest_end(msg, nl_ifs);
1338
1339 return 0;
1340}
1341
Johannes Berg86e8cf92013-06-19 10:57:22 +02001342struct nl80211_dump_wiphy_state {
1343 s64 filter_wiphy;
1344 long start;
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301345 long split_start, band_start, chan_start, capa_start;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001346 bool split;
1347};
1348
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001349static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
Johannes Berg3bb20552014-05-26 13:52:25 +02001350 enum nl80211_commands cmd,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001351 struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001352 int flags, struct nl80211_dump_wiphy_state *state)
Johannes Berg55682962007-09-20 13:09:35 -04001353{
1354 void *hdr;
Johannes Bergee688b002008-01-24 19:38:39 +01001355 struct nlattr *nl_bands, *nl_band;
1356 struct nlattr *nl_freqs, *nl_freq;
Johannes Berg8fdc6212009-03-14 09:34:01 +01001357 struct nlattr *nl_cmds;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001358 enum nl80211_band band;
Johannes Bergee688b002008-01-24 19:38:39 +01001359 struct ieee80211_channel *chan;
Johannes Bergee688b002008-01-24 19:38:39 +01001360 int i;
Johannes Berg2e161f72010-08-12 15:38:38 +02001361 const struct ieee80211_txrx_stypes *mgmt_stypes =
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001362 rdev->wiphy.mgmt_stypes;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001363 u32 features;
Johannes Berg55682962007-09-20 13:09:35 -04001364
Johannes Berg3bb20552014-05-26 13:52:25 +02001365 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04001366 if (!hdr)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001367 return -ENOBUFS;
1368
Johannes Berg86e8cf92013-06-19 10:57:22 +02001369 if (WARN_ON(!state))
1370 return -EINVAL;
Johannes Berg55682962007-09-20 13:09:35 -04001371
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001372 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001373 nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001374 wiphy_name(&rdev->wiphy)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04001375 nla_put_u32(msg, NL80211_ATTR_GENERATION,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001376 cfg80211_rdev_list_generation))
David S. Miller9360ffd2012-03-29 04:41:26 -04001377 goto nla_put_failure;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02001378
Johannes Berg3bb20552014-05-26 13:52:25 +02001379 if (cmd != NL80211_CMD_NEW_WIPHY)
1380 goto finish;
1381
Johannes Berg86e8cf92013-06-19 10:57:22 +02001382 switch (state->split_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001383 case 0:
1384 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001385 rdev->wiphy.retry_short) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001386 nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001387 rdev->wiphy.retry_long) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001388 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001389 rdev->wiphy.frag_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001390 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001391 rdev->wiphy.rts_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001392 nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001393 rdev->wiphy.coverage_class) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001394 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001395 rdev->wiphy.max_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001396 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001397 rdev->wiphy.max_sched_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001398 nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001399 rdev->wiphy.max_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001400 nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001401 rdev->wiphy.max_sched_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001402 nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
Avraham Stern3b06d272015-10-12 09:51:34 +03001403 rdev->wiphy.max_match_sets) ||
1404 nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
1405 rdev->wiphy.max_sched_scan_plans) ||
1406 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
1407 rdev->wiphy.max_sched_scan_plan_interval) ||
1408 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
1409 rdev->wiphy.max_sched_scan_plan_iterations))
Johannes Bergee688b002008-01-24 19:38:39 +01001410 goto nla_put_failure;
1411
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001412 if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001413 nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
1414 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001415 if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001416 nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
1417 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001418 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001419 nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
1420 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001421 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001422 nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
1423 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001424 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001425 nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
1426 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001427 if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001428 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
David S. Miller9360ffd2012-03-29 04:41:26 -04001429 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001430 state->split_start++;
1431 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001432 break;
1433 case 1:
1434 if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001435 sizeof(u32) * rdev->wiphy.n_cipher_suites,
1436 rdev->wiphy.cipher_suites))
Mahesh Palivelabf0c111e2012-06-22 07:27:46 +00001437 goto nla_put_failure;
1438
Johannes Berg3713b4e2013-02-14 16:19:38 +01001439 if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001440 rdev->wiphy.max_num_pmkids))
Johannes Bergee688b002008-01-24 19:38:39 +01001441 goto nla_put_failure;
1442
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001443 if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001444 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
1445 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001446
Johannes Berg3713b4e2013-02-14 16:19:38 +01001447 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001448 rdev->wiphy.available_antennas_tx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001449 nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001450 rdev->wiphy.available_antennas_rx))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001451 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001452
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001453 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001454 nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001455 rdev->wiphy.probe_resp_offload))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001456 goto nla_put_failure;
Jouni Malinene2f367f262008-11-21 19:01:30 +02001457
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001458 if ((rdev->wiphy.available_antennas_tx ||
1459 rdev->wiphy.available_antennas_rx) &&
1460 rdev->ops->get_antenna) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001461 u32 tx_ant = 0, rx_ant = 0;
1462 int res;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07001463
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001464 res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001465 if (!res) {
1466 if (nla_put_u32(msg,
1467 NL80211_ATTR_WIPHY_ANTENNA_TX,
1468 tx_ant) ||
1469 nla_put_u32(msg,
1470 NL80211_ATTR_WIPHY_ANTENNA_RX,
1471 rx_ant))
1472 goto nla_put_failure;
1473 }
Johannes Bergee688b002008-01-24 19:38:39 +01001474 }
1475
Johannes Berg86e8cf92013-06-19 10:57:22 +02001476 state->split_start++;
1477 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001478 break;
1479 case 2:
1480 if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001481 rdev->wiphy.interface_modes))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001482 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001483 state->split_start++;
1484 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001485 break;
1486 case 3:
1487 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
1488 if (!nl_bands)
Johannes Bergee688b002008-01-24 19:38:39 +01001489 goto nla_put_failure;
1490
Johannes Berg86e8cf92013-06-19 10:57:22 +02001491 for (band = state->band_start;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001492 band < NUM_NL80211_BANDS; band++) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001493 struct ieee80211_supported_band *sband;
1494
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001495 sband = rdev->wiphy.bands[band];
Johannes Berg3713b4e2013-02-14 16:19:38 +01001496
1497 if (!sband)
1498 continue;
1499
1500 nl_band = nla_nest_start(msg, band);
1501 if (!nl_band)
Johannes Bergee688b002008-01-24 19:38:39 +01001502 goto nla_put_failure;
1503
Johannes Berg86e8cf92013-06-19 10:57:22 +02001504 switch (state->chan_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001505 case 0:
1506 if (nl80211_send_band_rateinfo(msg, sband))
1507 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001508 state->chan_start++;
1509 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001510 break;
1511 default:
1512 /* add frequencies */
1513 nl_freqs = nla_nest_start(
1514 msg, NL80211_BAND_ATTR_FREQS);
1515 if (!nl_freqs)
1516 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001517
Johannes Berg86e8cf92013-06-19 10:57:22 +02001518 for (i = state->chan_start - 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001519 i < sband->n_channels;
1520 i++) {
1521 nl_freq = nla_nest_start(msg, i);
1522 if (!nl_freq)
1523 goto nla_put_failure;
1524
1525 chan = &sband->channels[i];
1526
Johannes Berg86e8cf92013-06-19 10:57:22 +02001527 if (nl80211_msg_put_channel(
1528 msg, chan,
1529 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001530 goto nla_put_failure;
1531
1532 nla_nest_end(msg, nl_freq);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001533 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001534 break;
1535 }
1536 if (i < sband->n_channels)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001537 state->chan_start = i + 2;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001538 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001539 state->chan_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001540 nla_nest_end(msg, nl_freqs);
1541 }
1542
1543 nla_nest_end(msg, nl_band);
1544
Johannes Berg86e8cf92013-06-19 10:57:22 +02001545 if (state->split) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001546 /* start again here */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001547 if (state->chan_start)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001548 band--;
1549 break;
1550 }
Johannes Bergee688b002008-01-24 19:38:39 +01001551 }
Johannes Berg3713b4e2013-02-14 16:19:38 +01001552 nla_nest_end(msg, nl_bands);
Johannes Bergee688b002008-01-24 19:38:39 +01001553
Johannes Berg57fbcce2016-04-12 15:56:15 +02001554 if (band < NUM_NL80211_BANDS)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001555 state->band_start = band + 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001556 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001557 state->band_start = 0;
Johannes Bergee688b002008-01-24 19:38:39 +01001558
Johannes Berg3713b4e2013-02-14 16:19:38 +01001559 /* if bands & channels are done, continue outside */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001560 if (state->band_start == 0 && state->chan_start == 0)
1561 state->split_start++;
1562 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001563 break;
1564 case 4:
1565 nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
1566 if (!nl_cmds)
David S. Miller9360ffd2012-03-29 04:41:26 -04001567 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001568
1569 i = 0;
1570#define CMD(op, n) \
1571 do { \
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001572 if (rdev->ops->op) { \
Johannes Berg3713b4e2013-02-14 16:19:38 +01001573 i++; \
1574 if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1575 goto nla_put_failure; \
1576 } \
1577 } while (0)
1578
1579 CMD(add_virtual_intf, NEW_INTERFACE);
1580 CMD(change_virtual_intf, SET_INTERFACE);
1581 CMD(add_key, NEW_KEY);
1582 CMD(start_ap, START_AP);
1583 CMD(add_station, NEW_STATION);
1584 CMD(add_mpath, NEW_MPATH);
1585 CMD(update_mesh_config, SET_MESH_CONFIG);
1586 CMD(change_bss, SET_BSS);
1587 CMD(auth, AUTHENTICATE);
1588 CMD(assoc, ASSOCIATE);
1589 CMD(deauth, DEAUTHENTICATE);
1590 CMD(disassoc, DISASSOCIATE);
1591 CMD(join_ibss, JOIN_IBSS);
1592 CMD(join_mesh, JOIN_MESH);
1593 CMD(set_pmksa, SET_PMKSA);
1594 CMD(del_pmksa, DEL_PMKSA);
1595 CMD(flush_pmksa, FLUSH_PMKSA);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001596 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001597 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1598 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1599 CMD(mgmt_tx, FRAME);
1600 CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001601 if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001602 i++;
1603 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1604 goto nla_put_failure;
1605 }
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001606 if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
1607 rdev->ops->join_mesh) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001608 i++;
1609 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1610 goto nla_put_failure;
1611 }
1612 CMD(set_wds_peer, SET_WDS_PEER);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001613 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001614 CMD(tdls_mgmt, TDLS_MGMT);
1615 CMD(tdls_oper, TDLS_OPER);
1616 }
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001617 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001618 CMD(sched_scan_start, START_SCHED_SCAN);
1619 CMD(probe_client, PROBE_CLIENT);
1620 CMD(set_noack_map, SET_NOACK_MAP);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001621 if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001622 i++;
1623 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1624 goto nla_put_failure;
1625 }
1626 CMD(start_p2p_device, START_P2P_DEVICE);
1627 CMD(set_mcast_rate, SET_MCAST_RATE);
Johannes Berg02df00e2014-06-10 14:06:25 +02001628#ifdef CONFIG_NL80211_TESTMODE
1629 CMD(testmode_cmd, TESTMODE);
1630#endif
Johannes Berg86e8cf92013-06-19 10:57:22 +02001631 if (state->split) {
Arend van Spriel5de17982013-04-18 15:49:00 +02001632 CMD(crit_proto_start, CRIT_PROTOCOL_START);
1633 CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001634 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02001635 CMD(channel_switch, CHANNEL_SWITCH);
Johannes Berg02df00e2014-06-10 14:06:25 +02001636 CMD(set_qos_map, SET_QOS_MAP);
Johannes Berg723e73a2014-10-22 09:25:06 +02001637 if (rdev->wiphy.features &
1638 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
Johannes Berg960d01a2014-09-09 22:55:35 +03001639 CMD(add_tx_ts, ADD_TX_TS);
Michael Braund757efc2016-10-10 19:12:22 +02001640 CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
vamsi krishna30da4e82016-10-27 16:51:11 +03001641 CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
Arend van Spriel5de17982013-04-18 15:49:00 +02001642 }
Johannes Berg02df00e2014-06-10 14:06:25 +02001643 /* add into the if now */
Johannes Berg8fdc6212009-03-14 09:34:01 +01001644#undef CMD
Samuel Ortizb23aa672009-07-01 21:26:54 +02001645
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001646 if (rdev->ops->connect || rdev->ops->auth) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001647 i++;
1648 if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
Johannes Berg2e161f72010-08-12 15:38:38 +02001649 goto nla_put_failure;
Johannes Berg2e161f72010-08-12 15:38:38 +02001650 }
1651
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001652 if (rdev->ops->disconnect || rdev->ops->deauth) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001653 i++;
1654 if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1655 goto nla_put_failure;
1656 }
Johannes Berg74b70a42010-08-24 12:15:53 +02001657
Johannes Berg3713b4e2013-02-14 16:19:38 +01001658 nla_nest_end(msg, nl_cmds);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001659 state->split_start++;
1660 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001661 break;
1662 case 5:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001663 if (rdev->ops->remain_on_channel &&
1664 (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001665 nla_put_u32(msg,
1666 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001667 rdev->wiphy.max_remain_on_channel_duration))
Johannes Berg2e161f72010-08-12 15:38:38 +02001668 goto nla_put_failure;
1669
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001670 if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001671 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
1672 goto nla_put_failure;
Johannes Berg2e161f72010-08-12 15:38:38 +02001673
Johannes Berg3713b4e2013-02-14 16:19:38 +01001674 if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
1675 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001676 state->split_start++;
1677 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001678 break;
1679 case 6:
Johannes Bergdfb89c52012-06-27 09:23:48 +02001680#ifdef CONFIG_PM
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001681 if (nl80211_send_wowlan(msg, rdev, state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001682 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001683 state->split_start++;
1684 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001685 break;
1686#else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001687 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001688#endif
1689 case 7:
1690 if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001691 rdev->wiphy.software_iftypes))
Johannes Bergff1b6e62011-05-04 15:37:28 +02001692 goto nla_put_failure;
1693
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001694 if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001695 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001696 goto nla_put_failure;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001697
Johannes Berg86e8cf92013-06-19 10:57:22 +02001698 state->split_start++;
1699 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001700 break;
1701 case 8:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001702 if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001703 nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001704 rdev->wiphy.ap_sme_capa))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001705 goto nla_put_failure;
1706
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001707 features = rdev->wiphy.features;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001708 /*
1709 * We can only add the per-channel limit information if the
1710 * dump is split, otherwise it makes it too big. Therefore
1711 * only advertise it in that case.
1712 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001713 if (state->split)
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001714 features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
1715 if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001716 goto nla_put_failure;
1717
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001718 if (rdev->wiphy.ht_capa_mod_mask &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001719 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001720 sizeof(*rdev->wiphy.ht_capa_mod_mask),
1721 rdev->wiphy.ht_capa_mod_mask))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001722 goto nla_put_failure;
1723
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001724 if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
1725 rdev->wiphy.max_acl_mac_addrs &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001726 nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001727 rdev->wiphy.max_acl_mac_addrs))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001728 goto nla_put_failure;
1729
1730 /*
1731 * Any information below this point is only available to
1732 * applications that can deal with it being split. This
1733 * helps ensure that newly added capabilities don't break
1734 * older tools by overrunning their buffers.
1735 *
1736 * We still increment split_start so that in the split
1737 * case we'll continue with more data in the next round,
1738 * but break unconditionally so unsplit data stops here.
1739 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001740 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001741 break;
1742 case 9:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001743 if (rdev->wiphy.extended_capabilities &&
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001744 (nla_put(msg, NL80211_ATTR_EXT_CAPA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001745 rdev->wiphy.extended_capabilities_len,
1746 rdev->wiphy.extended_capabilities) ||
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001747 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001748 rdev->wiphy.extended_capabilities_len,
1749 rdev->wiphy.extended_capabilities_mask)))
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001750 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001751
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001752 if (rdev->wiphy.vht_capa_mod_mask &&
Johannes Bergee2aca32013-02-21 17:36:01 +01001753 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001754 sizeof(*rdev->wiphy.vht_capa_mod_mask),
1755 rdev->wiphy.vht_capa_mod_mask))
Johannes Bergee2aca32013-02-21 17:36:01 +01001756 goto nla_put_failure;
1757
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001758 state->split_start++;
1759 break;
1760 case 10:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001761 if (nl80211_send_coalesce(msg, rdev))
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001762 goto nla_put_failure;
1763
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001764 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001765 (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
1766 nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
1767 goto nla_put_failure;
Jouni Malinenb43504c2014-01-15 00:01:08 +02001768
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001769 if (rdev->wiphy.max_ap_assoc_sta &&
Jouni Malinenb43504c2014-01-15 00:01:08 +02001770 nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001771 rdev->wiphy.max_ap_assoc_sta))
Jouni Malinenb43504c2014-01-15 00:01:08 +02001772 goto nla_put_failure;
1773
Johannes Bergad7e7182013-11-13 13:37:47 +01001774 state->split_start++;
1775 break;
1776 case 11:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001777 if (rdev->wiphy.n_vendor_commands) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001778 const struct nl80211_vendor_cmd_info *info;
1779 struct nlattr *nested;
Johannes Bergad7e7182013-11-13 13:37:47 +01001780
Johannes Berg567ffc32013-12-18 14:43:31 +01001781 nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
1782 if (!nested)
Johannes Bergad7e7182013-11-13 13:37:47 +01001783 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01001784
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001785 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
1786 info = &rdev->wiphy.vendor_commands[i].info;
Johannes Berg567ffc32013-12-18 14:43:31 +01001787 if (nla_put(msg, i + 1, sizeof(*info), info))
1788 goto nla_put_failure;
1789 }
1790 nla_nest_end(msg, nested);
1791 }
1792
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001793 if (rdev->wiphy.n_vendor_events) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001794 const struct nl80211_vendor_cmd_info *info;
1795 struct nlattr *nested;
1796
1797 nested = nla_nest_start(msg,
1798 NL80211_ATTR_VENDOR_EVENTS);
1799 if (!nested)
1800 goto nla_put_failure;
1801
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001802 for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
1803 info = &rdev->wiphy.vendor_events[i];
Johannes Berg567ffc32013-12-18 14:43:31 +01001804 if (nla_put(msg, i + 1, sizeof(*info), info))
1805 goto nla_put_failure;
1806 }
1807 nla_nest_end(msg, nested);
1808 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03001809 state->split_start++;
1810 break;
1811 case 12:
1812 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
1813 nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
1814 rdev->wiphy.max_num_csa_counters))
1815 goto nla_put_failure;
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001816
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02001817 if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
1818 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
1819 goto nla_put_failure;
1820
Gautam Kumar Shuklad75bb062014-12-23 16:55:19 +01001821 if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
1822 sizeof(rdev->wiphy.ext_features),
1823 rdev->wiphy.ext_features))
1824 goto nla_put_failure;
1825
Arend van Spriel38de03d2016-03-02 20:37:18 +01001826 if (rdev->wiphy.bss_select_support) {
1827 struct nlattr *nested;
1828 u32 bss_select_support = rdev->wiphy.bss_select_support;
1829
1830 nested = nla_nest_start(msg, NL80211_ATTR_BSS_SELECT);
1831 if (!nested)
1832 goto nla_put_failure;
1833
1834 i = 0;
1835 while (bss_select_support) {
1836 if ((bss_select_support & 1) &&
1837 nla_put_flag(msg, i))
1838 goto nla_put_failure;
1839 i++;
1840 bss_select_support >>= 1;
1841 }
1842 nla_nest_end(msg, nested);
1843 }
1844
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301845 state->split_start++;
1846 break;
1847 case 13:
1848 if (rdev->wiphy.num_iftype_ext_capab &&
1849 rdev->wiphy.iftype_ext_capab) {
1850 struct nlattr *nested_ext_capab, *nested;
1851
1852 nested = nla_nest_start(msg,
1853 NL80211_ATTR_IFTYPE_EXT_CAPA);
1854 if (!nested)
1855 goto nla_put_failure;
1856
1857 for (i = state->capa_start;
1858 i < rdev->wiphy.num_iftype_ext_capab; i++) {
1859 const struct wiphy_iftype_ext_capab *capab;
1860
1861 capab = &rdev->wiphy.iftype_ext_capab[i];
1862
1863 nested_ext_capab = nla_nest_start(msg, i);
1864 if (!nested_ext_capab ||
1865 nla_put_u32(msg, NL80211_ATTR_IFTYPE,
1866 capab->iftype) ||
1867 nla_put(msg, NL80211_ATTR_EXT_CAPA,
1868 capab->extended_capabilities_len,
1869 capab->extended_capabilities) ||
1870 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
1871 capab->extended_capabilities_len,
1872 capab->extended_capabilities_mask))
1873 goto nla_put_failure;
1874
1875 nla_nest_end(msg, nested_ext_capab);
1876 if (state->split)
1877 break;
1878 }
1879 nla_nest_end(msg, nested);
1880 if (i < rdev->wiphy.num_iftype_ext_capab) {
1881 state->capa_start = i + 1;
1882 break;
1883 }
1884 }
1885
Johannes Berg3713b4e2013-02-14 16:19:38 +01001886 /* done */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001887 state->split_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001888 break;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001889 }
Johannes Berg3bb20552014-05-26 13:52:25 +02001890 finish:
Johannes Berg053c0952015-01-16 22:09:00 +01001891 genlmsg_end(msg, hdr);
1892 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04001893
1894 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001895 genlmsg_cancel(msg, hdr);
1896 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04001897}
1898
Johannes Berg86e8cf92013-06-19 10:57:22 +02001899static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
1900 struct netlink_callback *cb,
1901 struct nl80211_dump_wiphy_state *state)
1902{
1903 struct nlattr **tb = nl80211_fam.attrbuf;
1904 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
1905 tb, nl80211_fam.maxattr, nl80211_policy);
1906 /* ignore parse errors for backward compatibility */
1907 if (ret)
1908 return 0;
1909
1910 state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
1911 if (tb[NL80211_ATTR_WIPHY])
1912 state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
1913 if (tb[NL80211_ATTR_WDEV])
1914 state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
1915 if (tb[NL80211_ATTR_IFINDEX]) {
1916 struct net_device *netdev;
1917 struct cfg80211_registered_device *rdev;
1918 int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
1919
Ying Xue7f2b8562014-01-15 10:23:45 +08001920 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001921 if (!netdev)
1922 return -ENODEV;
1923 if (netdev->ieee80211_ptr) {
Zhao, Gangf26cbf42014-04-21 12:53:03 +08001924 rdev = wiphy_to_rdev(
Johannes Berg86e8cf92013-06-19 10:57:22 +02001925 netdev->ieee80211_ptr->wiphy);
1926 state->filter_wiphy = rdev->wiphy_idx;
1927 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001928 }
1929
1930 return 0;
1931}
1932
Johannes Berg55682962007-09-20 13:09:35 -04001933static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
1934{
Johannes Berg645e77d2013-03-01 14:03:49 +01001935 int idx = 0, ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001936 struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001937 struct cfg80211_registered_device *rdev;
Johannes Berg3a5a4232013-06-19 10:09:57 +02001938
Johannes Berg5fe231e2013-05-08 21:45:15 +02001939 rtnl_lock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02001940 if (!state) {
1941 state = kzalloc(sizeof(*state), GFP_KERNEL);
John W. Linville57ed5cd2013-06-28 13:18:21 -04001942 if (!state) {
1943 rtnl_unlock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02001944 return -ENOMEM;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001945 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001946 state->filter_wiphy = -1;
1947 ret = nl80211_dump_wiphy_parse(skb, cb, state);
1948 if (ret) {
1949 kfree(state);
1950 rtnl_unlock();
1951 return ret;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001952 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001953 cb->args[0] = (long)state;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001954 }
1955
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001956 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
1957 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02001958 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001959 if (++idx <= state->start)
Johannes Berg55682962007-09-20 13:09:35 -04001960 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001961 if (state->filter_wiphy != -1 &&
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001962 state->filter_wiphy != rdev->wiphy_idx)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001963 continue;
1964 /* attempt to fit multiple wiphy data chunks into the skb */
1965 do {
Johannes Berg3bb20552014-05-26 13:52:25 +02001966 ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
1967 skb,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001968 NETLINK_CB(cb->skb).portid,
1969 cb->nlh->nlmsg_seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001970 NLM_F_MULTI, state);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001971 if (ret < 0) {
1972 /*
1973 * If sending the wiphy data didn't fit (ENOBUFS
1974 * or EMSGSIZE returned), this SKB is still
1975 * empty (so it's not too big because another
1976 * wiphy dataset is already in the skb) and
1977 * we've not tried to adjust the dump allocation
1978 * yet ... then adjust the alloc size to be
1979 * bigger, and return 1 but with the empty skb.
1980 * This results in an empty message being RX'ed
1981 * in userspace, but that is ignored.
1982 *
1983 * We can then retry with the larger buffer.
1984 */
1985 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
Pontus Fuchsf12cb282014-01-16 15:00:40 +01001986 !skb->len && !state->split &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001987 cb->min_dump_alloc < 4096) {
1988 cb->min_dump_alloc = 4096;
Pontus Fuchsf12cb282014-01-16 15:00:40 +01001989 state->split_start = 0;
David S. Millerd98cae64e2013-06-19 16:49:39 -07001990 rtnl_unlock();
Johannes Berg3713b4e2013-02-14 16:19:38 +01001991 return 1;
1992 }
1993 idx--;
1994 break;
Johannes Berg645e77d2013-03-01 14:03:49 +01001995 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001996 } while (state->split_start > 0);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001997 break;
Johannes Berg55682962007-09-20 13:09:35 -04001998 }
Johannes Berg5fe231e2013-05-08 21:45:15 +02001999 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002000
Johannes Berg86e8cf92013-06-19 10:57:22 +02002001 state->start = idx;
Johannes Berg55682962007-09-20 13:09:35 -04002002
2003 return skb->len;
2004}
2005
Johannes Berg86e8cf92013-06-19 10:57:22 +02002006static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
2007{
2008 kfree((void *)cb->args[0]);
2009 return 0;
2010}
2011
Johannes Berg55682962007-09-20 13:09:35 -04002012static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
2013{
2014 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002015 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg86e8cf92013-06-19 10:57:22 +02002016 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -04002017
Johannes Berg645e77d2013-03-01 14:03:49 +01002018 msg = nlmsg_new(4096, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002019 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002020 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002021
Johannes Berg3bb20552014-05-26 13:52:25 +02002022 if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
2023 info->snd_portid, info->snd_seq, 0,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002024 &state) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002025 nlmsg_free(msg);
2026 return -ENOBUFS;
2027 }
Johannes Berg55682962007-09-20 13:09:35 -04002028
Johannes Berg134e6372009-07-10 09:51:34 +00002029 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002030}
2031
Jouni Malinen31888482008-10-30 16:59:24 +02002032static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
2033 [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 },
2034 [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 },
2035 [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 },
2036 [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 },
2037 [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 },
2038};
2039
2040static int parse_txq_params(struct nlattr *tb[],
2041 struct ieee80211_txq_params *txq_params)
2042{
Dan Williams0781a502018-01-29 17:03:15 -08002043 u8 ac;
2044
Johannes Berga3304b02012-03-28 11:04:24 +02002045 if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
Jouni Malinen31888482008-10-30 16:59:24 +02002046 !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
2047 !tb[NL80211_TXQ_ATTR_AIFS])
2048 return -EINVAL;
2049
Dan Williams0781a502018-01-29 17:03:15 -08002050 ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
Jouni Malinen31888482008-10-30 16:59:24 +02002051 txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
2052 txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
2053 txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
2054 txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
2055
Dan Williams0781a502018-01-29 17:03:15 -08002056 if (ac >= NL80211_NUM_ACS)
Johannes Berga3304b02012-03-28 11:04:24 +02002057 return -EINVAL;
Dan Williams0781a502018-01-29 17:03:15 -08002058 txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS);
Jouni Malinen31888482008-10-30 16:59:24 +02002059 return 0;
2060}
2061
Johannes Bergf444de02010-05-05 15:25:02 +02002062static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
2063{
2064 /*
Johannes Bergcc1d2802012-05-16 23:50:20 +02002065 * You can only set the channel explicitly for WDS interfaces,
2066 * all others have their channel managed via their respective
2067 * "establish a connection" command (connect, join, ...)
2068 *
2069 * For AP/GO and mesh mode, the channel can be set with the
2070 * channel userspace API, but is only stored and passed to the
2071 * low-level driver when the AP starts or the mesh is joined.
2072 * This is for backward compatibility, userspace can also give
2073 * the channel in the start-ap or join-mesh commands instead.
Johannes Bergf444de02010-05-05 15:25:02 +02002074 *
2075 * Monitors are special as they are normally slaved to
Johannes Berge8c9bd52012-06-06 08:18:22 +02002076 * whatever else is going on, so they have their own special
2077 * operation to set the monitor channel if possible.
Johannes Bergf444de02010-05-05 15:25:02 +02002078 */
2079 return !wdev ||
2080 wdev->iftype == NL80211_IFTYPE_AP ||
Johannes Bergf444de02010-05-05 15:25:02 +02002081 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
Johannes Berg074ac8d2010-09-16 14:58:22 +02002082 wdev->iftype == NL80211_IFTYPE_MONITOR ||
2083 wdev->iftype == NL80211_IFTYPE_P2P_GO;
Johannes Bergf444de02010-05-05 15:25:02 +02002084}
2085
Johannes Berg683b6d32012-11-08 21:25:48 +01002086static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
2087 struct genl_info *info,
2088 struct cfg80211_chan_def *chandef)
2089{
Mahesh Paliveladbeca2e2012-11-29 14:11:07 +05302090 u32 control_freq;
Johannes Berg683b6d32012-11-08 21:25:48 +01002091
2092 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
2093 return -EINVAL;
2094
2095 control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
2096
2097 chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002098 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
2099 chandef->center_freq1 = control_freq;
2100 chandef->center_freq2 = 0;
Johannes Berg683b6d32012-11-08 21:25:48 +01002101
2102 /* Primary channel not allowed */
2103 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
2104 return -EINVAL;
2105
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002106 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
2107 enum nl80211_channel_type chantype;
Johannes Berg683b6d32012-11-08 21:25:48 +01002108
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002109 chantype = nla_get_u32(
2110 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
2111
2112 switch (chantype) {
2113 case NL80211_CHAN_NO_HT:
2114 case NL80211_CHAN_HT20:
2115 case NL80211_CHAN_HT40PLUS:
2116 case NL80211_CHAN_HT40MINUS:
2117 cfg80211_chandef_create(chandef, chandef->chan,
2118 chantype);
2119 break;
2120 default:
Johannes Berg683b6d32012-11-08 21:25:48 +01002121 return -EINVAL;
Johannes Berg683b6d32012-11-08 21:25:48 +01002122 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002123 } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
2124 chandef->width =
2125 nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
2126 if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
2127 chandef->center_freq1 =
2128 nla_get_u32(
2129 info->attrs[NL80211_ATTR_CENTER_FREQ1]);
2130 if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
2131 chandef->center_freq2 =
2132 nla_get_u32(
2133 info->attrs[NL80211_ATTR_CENTER_FREQ2]);
2134 }
2135
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002136 if (!cfg80211_chandef_valid(chandef))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002137 return -EINVAL;
2138
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002139 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
2140 IEEE80211_CHAN_DISABLED))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002141 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002142
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002143 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
2144 chandef->width == NL80211_CHAN_WIDTH_10) &&
2145 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
2146 return -EINVAL;
2147
Johannes Berg683b6d32012-11-08 21:25:48 +01002148 return 0;
2149}
2150
Johannes Bergf444de02010-05-05 15:25:02 +02002151static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
Jouni Malinene16821b2014-04-28 11:22:08 +03002152 struct net_device *dev,
Johannes Bergf444de02010-05-05 15:25:02 +02002153 struct genl_info *info)
2154{
Johannes Berg683b6d32012-11-08 21:25:48 +01002155 struct cfg80211_chan_def chandef;
Johannes Bergf444de02010-05-05 15:25:02 +02002156 int result;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002157 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
Jouni Malinene16821b2014-04-28 11:22:08 +03002158 struct wireless_dev *wdev = NULL;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002159
Jouni Malinene16821b2014-04-28 11:22:08 +03002160 if (dev)
2161 wdev = dev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002162 if (!nl80211_can_set_dev_channel(wdev))
2163 return -EOPNOTSUPP;
Jouni Malinene16821b2014-04-28 11:22:08 +03002164 if (wdev)
2165 iftype = wdev->iftype;
Johannes Bergf444de02010-05-05 15:25:02 +02002166
Johannes Berg683b6d32012-11-08 21:25:48 +01002167 result = nl80211_parse_chandef(rdev, info, &chandef);
2168 if (result)
2169 return result;
Johannes Bergf444de02010-05-05 15:25:02 +02002170
Johannes Berge8c9bd52012-06-06 08:18:22 +02002171 switch (iftype) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002172 case NL80211_IFTYPE_AP:
2173 case NL80211_IFTYPE_P2P_GO:
Arik Nemtsov923b3522015-07-08 15:41:44 +03002174 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
2175 iftype)) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002176 result = -EINVAL;
2177 break;
2178 }
Jouni Malinene16821b2014-04-28 11:22:08 +03002179 if (wdev->beacon_interval) {
2180 if (!dev || !rdev->ops->set_ap_chanwidth ||
2181 !(rdev->wiphy.features &
2182 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
2183 result = -EBUSY;
2184 break;
2185 }
2186
2187 /* Only allow dynamic channel width changes */
2188 if (chandef.chan != wdev->preset_chandef.chan) {
2189 result = -EBUSY;
2190 break;
2191 }
2192 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
2193 if (result)
2194 break;
2195 }
Johannes Berg683b6d32012-11-08 21:25:48 +01002196 wdev->preset_chandef = chandef;
Johannes Bergaa430da2012-05-16 23:50:18 +02002197 result = 0;
2198 break;
Johannes Bergcc1d2802012-05-16 23:50:20 +02002199 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg683b6d32012-11-08 21:25:48 +01002200 result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
Johannes Bergcc1d2802012-05-16 23:50:20 +02002201 break;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002202 case NL80211_IFTYPE_MONITOR:
Johannes Berg683b6d32012-11-08 21:25:48 +01002203 result = cfg80211_set_monitor_channel(rdev, &chandef);
Johannes Berge8c9bd52012-06-06 08:18:22 +02002204 break;
Johannes Bergaa430da2012-05-16 23:50:18 +02002205 default:
Johannes Berge8c9bd52012-06-06 08:18:22 +02002206 result = -EINVAL;
Johannes Bergf444de02010-05-05 15:25:02 +02002207 }
Johannes Bergf444de02010-05-05 15:25:02 +02002208
2209 return result;
2210}
2211
2212static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
2213{
Johannes Berg4c476992010-10-04 21:36:35 +02002214 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2215 struct net_device *netdev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02002216
Jouni Malinene16821b2014-04-28 11:22:08 +03002217 return __nl80211_set_channel(rdev, netdev, info);
Johannes Bergf444de02010-05-05 15:25:02 +02002218}
2219
Bill Jordane8347eb2010-10-01 13:54:28 -04002220static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
2221{
Johannes Berg43b19952010-10-07 13:10:30 +02002222 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2223 struct net_device *dev = info->user_ptr[1];
2224 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg388ac772010-10-07 13:11:09 +02002225 const u8 *bssid;
Bill Jordane8347eb2010-10-01 13:54:28 -04002226
2227 if (!info->attrs[NL80211_ATTR_MAC])
2228 return -EINVAL;
2229
Johannes Berg43b19952010-10-07 13:10:30 +02002230 if (netif_running(dev))
2231 return -EBUSY;
Bill Jordane8347eb2010-10-01 13:54:28 -04002232
Johannes Berg43b19952010-10-07 13:10:30 +02002233 if (!rdev->ops->set_wds_peer)
2234 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002235
Johannes Berg43b19952010-10-07 13:10:30 +02002236 if (wdev->iftype != NL80211_IFTYPE_WDS)
2237 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002238
2239 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Hila Gonene35e4d22012-06-27 17:19:42 +03002240 return rdev_set_wds_peer(rdev, dev, bssid);
Bill Jordane8347eb2010-10-01 13:54:28 -04002241}
2242
Johannes Berg55682962007-09-20 13:09:35 -04002243static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
2244{
2245 struct cfg80211_registered_device *rdev;
Johannes Bergf444de02010-05-05 15:25:02 +02002246 struct net_device *netdev = NULL;
2247 struct wireless_dev *wdev;
Bill Jordana1e567c2010-09-10 11:22:32 -04002248 int result = 0, rem_txq_params = 0;
Jouni Malinen31888482008-10-30 16:59:24 +02002249 struct nlattr *nl_txq_params;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002250 u32 changed;
2251 u8 retry_short = 0, retry_long = 0;
2252 u32 frag_threshold = 0, rts_threshold = 0;
Lukáš Turek81077e82009-12-21 22:50:47 +01002253 u8 coverage_class = 0;
Johannes Berg55682962007-09-20 13:09:35 -04002254
Johannes Berg5fe231e2013-05-08 21:45:15 +02002255 ASSERT_RTNL();
2256
Johannes Bergf444de02010-05-05 15:25:02 +02002257 /*
2258 * Try to find the wiphy and netdev. Normally this
2259 * function shouldn't need the netdev, but this is
2260 * done for backward compatibility -- previously
2261 * setting the channel was done per wiphy, but now
2262 * it is per netdev. Previous userland like hostapd
2263 * also passed a netdev to set_wiphy, so that it is
2264 * possible to let that go to the right netdev!
2265 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002266
Johannes Bergf444de02010-05-05 15:25:02 +02002267 if (info->attrs[NL80211_ATTR_IFINDEX]) {
2268 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
2269
Ying Xue7f2b8562014-01-15 10:23:45 +08002270 netdev = __dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002271 if (netdev && netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002272 rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002273 else
Johannes Bergf444de02010-05-05 15:25:02 +02002274 netdev = NULL;
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002275 }
2276
Johannes Bergf444de02010-05-05 15:25:02 +02002277 if (!netdev) {
Johannes Berg878d9ec2012-06-15 14:18:32 +02002278 rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
2279 info->attrs);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002280 if (IS_ERR(rdev))
Johannes Berg4c476992010-10-04 21:36:35 +02002281 return PTR_ERR(rdev);
Johannes Bergf444de02010-05-05 15:25:02 +02002282 wdev = NULL;
2283 netdev = NULL;
2284 result = 0;
Johannes Berg71fe96b2012-10-24 10:04:58 +02002285 } else
Johannes Bergf444de02010-05-05 15:25:02 +02002286 wdev = netdev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002287
2288 /*
2289 * end workaround code, by now the rdev is available
2290 * and locked, and wdev may or may not be NULL.
2291 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002292
2293 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
Jouni Malinen31888482008-10-30 16:59:24 +02002294 result = cfg80211_dev_rename(
2295 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002296
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002297 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002298 return result;
Johannes Berg55682962007-09-20 13:09:35 -04002299
Jouni Malinen31888482008-10-30 16:59:24 +02002300 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
2301 struct ieee80211_txq_params txq_params;
2302 struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
2303
Ying Xue7f2b8562014-01-15 10:23:45 +08002304 if (!rdev->ops->set_txq_params)
2305 return -EOPNOTSUPP;
Jouni Malinen31888482008-10-30 16:59:24 +02002306
Ying Xue7f2b8562014-01-15 10:23:45 +08002307 if (!netdev)
2308 return -EINVAL;
Eliad Pellerf70f01c2011-09-25 20:06:53 +03002309
Johannes Berg133a3ff2011-11-03 14:50:13 +01002310 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002311 netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2312 return -EINVAL;
Johannes Berg133a3ff2011-11-03 14:50:13 +01002313
Ying Xue7f2b8562014-01-15 10:23:45 +08002314 if (!netif_running(netdev))
2315 return -ENETDOWN;
Johannes Berg2b5f8b02012-04-02 10:51:55 +02002316
Jouni Malinen31888482008-10-30 16:59:24 +02002317 nla_for_each_nested(nl_txq_params,
2318 info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
2319 rem_txq_params) {
Johannes Bergae811e22014-01-24 10:17:47 +01002320 result = nla_parse(tb, NL80211_TXQ_ATTR_MAX,
2321 nla_data(nl_txq_params),
2322 nla_len(nl_txq_params),
2323 txq_params_policy);
2324 if (result)
2325 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002326 result = parse_txq_params(tb, &txq_params);
2327 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002328 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002329
Hila Gonene35e4d22012-06-27 17:19:42 +03002330 result = rdev_set_txq_params(rdev, netdev,
2331 &txq_params);
Jouni Malinen31888482008-10-30 16:59:24 +02002332 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002333 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002334 }
2335 }
2336
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002337 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinene16821b2014-04-28 11:22:08 +03002338 result = __nl80211_set_channel(
2339 rdev,
2340 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
2341 info);
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002342 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002343 return result;
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002344 }
2345
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002346 if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
Johannes Bergc8442112012-10-24 10:17:18 +02002347 struct wireless_dev *txp_wdev = wdev;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002348 enum nl80211_tx_power_setting type;
2349 int idx, mbm = 0;
2350
Johannes Bergc8442112012-10-24 10:17:18 +02002351 if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
2352 txp_wdev = NULL;
2353
Ying Xue7f2b8562014-01-15 10:23:45 +08002354 if (!rdev->ops->set_tx_power)
2355 return -EOPNOTSUPP;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002356
2357 idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
2358 type = nla_get_u32(info->attrs[idx]);
2359
2360 if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002361 (type != NL80211_TX_POWER_AUTOMATIC))
2362 return -EINVAL;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002363
2364 if (type != NL80211_TX_POWER_AUTOMATIC) {
2365 idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
2366 mbm = nla_get_u32(info->attrs[idx]);
2367 }
2368
Johannes Bergc8442112012-10-24 10:17:18 +02002369 result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002370 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002371 return result;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002372 }
2373
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002374 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
2375 info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
2376 u32 tx_ant, rx_ant;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07002377
Bruno Randolf7f531e02010-12-16 11:30:22 +09002378 if ((!rdev->wiphy.available_antennas_tx &&
2379 !rdev->wiphy.available_antennas_rx) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002380 !rdev->ops->set_antenna)
2381 return -EOPNOTSUPP;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002382
2383 tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
2384 rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
2385
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002386 /* reject antenna configurations which don't match the
Bruno Randolf7f531e02010-12-16 11:30:22 +09002387 * available antenna masks, except for the "all" mask */
2388 if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002389 (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
2390 return -EINVAL;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002391
Bruno Randolf7f531e02010-12-16 11:30:22 +09002392 tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
2393 rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002394
Hila Gonene35e4d22012-06-27 17:19:42 +03002395 result = rdev_set_antenna(rdev, tx_ant, rx_ant);
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002396 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002397 return result;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002398 }
2399
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002400 changed = 0;
2401
2402 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
2403 retry_short = nla_get_u8(
2404 info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002405 if (retry_short == 0)
2406 return -EINVAL;
2407
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002408 changed |= WIPHY_PARAM_RETRY_SHORT;
2409 }
2410
2411 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
2412 retry_long = nla_get_u8(
2413 info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002414 if (retry_long == 0)
2415 return -EINVAL;
2416
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002417 changed |= WIPHY_PARAM_RETRY_LONG;
2418 }
2419
2420 if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
2421 frag_threshold = nla_get_u32(
2422 info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002423 if (frag_threshold < 256)
2424 return -EINVAL;
2425
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002426 if (frag_threshold != (u32) -1) {
2427 /*
2428 * Fragments (apart from the last one) are required to
2429 * have even length. Make the fragmentation code
2430 * simpler by stripping LSB should someone try to use
2431 * odd threshold value.
2432 */
2433 frag_threshold &= ~0x1;
2434 }
2435 changed |= WIPHY_PARAM_FRAG_THRESHOLD;
2436 }
2437
2438 if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
2439 rts_threshold = nla_get_u32(
2440 info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
2441 changed |= WIPHY_PARAM_RTS_THRESHOLD;
2442 }
2443
Lukáš Turek81077e82009-12-21 22:50:47 +01002444 if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002445 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
2446 return -EINVAL;
2447
Lukáš Turek81077e82009-12-21 22:50:47 +01002448 coverage_class = nla_get_u8(
2449 info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
2450 changed |= WIPHY_PARAM_COVERAGE_CLASS;
2451 }
2452
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002453 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
2454 if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
2455 return -EOPNOTSUPP;
2456
2457 changed |= WIPHY_PARAM_DYN_ACK;
2458 }
2459
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002460 if (changed) {
2461 u8 old_retry_short, old_retry_long;
2462 u32 old_frag_threshold, old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002463 u8 old_coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002464
Ying Xue7f2b8562014-01-15 10:23:45 +08002465 if (!rdev->ops->set_wiphy_params)
2466 return -EOPNOTSUPP;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002467
2468 old_retry_short = rdev->wiphy.retry_short;
2469 old_retry_long = rdev->wiphy.retry_long;
2470 old_frag_threshold = rdev->wiphy.frag_threshold;
2471 old_rts_threshold = rdev->wiphy.rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002472 old_coverage_class = rdev->wiphy.coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002473
2474 if (changed & WIPHY_PARAM_RETRY_SHORT)
2475 rdev->wiphy.retry_short = retry_short;
2476 if (changed & WIPHY_PARAM_RETRY_LONG)
2477 rdev->wiphy.retry_long = retry_long;
2478 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
2479 rdev->wiphy.frag_threshold = frag_threshold;
2480 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
2481 rdev->wiphy.rts_threshold = rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002482 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
2483 rdev->wiphy.coverage_class = coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002484
Hila Gonene35e4d22012-06-27 17:19:42 +03002485 result = rdev_set_wiphy_params(rdev, changed);
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002486 if (result) {
2487 rdev->wiphy.retry_short = old_retry_short;
2488 rdev->wiphy.retry_long = old_retry_long;
2489 rdev->wiphy.frag_threshold = old_frag_threshold;
2490 rdev->wiphy.rts_threshold = old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002491 rdev->wiphy.coverage_class = old_coverage_class;
Michal Kazior9189ee32015-08-03 10:55:24 +02002492 return result;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002493 }
2494 }
Ying Xue7f2b8562014-01-15 10:23:45 +08002495 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002496}
2497
Johannes Berg71bbc992012-06-15 15:30:18 +02002498static inline u64 wdev_id(struct wireless_dev *wdev)
2499{
2500 return (u64)wdev->identifier |
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002501 ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
Johannes Berg71bbc992012-06-15 15:30:18 +02002502}
Johannes Berg55682962007-09-20 13:09:35 -04002503
Johannes Berg683b6d32012-11-08 21:25:48 +01002504static int nl80211_send_chandef(struct sk_buff *msg,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01002505 const struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01002506{
Johannes Berg601555c2014-11-27 17:26:56 +01002507 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
2508 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002509
Johannes Berg683b6d32012-11-08 21:25:48 +01002510 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
2511 chandef->chan->center_freq))
2512 return -ENOBUFS;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002513 switch (chandef->width) {
2514 case NL80211_CHAN_WIDTH_20_NOHT:
2515 case NL80211_CHAN_WIDTH_20:
2516 case NL80211_CHAN_WIDTH_40:
2517 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
2518 cfg80211_get_chandef_type(chandef)))
2519 return -ENOBUFS;
2520 break;
2521 default:
2522 break;
2523 }
2524 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
2525 return -ENOBUFS;
2526 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
2527 return -ENOBUFS;
2528 if (chandef->center_freq2 &&
2529 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
Johannes Berg683b6d32012-11-08 21:25:48 +01002530 return -ENOBUFS;
2531 return 0;
2532}
2533
Eric W. Biederman15e47302012-09-07 20:12:54 +00002534static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
Johannes Bergd7264052009-04-19 16:23:20 +02002535 struct cfg80211_registered_device *rdev,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002536 struct wireless_dev *wdev, bool removal)
Johannes Berg55682962007-09-20 13:09:35 -04002537{
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002538 struct net_device *dev = wdev->netdev;
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002539 u8 cmd = NL80211_CMD_NEW_INTERFACE;
Johannes Berg55682962007-09-20 13:09:35 -04002540 void *hdr;
2541
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002542 if (removal)
2543 cmd = NL80211_CMD_DEL_INTERFACE;
2544
2545 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04002546 if (!hdr)
2547 return -1;
2548
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002549 if (dev &&
2550 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002551 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002552 goto nla_put_failure;
2553
2554 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
2555 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02002556 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
2557 NL80211_ATTR_PAD) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002558 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04002559 nla_put_u32(msg, NL80211_ATTR_GENERATION,
2560 rdev->devlist_generation ^
2561 (cfg80211_rdev_list_generation << 2)))
2562 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002563
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002564 if (rdev->ops->get_channel) {
Johannes Berg683b6d32012-11-08 21:25:48 +01002565 int ret;
2566 struct cfg80211_chan_def chandef;
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002567
Johannes Berg683b6d32012-11-08 21:25:48 +01002568 ret = rdev_get_channel(rdev, wdev, &chandef);
2569 if (ret == 0) {
2570 if (nl80211_send_chandef(msg, &chandef))
2571 goto nla_put_failure;
2572 }
Pontus Fuchsd91df0e2012-04-03 16:39:58 +02002573 }
2574
Rafał Miłeckid55d0d52015-08-31 22:59:38 +02002575 if (rdev->ops->get_tx_power) {
2576 int dbm, ret;
2577
2578 ret = rdev_get_tx_power(rdev, wdev, &dbm);
2579 if (ret == 0 &&
2580 nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
2581 DBM_TO_MBM(dbm)))
2582 goto nla_put_failure;
2583 }
2584
Antonio Quartullib84e7a02012-11-07 12:52:20 +01002585 if (wdev->ssid_len) {
2586 if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
2587 goto nla_put_failure;
2588 }
2589
Johannes Berg053c0952015-01-16 22:09:00 +01002590 genlmsg_end(msg, hdr);
2591 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002592
2593 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002594 genlmsg_cancel(msg, hdr);
2595 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04002596}
2597
2598static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
2599{
2600 int wp_idx = 0;
2601 int if_idx = 0;
2602 int wp_start = cb->args[0];
2603 int if_start = cb->args[1];
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002604 int filter_wiphy = -1;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002605 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -04002606 struct wireless_dev *wdev;
Johannes Berg56769e72017-03-15 14:26:04 +01002607 int ret;
Johannes Berg55682962007-09-20 13:09:35 -04002608
Johannes Berg5fe231e2013-05-08 21:45:15 +02002609 rtnl_lock();
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002610 if (!cb->args[2]) {
2611 struct nl80211_dump_wiphy_state state = {
2612 .filter_wiphy = -1,
2613 };
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002614
2615 ret = nl80211_dump_wiphy_parse(skb, cb, &state);
2616 if (ret)
Johannes Berg56769e72017-03-15 14:26:04 +01002617 goto out_unlock;
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002618
2619 filter_wiphy = state.filter_wiphy;
2620
2621 /*
2622 * if filtering, set cb->args[2] to +1 since 0 is the default
2623 * value needed to determine that parsing is necessary.
2624 */
2625 if (filter_wiphy >= 0)
2626 cb->args[2] = filter_wiphy + 1;
2627 else
2628 cb->args[2] = -1;
2629 } else if (cb->args[2] > 0) {
2630 filter_wiphy = cb->args[2] - 1;
2631 }
2632
Johannes Bergf5ea9122009-08-07 16:17:38 +02002633 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2634 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002635 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002636 if (wp_idx < wp_start) {
2637 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002638 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002639 }
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002640
2641 if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
2642 continue;
2643
Johannes Berg55682962007-09-20 13:09:35 -04002644 if_idx = 0;
2645
Johannes Berg53873f12016-05-03 16:52:04 +03002646 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002647 if (if_idx < if_start) {
2648 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002649 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002650 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002651 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
Johannes Berg55682962007-09-20 13:09:35 -04002652 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002653 rdev, wdev, false) < 0) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002654 goto out;
2655 }
2656 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002657 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002658
2659 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002660 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002661 out:
Johannes Berg55682962007-09-20 13:09:35 -04002662 cb->args[0] = wp_idx;
2663 cb->args[1] = if_idx;
2664
Johannes Berg56769e72017-03-15 14:26:04 +01002665 ret = skb->len;
2666 out_unlock:
2667 rtnl_unlock();
2668
2669 return ret;
Johannes Berg55682962007-09-20 13:09:35 -04002670}
2671
2672static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
2673{
2674 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002675 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002676 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002677
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07002678 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002679 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002680 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002681
Eric W. Biederman15e47302012-09-07 20:12:54 +00002682 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002683 rdev, wdev, false) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002684 nlmsg_free(msg);
2685 return -ENOBUFS;
2686 }
Johannes Berg55682962007-09-20 13:09:35 -04002687
Johannes Berg134e6372009-07-10 09:51:34 +00002688 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002689}
2690
Michael Wu66f7ac52008-01-31 19:48:22 +01002691static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
2692 [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
2693 [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
2694 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
2695 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
2696 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002697 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
Michael Wu66f7ac52008-01-31 19:48:22 +01002698};
2699
2700static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
2701{
2702 struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
2703 int flag;
2704
2705 *mntrflags = 0;
2706
2707 if (!nla)
2708 return -EINVAL;
2709
2710 if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
2711 nla, mntr_flags_policy))
2712 return -EINVAL;
2713
2714 for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
2715 if (flags[flag])
2716 *mntrflags |= (1<<flag);
2717
2718 return 0;
2719}
2720
Johannes Berg9bc383d2009-11-19 11:55:19 +01002721static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002722 struct net_device *netdev, u8 use_4addr,
2723 enum nl80211_iftype iftype)
Johannes Berg9bc383d2009-11-19 11:55:19 +01002724{
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002725 if (!use_4addr) {
Jiri Pirkof350a0a82010-06-15 06:50:45 +00002726 if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002727 return -EBUSY;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002728 return 0;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002729 }
Johannes Berg9bc383d2009-11-19 11:55:19 +01002730
2731 switch (iftype) {
2732 case NL80211_IFTYPE_AP_VLAN:
2733 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
2734 return 0;
2735 break;
2736 case NL80211_IFTYPE_STATION:
2737 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
2738 return 0;
2739 break;
2740 default:
2741 break;
2742 }
2743
2744 return -EOPNOTSUPP;
2745}
2746
Johannes Berg55682962007-09-20 13:09:35 -04002747static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
2748{
Johannes Berg4c476992010-10-04 21:36:35 +02002749 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002750 struct vif_params params;
Johannes Berge36d56b2009-06-09 21:04:43 +02002751 int err;
Johannes Berg04a773a2009-04-19 21:24:32 +02002752 enum nl80211_iftype otype, ntype;
Johannes Berg4c476992010-10-04 21:36:35 +02002753 struct net_device *dev = info->user_ptr[1];
Johannes Berg92ffe052008-09-16 20:39:36 +02002754 u32 _flags, *flags = NULL;
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002755 bool change = false;
Johannes Berg55682962007-09-20 13:09:35 -04002756
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002757 memset(&params, 0, sizeof(params));
2758
Johannes Berg04a773a2009-04-19 21:24:32 +02002759 otype = ntype = dev->ieee80211_ptr->iftype;
Johannes Berg55682962007-09-20 13:09:35 -04002760
Johannes Berg723b0382008-09-16 20:22:09 +02002761 if (info->attrs[NL80211_ATTR_IFTYPE]) {
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002762 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg04a773a2009-04-19 21:24:32 +02002763 if (otype != ntype)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002764 change = true;
Johannes Berg4c476992010-10-04 21:36:35 +02002765 if (ntype > NL80211_IFTYPE_MAX)
2766 return -EINVAL;
Johannes Berg723b0382008-09-16 20:22:09 +02002767 }
2768
Johannes Berg92ffe052008-09-16 20:39:36 +02002769 if (info->attrs[NL80211_ATTR_MESH_ID]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01002770 struct wireless_dev *wdev = dev->ieee80211_ptr;
2771
Johannes Berg4c476992010-10-04 21:36:35 +02002772 if (ntype != NL80211_IFTYPE_MESH_POINT)
2773 return -EINVAL;
Johannes Berg29cbe682010-12-03 09:20:44 +01002774 if (netif_running(dev))
2775 return -EBUSY;
2776
2777 wdev_lock(wdev);
2778 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2779 IEEE80211_MAX_MESH_ID_LEN);
2780 wdev->mesh_id_up_len =
2781 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2782 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2783 wdev->mesh_id_up_len);
2784 wdev_unlock(wdev);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002785 }
2786
Felix Fietkau8b787642009-11-10 18:53:10 +01002787 if (info->attrs[NL80211_ATTR_4ADDR]) {
2788 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
2789 change = true;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002790 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002791 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002792 return err;
Felix Fietkau8b787642009-11-10 18:53:10 +01002793 } else {
2794 params.use_4addr = -1;
2795 }
2796
Johannes Berg92ffe052008-09-16 20:39:36 +02002797 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
Johannes Berg4c476992010-10-04 21:36:35 +02002798 if (ntype != NL80211_IFTYPE_MONITOR)
2799 return -EINVAL;
Johannes Berg92ffe052008-09-16 20:39:36 +02002800 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
2801 &_flags);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002802 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002803 return err;
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002804
2805 flags = &_flags;
2806 change = true;
Johannes Berg92ffe052008-09-16 20:39:36 +02002807 }
Johannes Berg3b858752009-03-12 09:55:09 +01002808
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +03002809 if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
2810 const u8 *mumimo_groups;
2811 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2812
2813 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2814 return -EOPNOTSUPP;
2815
2816 mumimo_groups =
2817 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
2818
2819 /* bits 0 and 63 are reserved and must be zero */
2820 if ((mumimo_groups[0] & BIT(7)) ||
2821 (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
2822 return -EINVAL;
2823
2824 memcpy(params.vht_mumimo_groups, mumimo_groups,
2825 VHT_MUMIMO_GROUPS_DATA_LEN);
2826 change = true;
2827 }
2828
2829 if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
2830 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2831
2832 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2833 return -EOPNOTSUPP;
2834
2835 nla_memcpy(params.macaddr,
2836 info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR],
2837 ETH_ALEN);
2838 change = true;
2839 }
2840
Luciano Coelho18003292013-08-29 13:26:57 +03002841 if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002842 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2843 return -EOPNOTSUPP;
2844
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002845 if (change)
Johannes Berg3d54d252009-08-21 14:51:05 +02002846 err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002847 else
2848 err = 0;
Johannes Berg60719ff2008-09-16 14:55:09 +02002849
Johannes Berg9bc383d2009-11-19 11:55:19 +01002850 if (!err && params.use_4addr != -1)
2851 dev->ieee80211_ptr->use_4addr = params.use_4addr;
2852
Johannes Berg55682962007-09-20 13:09:35 -04002853 return err;
2854}
2855
2856static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2857{
Johannes Berg4c476992010-10-04 21:36:35 +02002858 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002859 struct vif_params params;
Johannes Berg84efbb82012-06-16 00:00:26 +02002860 struct wireless_dev *wdev;
Denis Kenzior896ff062016-08-03 16:58:33 -05002861 struct sk_buff *msg;
Johannes Berg55682962007-09-20 13:09:35 -04002862 int err;
2863 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
Michael Wu66f7ac52008-01-31 19:48:22 +01002864 u32 flags;
Johannes Berg55682962007-09-20 13:09:35 -04002865
Johannes Berg78f22b62014-03-24 17:57:27 +01002866 /* to avoid failing a new interface creation due to pending removal */
2867 cfg80211_destroy_ifaces(rdev);
2868
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002869 memset(&params, 0, sizeof(params));
2870
Johannes Berg55682962007-09-20 13:09:35 -04002871 if (!info->attrs[NL80211_ATTR_IFNAME])
2872 return -EINVAL;
2873
2874 if (info->attrs[NL80211_ATTR_IFTYPE]) {
2875 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
2876 if (type > NL80211_IFTYPE_MAX)
2877 return -EINVAL;
2878 }
2879
Johannes Berg79c97e92009-07-07 03:56:12 +02002880 if (!rdev->ops->add_virtual_intf ||
Johannes Berg4c476992010-10-04 21:36:35 +02002881 !(rdev->wiphy.interface_modes & (1 << type)))
2882 return -EOPNOTSUPP;
Johannes Berg55682962007-09-20 13:09:35 -04002883
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002884 if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
Ben Greeare8f479b2014-10-22 12:23:05 -07002885 rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
2886 info->attrs[NL80211_ATTR_MAC]) {
Arend van Spriel1c18f142013-01-08 10:17:27 +01002887 nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
2888 ETH_ALEN);
2889 if (!is_valid_ether_addr(params.macaddr))
2890 return -EADDRNOTAVAIL;
2891 }
2892
Johannes Berg9bc383d2009-11-19 11:55:19 +01002893 if (info->attrs[NL80211_ATTR_4ADDR]) {
Felix Fietkau8b787642009-11-10 18:53:10 +01002894 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002895 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002896 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002897 return err;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002898 }
Felix Fietkau8b787642009-11-10 18:53:10 +01002899
Michael Wu66f7ac52008-01-31 19:48:22 +01002900 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
2901 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
2902 &flags);
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002903
Luciano Coelho18003292013-08-29 13:26:57 +03002904 if (!err && (flags & MONITOR_FLAG_ACTIVE) &&
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002905 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2906 return -EOPNOTSUPP;
2907
Johannes Berga18c7192015-02-24 10:56:42 +01002908 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2909 if (!msg)
2910 return -ENOMEM;
2911
Hila Gonene35e4d22012-06-27 17:19:42 +03002912 wdev = rdev_add_virtual_intf(rdev,
2913 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
Tom Gundersen6bab2e192015-03-18 11:13:39 +01002914 NET_NAME_USER, type, err ? NULL : &flags,
2915 &params);
Rafał Miłeckid687cbb2014-11-14 18:43:28 +01002916 if (WARN_ON(!wdev)) {
2917 nlmsg_free(msg);
2918 return -EPROTO;
2919 } else if (IS_ERR(wdev)) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002920 nlmsg_free(msg);
Johannes Berg84efbb82012-06-16 00:00:26 +02002921 return PTR_ERR(wdev);
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002922 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002923
Jukka Rissanen18e5ca62014-11-13 17:25:14 +02002924 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
Johannes Berg78f22b62014-03-24 17:57:27 +01002925 wdev->owner_nlportid = info->snd_portid;
2926
Johannes Berg98104fde2012-06-16 00:19:54 +02002927 switch (type) {
2928 case NL80211_IFTYPE_MESH_POINT:
2929 if (!info->attrs[NL80211_ATTR_MESH_ID])
2930 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002931 wdev_lock(wdev);
2932 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2933 IEEE80211_MAX_MESH_ID_LEN);
2934 wdev->mesh_id_up_len =
2935 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2936 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2937 wdev->mesh_id_up_len);
2938 wdev_unlock(wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02002939 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002940 case NL80211_IFTYPE_NAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02002941 case NL80211_IFTYPE_P2P_DEVICE:
2942 /*
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002943 * P2P Device and NAN do not have a netdev, so don't go
Johannes Berg98104fde2012-06-16 00:19:54 +02002944 * through the netdev notifier and must be added here
2945 */
2946 mutex_init(&wdev->mtx);
2947 INIT_LIST_HEAD(&wdev->event_list);
2948 spin_lock_init(&wdev->event_lock);
2949 INIT_LIST_HEAD(&wdev->mgmt_registrations);
2950 spin_lock_init(&wdev->mgmt_registrations_lock);
2951
Johannes Berg98104fde2012-06-16 00:19:54 +02002952 wdev->identifier = ++rdev->wdev_id;
Johannes Berg53873f12016-05-03 16:52:04 +03002953 list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
Johannes Berg98104fde2012-06-16 00:19:54 +02002954 rdev->devlist_generation++;
Johannes Berg98104fde2012-06-16 00:19:54 +02002955 break;
2956 default:
2957 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002958 }
2959
Eric W. Biederman15e47302012-09-07 20:12:54 +00002960 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002961 rdev, wdev, false) < 0) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002962 nlmsg_free(msg);
2963 return -ENOBUFS;
2964 }
2965
Denis Kenzior896ff062016-08-03 16:58:33 -05002966 /*
2967 * For wdevs which have no associated netdev object (e.g. of type
2968 * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
2969 * For all other types, the event will be generated from the
2970 * netdev notifier
2971 */
2972 if (!wdev->netdev)
2973 nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002974
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002975 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002976}
2977
2978static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
2979{
Johannes Berg4c476992010-10-04 21:36:35 +02002980 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg84efbb82012-06-16 00:00:26 +02002981 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002982
Johannes Berg4c476992010-10-04 21:36:35 +02002983 if (!rdev->ops->del_virtual_intf)
2984 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01002985
Johannes Berg84efbb82012-06-16 00:00:26 +02002986 /*
2987 * If we remove a wireless device without a netdev then clear
2988 * user_ptr[1] so that nl80211_post_doit won't dereference it
2989 * to check if it needs to do dev_put(). Otherwise it crashes
2990 * since the wdev has been freed, unlike with a netdev where
2991 * we need the dev_put() for the netdev to really be freed.
2992 */
2993 if (!wdev->netdev)
2994 info->user_ptr[1] = NULL;
2995
Denis Kenzior7f8ed012016-08-03 16:58:35 -05002996 return rdev_del_virtual_intf(rdev, wdev);
Johannes Berg55682962007-09-20 13:09:35 -04002997}
2998
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01002999static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
3000{
3001 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3002 struct net_device *dev = info->user_ptr[1];
3003 u16 noack_map;
3004
3005 if (!info->attrs[NL80211_ATTR_NOACK_MAP])
3006 return -EINVAL;
3007
3008 if (!rdev->ops->set_noack_map)
3009 return -EOPNOTSUPP;
3010
3011 noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
3012
Hila Gonene35e4d22012-06-27 17:19:42 +03003013 return rdev_set_noack_map(rdev, dev, noack_map);
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003014}
3015
Johannes Berg41ade002007-12-19 02:03:29 +01003016struct get_key_cookie {
3017 struct sk_buff *msg;
3018 int error;
Johannes Bergb9454e82009-07-08 13:29:08 +02003019 int idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003020};
3021
3022static void get_key_callback(void *c, struct key_params *params)
3023{
Johannes Bergb9454e82009-07-08 13:29:08 +02003024 struct nlattr *key;
Johannes Berg41ade002007-12-19 02:03:29 +01003025 struct get_key_cookie *cookie = c;
3026
David S. Miller9360ffd2012-03-29 04:41:26 -04003027 if ((params->key &&
3028 nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
3029 params->key_len, params->key)) ||
3030 (params->seq &&
3031 nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
3032 params->seq_len, params->seq)) ||
3033 (params->cipher &&
3034 nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
3035 params->cipher)))
3036 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003037
Johannes Bergb9454e82009-07-08 13:29:08 +02003038 key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
3039 if (!key)
3040 goto nla_put_failure;
3041
David S. Miller9360ffd2012-03-29 04:41:26 -04003042 if ((params->key &&
3043 nla_put(cookie->msg, NL80211_KEY_DATA,
3044 params->key_len, params->key)) ||
3045 (params->seq &&
3046 nla_put(cookie->msg, NL80211_KEY_SEQ,
3047 params->seq_len, params->seq)) ||
3048 (params->cipher &&
3049 nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
3050 params->cipher)))
3051 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003052
David S. Miller9360ffd2012-03-29 04:41:26 -04003053 if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx))
3054 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003055
3056 nla_nest_end(cookie->msg, key);
3057
Johannes Berg41ade002007-12-19 02:03:29 +01003058 return;
3059 nla_put_failure:
3060 cookie->error = 1;
3061}
3062
3063static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
3064{
Johannes Berg4c476992010-10-04 21:36:35 +02003065 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003066 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003067 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003068 u8 key_idx = 0;
Johannes Berge31b8212010-10-05 19:39:30 +02003069 const u8 *mac_addr = NULL;
3070 bool pairwise;
Johannes Berg41ade002007-12-19 02:03:29 +01003071 struct get_key_cookie cookie = {
3072 .error = 0,
3073 };
3074 void *hdr;
3075 struct sk_buff *msg;
3076
3077 if (info->attrs[NL80211_ATTR_KEY_IDX])
3078 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
3079
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +02003080 if (key_idx > 5)
Johannes Berg41ade002007-12-19 02:03:29 +01003081 return -EINVAL;
3082
3083 if (info->attrs[NL80211_ATTR_MAC])
3084 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3085
Johannes Berge31b8212010-10-05 19:39:30 +02003086 pairwise = !!mac_addr;
3087 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
3088 u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003089
Johannes Berge31b8212010-10-05 19:39:30 +02003090 if (kt >= NUM_NL80211_KEYTYPES)
3091 return -EINVAL;
3092 if (kt != NL80211_KEYTYPE_GROUP &&
3093 kt != NL80211_KEYTYPE_PAIRWISE)
3094 return -EINVAL;
3095 pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
3096 }
3097
Johannes Berg4c476992010-10-04 21:36:35 +02003098 if (!rdev->ops->get_key)
3099 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003100
Johannes Berg0fa7b392015-01-23 11:10:12 +01003101 if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3102 return -ENOENT;
3103
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003104 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02003105 if (!msg)
3106 return -ENOMEM;
Johannes Berg41ade002007-12-19 02:03:29 +01003107
Eric W. Biederman15e47302012-09-07 20:12:54 +00003108 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg41ade002007-12-19 02:03:29 +01003109 NL80211_CMD_NEW_KEY);
Dan Carpentercb35fba2013-08-14 14:50:01 +03003110 if (!hdr)
Johannes Berg9fe271a2013-10-25 11:15:12 +02003111 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003112
3113 cookie.msg = msg;
Johannes Bergb9454e82009-07-08 13:29:08 +02003114 cookie.idx = key_idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003115
David S. Miller9360ffd2012-03-29 04:41:26 -04003116 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3117 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
3118 goto nla_put_failure;
3119 if (mac_addr &&
3120 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
3121 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003122
Hila Gonene35e4d22012-06-27 17:19:42 +03003123 err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
3124 get_key_callback);
Johannes Berg41ade002007-12-19 02:03:29 +01003125
3126 if (err)
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003127 goto free_msg;
Johannes Berg41ade002007-12-19 02:03:29 +01003128
3129 if (cookie.error)
3130 goto nla_put_failure;
3131
3132 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02003133 return genlmsg_reply(msg, info);
Johannes Berg41ade002007-12-19 02:03:29 +01003134
3135 nla_put_failure:
3136 err = -ENOBUFS;
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003137 free_msg:
Johannes Berg41ade002007-12-19 02:03:29 +01003138 nlmsg_free(msg);
Johannes Berg41ade002007-12-19 02:03:29 +01003139 return err;
3140}
3141
3142static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
3143{
Johannes Berg4c476992010-10-04 21:36:35 +02003144 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergb9454e82009-07-08 13:29:08 +02003145 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003146 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003147 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003148
Johannes Bergb9454e82009-07-08 13:29:08 +02003149 err = nl80211_parse_key(info, &key);
3150 if (err)
3151 return err;
3152
3153 if (key.idx < 0)
Johannes Berg41ade002007-12-19 02:03:29 +01003154 return -EINVAL;
3155
Johannes Bergb9454e82009-07-08 13:29:08 +02003156 /* only support setting default key */
3157 if (!key.def && !key.defmgmt)
Johannes Berg41ade002007-12-19 02:03:29 +01003158 return -EINVAL;
3159
Johannes Bergfffd0932009-07-08 14:22:54 +02003160 wdev_lock(dev->ieee80211_ptr);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003161
3162 if (key.def) {
3163 if (!rdev->ops->set_default_key) {
3164 err = -EOPNOTSUPP;
3165 goto out;
3166 }
3167
3168 err = nl80211_key_allowed(dev->ieee80211_ptr);
3169 if (err)
3170 goto out;
3171
Hila Gonene35e4d22012-06-27 17:19:42 +03003172 err = rdev_set_default_key(rdev, dev, key.idx,
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003173 key.def_uni, key.def_multi);
3174
3175 if (err)
3176 goto out;
Johannes Bergfffd0932009-07-08 14:22:54 +02003177
Johannes Berg3d23e342009-09-29 23:27:28 +02003178#ifdef CONFIG_CFG80211_WEXT
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003179 dev->ieee80211_ptr->wext.default_key = key.idx;
Johannes Berg08645122009-05-11 13:54:58 +02003180#endif
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003181 } else {
3182 if (key.def_uni || !key.def_multi) {
3183 err = -EINVAL;
3184 goto out;
3185 }
3186
3187 if (!rdev->ops->set_default_mgmt_key) {
3188 err = -EOPNOTSUPP;
3189 goto out;
3190 }
3191
3192 err = nl80211_key_allowed(dev->ieee80211_ptr);
3193 if (err)
3194 goto out;
3195
Hila Gonene35e4d22012-06-27 17:19:42 +03003196 err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003197 if (err)
3198 goto out;
3199
3200#ifdef CONFIG_CFG80211_WEXT
3201 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
3202#endif
3203 }
3204
3205 out:
Johannes Bergfffd0932009-07-08 14:22:54 +02003206 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003207
Johannes Berg41ade002007-12-19 02:03:29 +01003208 return err;
3209}
3210
3211static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
3212{
Johannes Berg4c476992010-10-04 21:36:35 +02003213 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfffd0932009-07-08 14:22:54 +02003214 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003215 struct net_device *dev = info->user_ptr[1];
Johannes Bergb9454e82009-07-08 13:29:08 +02003216 struct key_parse key;
Johannes Berge31b8212010-10-05 19:39:30 +02003217 const u8 *mac_addr = NULL;
Johannes Berg41ade002007-12-19 02:03:29 +01003218
Johannes Bergb9454e82009-07-08 13:29:08 +02003219 err = nl80211_parse_key(info, &key);
3220 if (err)
3221 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003222
Johannes Bergb9454e82009-07-08 13:29:08 +02003223 if (!key.p.key)
Johannes Berg41ade002007-12-19 02:03:29 +01003224 return -EINVAL;
3225
Johannes Berg41ade002007-12-19 02:03:29 +01003226 if (info->attrs[NL80211_ATTR_MAC])
3227 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3228
Johannes Berge31b8212010-10-05 19:39:30 +02003229 if (key.type == -1) {
3230 if (mac_addr)
3231 key.type = NL80211_KEYTYPE_PAIRWISE;
3232 else
3233 key.type = NL80211_KEYTYPE_GROUP;
3234 }
3235
3236 /* for now */
3237 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3238 key.type != NL80211_KEYTYPE_GROUP)
3239 return -EINVAL;
3240
Johannes Berg4c476992010-10-04 21:36:35 +02003241 if (!rdev->ops->add_key)
3242 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003243
Johannes Berge31b8212010-10-05 19:39:30 +02003244 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
3245 key.type == NL80211_KEYTYPE_PAIRWISE,
3246 mac_addr))
Johannes Berg4c476992010-10-04 21:36:35 +02003247 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02003248
3249 wdev_lock(dev->ieee80211_ptr);
3250 err = nl80211_key_allowed(dev->ieee80211_ptr);
3251 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003252 err = rdev_add_key(rdev, dev, key.idx,
3253 key.type == NL80211_KEYTYPE_PAIRWISE,
3254 mac_addr, &key.p);
Johannes Bergfffd0932009-07-08 14:22:54 +02003255 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003256
Johannes Berg41ade002007-12-19 02:03:29 +01003257 return err;
3258}
3259
3260static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
3261{
Johannes Berg4c476992010-10-04 21:36:35 +02003262 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003263 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003264 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003265 u8 *mac_addr = NULL;
Johannes Bergb9454e82009-07-08 13:29:08 +02003266 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003267
Johannes Bergb9454e82009-07-08 13:29:08 +02003268 err = nl80211_parse_key(info, &key);
3269 if (err)
3270 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003271
3272 if (info->attrs[NL80211_ATTR_MAC])
3273 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3274
Johannes Berge31b8212010-10-05 19:39:30 +02003275 if (key.type == -1) {
3276 if (mac_addr)
3277 key.type = NL80211_KEYTYPE_PAIRWISE;
3278 else
3279 key.type = NL80211_KEYTYPE_GROUP;
3280 }
3281
3282 /* for now */
3283 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3284 key.type != NL80211_KEYTYPE_GROUP)
3285 return -EINVAL;
3286
Johannes Berg4c476992010-10-04 21:36:35 +02003287 if (!rdev->ops->del_key)
3288 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003289
Johannes Bergfffd0932009-07-08 14:22:54 +02003290 wdev_lock(dev->ieee80211_ptr);
3291 err = nl80211_key_allowed(dev->ieee80211_ptr);
Johannes Berge31b8212010-10-05 19:39:30 +02003292
Johannes Berg0fa7b392015-01-23 11:10:12 +01003293 if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
Johannes Berge31b8212010-10-05 19:39:30 +02003294 !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3295 err = -ENOENT;
3296
Johannes Bergfffd0932009-07-08 14:22:54 +02003297 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003298 err = rdev_del_key(rdev, dev, key.idx,
3299 key.type == NL80211_KEYTYPE_PAIRWISE,
3300 mac_addr);
Johannes Berg41ade002007-12-19 02:03:29 +01003301
Johannes Berg3d23e342009-09-29 23:27:28 +02003302#ifdef CONFIG_CFG80211_WEXT
Johannes Berg08645122009-05-11 13:54:58 +02003303 if (!err) {
Johannes Bergb9454e82009-07-08 13:29:08 +02003304 if (key.idx == dev->ieee80211_ptr->wext.default_key)
Johannes Berg08645122009-05-11 13:54:58 +02003305 dev->ieee80211_ptr->wext.default_key = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02003306 else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
Johannes Berg08645122009-05-11 13:54:58 +02003307 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
3308 }
3309#endif
Johannes Bergfffd0932009-07-08 14:22:54 +02003310 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg08645122009-05-11 13:54:58 +02003311
Johannes Berg41ade002007-12-19 02:03:29 +01003312 return err;
3313}
3314
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05303315/* This function returns an error or the number of nested attributes */
3316static int validate_acl_mac_addrs(struct nlattr *nl_attr)
3317{
3318 struct nlattr *attr;
3319 int n_entries = 0, tmp;
3320
3321 nla_for_each_nested(attr, nl_attr, tmp) {
3322 if (nla_len(attr) != ETH_ALEN)
3323 return -EINVAL;
3324
3325 n_entries++;
3326 }
3327
3328 return n_entries;
3329}
3330
3331/*
3332 * This function parses ACL information and allocates memory for ACL data.
3333 * On successful return, the calling function is responsible to free the
3334 * ACL buffer returned by this function.
3335 */
3336static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
3337 struct genl_info *info)
3338{
3339 enum nl80211_acl_policy acl_policy;
3340 struct nlattr *attr;
3341 struct cfg80211_acl_data *acl;
3342 int i = 0, n_entries, tmp;
3343
3344 if (!wiphy->max_acl_mac_addrs)
3345 return ERR_PTR(-EOPNOTSUPP);
3346
3347 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
3348 return ERR_PTR(-EINVAL);
3349
3350 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
3351 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
3352 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
3353 return ERR_PTR(-EINVAL);
3354
3355 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
3356 return ERR_PTR(-EINVAL);
3357
3358 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
3359 if (n_entries < 0)
3360 return ERR_PTR(n_entries);
3361
3362 if (n_entries > wiphy->max_acl_mac_addrs)
3363 return ERR_PTR(-ENOTSUPP);
3364
3365 acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
3366 GFP_KERNEL);
3367 if (!acl)
3368 return ERR_PTR(-ENOMEM);
3369
3370 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
3371 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
3372 i++;
3373 }
3374
3375 acl->n_acl_entries = n_entries;
3376 acl->acl_policy = acl_policy;
3377
3378 return acl;
3379}
3380
3381static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
3382{
3383 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3384 struct net_device *dev = info->user_ptr[1];
3385 struct cfg80211_acl_data *acl;
3386 int err;
3387
3388 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3389 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3390 return -EOPNOTSUPP;
3391
3392 if (!dev->ieee80211_ptr->beacon_interval)
3393 return -EINVAL;
3394
3395 acl = parse_acl_data(&rdev->wiphy, info);
3396 if (IS_ERR(acl))
3397 return PTR_ERR(acl);
3398
3399 err = rdev_set_mac_acl(rdev, dev, acl);
3400
3401 kfree(acl);
3402
3403 return err;
3404}
3405
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303406static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
3407 u8 *rates, u8 rates_len)
3408{
3409 u8 i;
3410 u32 mask = 0;
3411
3412 for (i = 0; i < rates_len; i++) {
3413 int rate = (rates[i] & 0x7f) * 5;
3414 int ridx;
3415
3416 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
3417 struct ieee80211_rate *srate =
3418 &sband->bitrates[ridx];
3419 if (rate == srate->bitrate) {
3420 mask |= 1 << ridx;
3421 break;
3422 }
3423 }
3424 if (ridx == sband->n_bitrates)
3425 return 0; /* rate not found */
3426 }
3427
3428 return mask;
3429}
3430
3431static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
3432 u8 *rates, u8 rates_len,
3433 u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
3434{
3435 u8 i;
3436
3437 memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
3438
3439 for (i = 0; i < rates_len; i++) {
3440 int ridx, rbit;
3441
3442 ridx = rates[i] / 8;
3443 rbit = BIT(rates[i] % 8);
3444
3445 /* check validity */
3446 if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
3447 return false;
3448
3449 /* check availability */
3450 if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
3451 mcs[ridx] |= rbit;
3452 else
3453 return false;
3454 }
3455
3456 return true;
3457}
3458
3459static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
3460{
3461 u16 mcs_mask = 0;
3462
3463 switch (vht_mcs_map) {
3464 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
3465 break;
3466 case IEEE80211_VHT_MCS_SUPPORT_0_7:
3467 mcs_mask = 0x00FF;
3468 break;
3469 case IEEE80211_VHT_MCS_SUPPORT_0_8:
3470 mcs_mask = 0x01FF;
3471 break;
3472 case IEEE80211_VHT_MCS_SUPPORT_0_9:
3473 mcs_mask = 0x03FF;
3474 break;
3475 default:
3476 break;
3477 }
3478
3479 return mcs_mask;
3480}
3481
3482static void vht_build_mcs_mask(u16 vht_mcs_map,
3483 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
3484{
3485 u8 nss;
3486
3487 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
3488 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
3489 vht_mcs_map >>= 2;
3490 }
3491}
3492
3493static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
3494 struct nl80211_txrate_vht *txrate,
3495 u16 mcs[NL80211_VHT_NSS_MAX])
3496{
3497 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3498 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
3499 u8 i;
3500
3501 if (!sband->vht_cap.vht_supported)
3502 return false;
3503
3504 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
3505
3506 /* Build vht_mcs_mask from VHT capabilities */
3507 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
3508
3509 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
3510 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
3511 mcs[i] = txrate->mcs[i];
3512 else
3513 return false;
3514 }
3515
3516 return true;
3517}
3518
3519static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
3520 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
3521 .len = NL80211_MAX_SUPP_RATES },
3522 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
3523 .len = NL80211_MAX_SUPP_HT_RATES },
3524 [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
3525 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
3526};
3527
3528static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
3529 struct cfg80211_bitrate_mask *mask)
3530{
3531 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
3532 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3533 int rem, i;
3534 struct nlattr *tx_rates;
3535 struct ieee80211_supported_band *sband;
3536 u16 vht_tx_mcs_map;
3537
3538 memset(mask, 0, sizeof(*mask));
3539 /* Default to all rates enabled */
3540 for (i = 0; i < NUM_NL80211_BANDS; i++) {
3541 sband = rdev->wiphy.bands[i];
3542
3543 if (!sband)
3544 continue;
3545
3546 mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
3547 memcpy(mask->control[i].ht_mcs,
3548 sband->ht_cap.mcs.rx_mask,
3549 sizeof(mask->control[i].ht_mcs));
3550
3551 if (!sband->vht_cap.vht_supported)
3552 continue;
3553
3554 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3555 vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
3556 }
3557
3558 /* if no rates are given set it back to the defaults */
3559 if (!info->attrs[NL80211_ATTR_TX_RATES])
3560 goto out;
3561
3562 /* The nested attribute uses enum nl80211_band as the index. This maps
3563 * directly to the enum nl80211_band values used in cfg80211.
3564 */
3565 BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
3566 nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
3567 enum nl80211_band band = nla_type(tx_rates);
3568 int err;
3569
3570 if (band < 0 || band >= NUM_NL80211_BANDS)
3571 return -EINVAL;
3572 sband = rdev->wiphy.bands[band];
3573 if (sband == NULL)
3574 return -EINVAL;
3575 err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
3576 nla_len(tx_rates), nl80211_txattr_policy);
3577 if (err)
3578 return err;
3579 if (tb[NL80211_TXRATE_LEGACY]) {
3580 mask->control[band].legacy = rateset_to_mask(
3581 sband,
3582 nla_data(tb[NL80211_TXRATE_LEGACY]),
3583 nla_len(tb[NL80211_TXRATE_LEGACY]));
3584 if ((mask->control[band].legacy == 0) &&
3585 nla_len(tb[NL80211_TXRATE_LEGACY]))
3586 return -EINVAL;
3587 }
3588 if (tb[NL80211_TXRATE_HT]) {
3589 if (!ht_rateset_to_mask(
3590 sband,
3591 nla_data(tb[NL80211_TXRATE_HT]),
3592 nla_len(tb[NL80211_TXRATE_HT]),
3593 mask->control[band].ht_mcs))
3594 return -EINVAL;
3595 }
3596 if (tb[NL80211_TXRATE_VHT]) {
3597 if (!vht_set_mcs_mask(
3598 sband,
3599 nla_data(tb[NL80211_TXRATE_VHT]),
3600 mask->control[band].vht_mcs))
3601 return -EINVAL;
3602 }
3603 if (tb[NL80211_TXRATE_GI]) {
3604 mask->control[band].gi =
3605 nla_get_u8(tb[NL80211_TXRATE_GI]);
3606 if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
3607 return -EINVAL;
3608 }
3609
3610 if (mask->control[band].legacy == 0) {
3611 /* don't allow empty legacy rates if HT or VHT
3612 * are not even supported.
3613 */
3614 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
3615 rdev->wiphy.bands[band]->vht_cap.vht_supported))
3616 return -EINVAL;
3617
3618 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
3619 if (mask->control[band].ht_mcs[i])
3620 goto out;
3621
3622 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
3623 if (mask->control[band].vht_mcs[i])
3624 goto out;
3625
3626 /* legacy and mcs rates may not be both empty */
3627 return -EINVAL;
3628 }
3629 }
3630
3631out:
3632 return 0;
3633}
3634
Johannes Berg8564e382016-09-19 09:44:44 +02003635static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
3636 enum nl80211_band band,
3637 struct cfg80211_bitrate_mask *beacon_rate)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303638{
Johannes Berg8564e382016-09-19 09:44:44 +02003639 u32 count_ht, count_vht, i;
3640 u32 rate = beacon_rate->control[band].legacy;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303641
3642 /* Allow only one rate */
3643 if (hweight32(rate) > 1)
3644 return -EINVAL;
3645
3646 count_ht = 0;
3647 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003648 if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303649 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003650 } else if (beacon_rate->control[band].ht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303651 count_ht++;
3652 if (count_ht > 1)
3653 return -EINVAL;
3654 }
3655 if (count_ht && rate)
3656 return -EINVAL;
3657 }
3658
3659 count_vht = 0;
3660 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003661 if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303662 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003663 } else if (beacon_rate->control[band].vht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303664 count_vht++;
3665 if (count_vht > 1)
3666 return -EINVAL;
3667 }
3668 if (count_vht && rate)
3669 return -EINVAL;
3670 }
3671
3672 if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
3673 return -EINVAL;
3674
Johannes Berg8564e382016-09-19 09:44:44 +02003675 if (rate &&
3676 !wiphy_ext_feature_isset(&rdev->wiphy,
3677 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
3678 return -EINVAL;
3679 if (count_ht &&
3680 !wiphy_ext_feature_isset(&rdev->wiphy,
3681 NL80211_EXT_FEATURE_BEACON_RATE_HT))
3682 return -EINVAL;
3683 if (count_vht &&
3684 !wiphy_ext_feature_isset(&rdev->wiphy,
3685 NL80211_EXT_FEATURE_BEACON_RATE_VHT))
3686 return -EINVAL;
3687
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303688 return 0;
3689}
3690
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003691static int nl80211_parse_beacon(struct nlattr *attrs[],
Johannes Berg88600202012-02-13 15:17:18 +01003692 struct cfg80211_beacon_data *bcn)
Johannes Berged1b6cc2007-12-19 02:03:32 +01003693{
Johannes Berg88600202012-02-13 15:17:18 +01003694 bool haveinfo = false;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003695
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003696 if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
3697 !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
3698 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
3699 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
Johannes Bergf4a11bb2009-03-27 12:40:28 +01003700 return -EINVAL;
3701
Johannes Berg88600202012-02-13 15:17:18 +01003702 memset(bcn, 0, sizeof(*bcn));
Johannes Berged1b6cc2007-12-19 02:03:32 +01003703
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003704 if (attrs[NL80211_ATTR_BEACON_HEAD]) {
3705 bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
3706 bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
Johannes Berg88600202012-02-13 15:17:18 +01003707 if (!bcn->head_len)
3708 return -EINVAL;
3709 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003710 }
3711
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003712 if (attrs[NL80211_ATTR_BEACON_TAIL]) {
3713 bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
3714 bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
Johannes Berg88600202012-02-13 15:17:18 +01003715 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003716 }
3717
Johannes Berg4c476992010-10-04 21:36:35 +02003718 if (!haveinfo)
3719 return -EINVAL;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003720
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003721 if (attrs[NL80211_ATTR_IE]) {
3722 bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
3723 bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003724 }
3725
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003726 if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003727 bcn->proberesp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003728 nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003729 bcn->proberesp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003730 nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003731 }
3732
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003733 if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003734 bcn->assocresp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003735 nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003736 bcn->assocresp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003737 nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003738 }
3739
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003740 if (attrs[NL80211_ATTR_PROBE_RESP]) {
3741 bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
3742 bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
Arik Nemtsov00f740e2011-11-10 11:28:56 +02003743 }
3744
Johannes Berg88600202012-02-13 15:17:18 +01003745 return 0;
3746}
3747
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003748static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
3749 struct cfg80211_ap_settings *params)
3750{
3751 struct wireless_dev *wdev;
3752 bool ret = false;
3753
Johannes Berg53873f12016-05-03 16:52:04 +03003754 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003755 if (wdev->iftype != NL80211_IFTYPE_AP &&
3756 wdev->iftype != NL80211_IFTYPE_P2P_GO)
3757 continue;
3758
Johannes Berg683b6d32012-11-08 21:25:48 +01003759 if (!wdev->preset_chandef.chan)
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003760 continue;
3761
Johannes Berg683b6d32012-11-08 21:25:48 +01003762 params->chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003763 ret = true;
3764 break;
3765 }
3766
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003767 return ret;
3768}
3769
Jouni Malinene39e5b52012-09-30 19:29:39 +03003770static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
3771 enum nl80211_auth_type auth_type,
3772 enum nl80211_commands cmd)
3773{
3774 if (auth_type > NL80211_AUTHTYPE_MAX)
3775 return false;
3776
3777 switch (cmd) {
3778 case NL80211_CMD_AUTHENTICATE:
3779 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
3780 auth_type == NL80211_AUTHTYPE_SAE)
3781 return false;
Jouni Malinene20f90f2016-10-27 00:42:02 +03003782 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3783 NL80211_EXT_FEATURE_FILS_STA) &&
3784 (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3785 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3786 auth_type == NL80211_AUTHTYPE_FILS_PK))
3787 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003788 return true;
3789 case NL80211_CMD_CONNECT:
Vidyullatha Kanchanapally36eabf62017-03-31 00:22:34 +03003790 /* SAE not supported yet */
3791 if (auth_type == NL80211_AUTHTYPE_SAE)
3792 return false;
3793 /* FILS with SK PFS or PK not supported yet */
3794 if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3795 auth_type == NL80211_AUTHTYPE_FILS_PK)
3796 return false;
3797 if (!wiphy_ext_feature_isset(
3798 &rdev->wiphy,
3799 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
3800 auth_type == NL80211_AUTHTYPE_FILS_SK)
3801 return false;
3802 return true;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003803 case NL80211_CMD_START_AP:
3804 /* SAE not supported yet */
3805 if (auth_type == NL80211_AUTHTYPE_SAE)
3806 return false;
Jouni Malinene20f90f2016-10-27 00:42:02 +03003807 /* FILS not supported yet */
3808 if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3809 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3810 auth_type == NL80211_AUTHTYPE_FILS_PK)
3811 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003812 return true;
3813 default:
3814 return false;
3815 }
3816}
3817
Johannes Berg88600202012-02-13 15:17:18 +01003818static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
3819{
3820 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3821 struct net_device *dev = info->user_ptr[1];
3822 struct wireless_dev *wdev = dev->ieee80211_ptr;
3823 struct cfg80211_ap_settings params;
3824 int err;
3825
3826 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3827 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3828 return -EOPNOTSUPP;
3829
3830 if (!rdev->ops->start_ap)
3831 return -EOPNOTSUPP;
3832
3833 if (wdev->beacon_interval)
3834 return -EALREADY;
3835
3836 memset(&params, 0, sizeof(params));
3837
3838 /* these are required for START_AP */
3839 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
3840 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
3841 !info->attrs[NL80211_ATTR_BEACON_HEAD])
3842 return -EINVAL;
3843
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003844 err = nl80211_parse_beacon(info->attrs, &params.beacon);
Johannes Berg88600202012-02-13 15:17:18 +01003845 if (err)
3846 return err;
3847
3848 params.beacon_interval =
3849 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
3850 params.dtim_period =
3851 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
3852
Purushottam Kushwahac6800ff2016-10-12 18:26:51 +05303853 err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
3854 params.beacon_interval);
Johannes Berg88600202012-02-13 15:17:18 +01003855 if (err)
3856 return err;
3857
3858 /*
3859 * In theory, some of these attributes should be required here
3860 * but since they were not used when the command was originally
3861 * added, keep them optional for old user space programs to let
3862 * them continue to work with drivers that do not need the
3863 * additional information -- drivers must check!
3864 */
3865 if (info->attrs[NL80211_ATTR_SSID]) {
3866 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3867 params.ssid_len =
3868 nla_len(info->attrs[NL80211_ATTR_SSID]);
3869 if (params.ssid_len == 0 ||
3870 params.ssid_len > IEEE80211_MAX_SSID_LEN)
3871 return -EINVAL;
3872 }
3873
3874 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
3875 params.hidden_ssid = nla_get_u32(
3876 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
3877 if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
3878 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
3879 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
3880 return -EINVAL;
3881 }
3882
3883 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
3884
3885 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
3886 params.auth_type = nla_get_u32(
3887 info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03003888 if (!nl80211_valid_auth_type(rdev, params.auth_type,
3889 NL80211_CMD_START_AP))
Johannes Berg88600202012-02-13 15:17:18 +01003890 return -EINVAL;
3891 } else
3892 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
3893
3894 err = nl80211_crypto_settings(rdev, info, &params.crypto,
3895 NL80211_MAX_NR_CIPHER_SUITES);
3896 if (err)
3897 return err;
3898
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05303899 if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
3900 if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
3901 return -EOPNOTSUPP;
3902 params.inactivity_timeout = nla_get_u16(
3903 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
3904 }
3905
Johannes Berg53cabad2012-11-14 15:17:28 +01003906 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
3907 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3908 return -EINVAL;
3909 params.p2p_ctwindow =
3910 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
3911 if (params.p2p_ctwindow > 127)
3912 return -EINVAL;
3913 if (params.p2p_ctwindow != 0 &&
3914 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
3915 return -EINVAL;
3916 }
3917
3918 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
3919 u8 tmp;
3920
3921 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3922 return -EINVAL;
3923 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
3924 if (tmp > 1)
3925 return -EINVAL;
3926 params.p2p_opp_ps = tmp;
3927 if (params.p2p_opp_ps != 0 &&
3928 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
3929 return -EINVAL;
3930 }
3931
Johannes Bergaa430da2012-05-16 23:50:18 +02003932 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01003933 err = nl80211_parse_chandef(rdev, info, &params.chandef);
3934 if (err)
3935 return err;
3936 } else if (wdev->preset_chandef.chan) {
3937 params.chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003938 } else if (!nl80211_get_ap_channel(rdev, &params))
Johannes Bergaa430da2012-05-16 23:50:18 +02003939 return -EINVAL;
3940
Arik Nemtsov923b3522015-07-08 15:41:44 +03003941 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
3942 wdev->iftype))
Johannes Bergaa430da2012-05-16 23:50:18 +02003943 return -EINVAL;
3944
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303945 if (info->attrs[NL80211_ATTR_TX_RATES]) {
3946 err = nl80211_parse_tx_bitrate_mask(info, &params.beacon_rate);
3947 if (err)
3948 return err;
3949
Johannes Berg8564e382016-09-19 09:44:44 +02003950 err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
3951 &params.beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303952 if (err)
3953 return err;
3954 }
3955
Eliad Peller18998c32014-09-10 14:07:34 +03003956 if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
3957 params.smps_mode =
3958 nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
3959 switch (params.smps_mode) {
3960 case NL80211_SMPS_OFF:
3961 break;
3962 case NL80211_SMPS_STATIC:
3963 if (!(rdev->wiphy.features &
3964 NL80211_FEATURE_STATIC_SMPS))
3965 return -EINVAL;
3966 break;
3967 case NL80211_SMPS_DYNAMIC:
3968 if (!(rdev->wiphy.features &
3969 NL80211_FEATURE_DYNAMIC_SMPS))
3970 return -EINVAL;
3971 break;
3972 default:
3973 return -EINVAL;
3974 }
3975 } else {
3976 params.smps_mode = NL80211_SMPS_OFF;
3977 }
3978
Purushottam Kushwaha6e8ef842016-07-05 13:44:51 +05303979 params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
3980 if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
3981 return -EOPNOTSUPP;
3982
Ola Olsson4baf6be2015-10-29 07:04:58 +01003983 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
3984 params.acl = parse_acl_data(&rdev->wiphy, info);
3985 if (IS_ERR(params.acl))
3986 return PTR_ERR(params.acl);
3987 }
3988
Simon Wunderlichc56589e2013-11-21 18:19:49 +01003989 wdev_lock(wdev);
Hila Gonene35e4d22012-06-27 17:19:42 +03003990 err = rdev_start_ap(rdev, dev, &params);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003991 if (!err) {
Johannes Berg683b6d32012-11-08 21:25:48 +01003992 wdev->preset_chandef = params.chandef;
Johannes Berg88600202012-02-13 15:17:18 +01003993 wdev->beacon_interval = params.beacon_interval;
Michal Kazior9e0e2962014-01-29 14:22:27 +01003994 wdev->chandef = params.chandef;
Antonio Quartulli06e191e2012-11-07 12:52:19 +01003995 wdev->ssid_len = params.ssid_len;
3996 memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003997 }
Simon Wunderlichc56589e2013-11-21 18:19:49 +01003998 wdev_unlock(wdev);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05303999
4000 kfree(params.acl);
4001
Johannes Berg56d18932011-05-09 18:41:15 +02004002 return err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004003}
4004
Johannes Berg88600202012-02-13 15:17:18 +01004005static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
4006{
4007 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4008 struct net_device *dev = info->user_ptr[1];
4009 struct wireless_dev *wdev = dev->ieee80211_ptr;
4010 struct cfg80211_beacon_data params;
4011 int err;
4012
4013 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4014 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4015 return -EOPNOTSUPP;
4016
4017 if (!rdev->ops->change_beacon)
4018 return -EOPNOTSUPP;
4019
4020 if (!wdev->beacon_interval)
4021 return -EINVAL;
4022
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004023 err = nl80211_parse_beacon(info->attrs, &params);
Johannes Berg88600202012-02-13 15:17:18 +01004024 if (err)
4025 return err;
4026
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004027 wdev_lock(wdev);
4028 err = rdev_change_beacon(rdev, dev, &params);
4029 wdev_unlock(wdev);
4030
4031 return err;
Johannes Berg88600202012-02-13 15:17:18 +01004032}
4033
4034static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
Johannes Berged1b6cc2007-12-19 02:03:32 +01004035{
Johannes Berg4c476992010-10-04 21:36:35 +02004036 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4037 struct net_device *dev = info->user_ptr[1];
Johannes Berged1b6cc2007-12-19 02:03:32 +01004038
Ilan Peer7c8d5e02014-02-25 15:33:38 +02004039 return cfg80211_stop_ap(rdev, dev, false);
Johannes Berged1b6cc2007-12-19 02:03:32 +01004040}
4041
Johannes Berg5727ef12007-12-19 02:03:34 +01004042static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
4043 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
4044 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
4045 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
Jouni Malinen0e467242009-05-11 21:57:55 +03004046 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
Javier Cardonab39c48f2011-04-07 15:08:30 -07004047 [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
Johannes Bergd83023d2011-12-14 09:29:15 +01004048 [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
Johannes Berg5727ef12007-12-19 02:03:34 +01004049};
4050
Johannes Bergeccb8e82009-05-11 21:57:56 +03004051static int parse_station_flags(struct genl_info *info,
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004052 enum nl80211_iftype iftype,
Johannes Bergeccb8e82009-05-11 21:57:56 +03004053 struct station_parameters *params)
Johannes Berg5727ef12007-12-19 02:03:34 +01004054{
4055 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
Johannes Bergeccb8e82009-05-11 21:57:56 +03004056 struct nlattr *nla;
Johannes Berg5727ef12007-12-19 02:03:34 +01004057 int flag;
4058
Johannes Bergeccb8e82009-05-11 21:57:56 +03004059 /*
4060 * Try parsing the new attribute first so userspace
4061 * can specify both for older kernels.
4062 */
4063 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
4064 if (nla) {
4065 struct nl80211_sta_flag_update *sta_flags;
Johannes Berg5727ef12007-12-19 02:03:34 +01004066
Johannes Bergeccb8e82009-05-11 21:57:56 +03004067 sta_flags = nla_data(nla);
4068 params->sta_flags_mask = sta_flags->mask;
4069 params->sta_flags_set = sta_flags->set;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004070 params->sta_flags_set &= params->sta_flags_mask;
Johannes Bergeccb8e82009-05-11 21:57:56 +03004071 if ((params->sta_flags_mask |
4072 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
4073 return -EINVAL;
4074 return 0;
4075 }
4076
4077 /* if present, parse the old attribute */
4078
4079 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
Johannes Berg5727ef12007-12-19 02:03:34 +01004080 if (!nla)
4081 return 0;
4082
4083 if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
4084 nla, sta_flags_policy))
4085 return -EINVAL;
4086
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004087 /*
4088 * Only allow certain flags for interface types so that
4089 * other attributes are silently ignored. Remember that
4090 * this is backward compatibility code with old userspace
4091 * and shouldn't be hit in other cases anyway.
4092 */
4093 switch (iftype) {
4094 case NL80211_IFTYPE_AP:
4095 case NL80211_IFTYPE_AP_VLAN:
4096 case NL80211_IFTYPE_P2P_GO:
4097 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4098 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4099 BIT(NL80211_STA_FLAG_WME) |
4100 BIT(NL80211_STA_FLAG_MFP);
4101 break;
4102 case NL80211_IFTYPE_P2P_CLIENT:
4103 case NL80211_IFTYPE_STATION:
4104 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4105 BIT(NL80211_STA_FLAG_TDLS_PEER);
4106 break;
4107 case NL80211_IFTYPE_MESH_POINT:
4108 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4109 BIT(NL80211_STA_FLAG_MFP) |
4110 BIT(NL80211_STA_FLAG_AUTHORIZED);
4111 default:
4112 return -EINVAL;
4113 }
Johannes Berg5727ef12007-12-19 02:03:34 +01004114
Johannes Berg3383b5a2012-05-10 20:14:43 +02004115 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
4116 if (flags[flag]) {
Johannes Bergeccb8e82009-05-11 21:57:56 +03004117 params->sta_flags_set |= (1<<flag);
Johannes Berg5727ef12007-12-19 02:03:34 +01004118
Johannes Berg3383b5a2012-05-10 20:14:43 +02004119 /* no longer support new API additions in old API */
4120 if (flag > NL80211_STA_FLAG_MAX_OLD_API)
4121 return -EINVAL;
4122 }
4123 }
4124
Johannes Berg5727ef12007-12-19 02:03:34 +01004125 return 0;
4126}
4127
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004128static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
4129 int attr)
4130{
4131 struct nlattr *rate;
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004132 u32 bitrate;
4133 u16 bitrate_compat;
Johannes Bergb51f3be2015-01-15 16:14:02 +01004134 enum nl80211_attrs rate_flg;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004135
4136 rate = nla_nest_start(msg, attr);
4137 if (!rate)
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004138 return false;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004139
4140 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
4141 bitrate = cfg80211_calculate_bitrate(info);
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004142 /* report 16-bit bitrate only if we can */
4143 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004144 if (bitrate > 0 &&
4145 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
4146 return false;
4147 if (bitrate_compat > 0 &&
4148 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
4149 return false;
4150
Johannes Bergb51f3be2015-01-15 16:14:02 +01004151 switch (info->bw) {
4152 case RATE_INFO_BW_5:
4153 rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
4154 break;
4155 case RATE_INFO_BW_10:
4156 rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
4157 break;
4158 default:
4159 WARN_ON(1);
4160 /* fall through */
4161 case RATE_INFO_BW_20:
4162 rate_flg = 0;
4163 break;
4164 case RATE_INFO_BW_40:
4165 rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
4166 break;
4167 case RATE_INFO_BW_80:
4168 rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
4169 break;
4170 case RATE_INFO_BW_160:
4171 rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
4172 break;
4173 }
4174
4175 if (rate_flg && nla_put_flag(msg, rate_flg))
4176 return false;
4177
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004178 if (info->flags & RATE_INFO_FLAGS_MCS) {
4179 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
4180 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004181 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4182 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4183 return false;
4184 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
4185 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
4186 return false;
4187 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
4188 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004189 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4190 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4191 return false;
4192 }
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004193
4194 nla_nest_end(msg, rate);
4195 return true;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004196}
4197
Felix Fietkau119363c2013-04-22 16:29:30 +02004198static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
4199 int id)
4200{
4201 void *attr;
4202 int i = 0;
4203
4204 if (!mask)
4205 return true;
4206
4207 attr = nla_nest_start(msg, id);
4208 if (!attr)
4209 return false;
4210
4211 for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
4212 if (!(mask & BIT(i)))
4213 continue;
4214
4215 if (nla_put_u8(msg, i, signal[i]))
4216 return false;
4217 }
4218
4219 nla_nest_end(msg, attr);
4220
4221 return true;
4222}
4223
Johannes Bergcf5ead82014-11-14 17:14:00 +01004224static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
4225 u32 seq, int flags,
John W. Linville66266b32012-03-15 13:25:41 -04004226 struct cfg80211_registered_device *rdev,
4227 struct net_device *dev,
Johannes Berg98b62182009-12-23 13:15:44 +01004228 const u8 *mac_addr, struct station_info *sinfo)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004229{
4230 void *hdr;
Paul Stewartf4263c92011-03-31 09:25:41 -07004231 struct nlattr *sinfoattr, *bss_param;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004232
Johannes Bergcf5ead82014-11-14 17:14:00 +01004233 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004234 if (!hdr)
4235 return -1;
4236
David S. Miller9360ffd2012-03-29 04:41:26 -04004237 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
4238 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
4239 nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
4240 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02004241
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004242 sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
4243 if (!sinfoattr)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004244 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004245
4246#define PUT_SINFO(attr, memb, type) do { \
Johannes Bergd686b922016-04-26 09:54:11 +02004247 BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
Mohammed Shafi Shajakhan739960f2016-04-07 19:59:34 +05304248 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
Johannes Berg319090b2014-11-17 14:08:11 +01004249 nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
4250 sinfo->memb)) \
4251 goto nla_put_failure; \
4252 } while (0)
Johannes Bergd686b922016-04-26 09:54:11 +02004253#define PUT_SINFO_U64(attr, memb) do { \
4254 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
4255 nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
4256 sinfo->memb, NL80211_STA_INFO_PAD)) \
4257 goto nla_put_failure; \
4258 } while (0)
Johannes Berg319090b2014-11-17 14:08:11 +01004259
4260 PUT_SINFO(CONNECTED_TIME, connected_time, u32);
4261 PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
4262
4263 if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
4264 BIT(NL80211_STA_INFO_RX_BYTES64)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004265 nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004266 (u32)sinfo->rx_bytes))
4267 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004268
4269 if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
4270 BIT(NL80211_STA_INFO_TX_BYTES64)) &&
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004271 nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
4272 (u32)sinfo->tx_bytes))
4273 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004274
Johannes Bergd686b922016-04-26 09:54:11 +02004275 PUT_SINFO_U64(RX_BYTES64, rx_bytes);
4276 PUT_SINFO_U64(TX_BYTES64, tx_bytes);
Johannes Berg319090b2014-11-17 14:08:11 +01004277 PUT_SINFO(LLID, llid, u16);
4278 PUT_SINFO(PLID, plid, u16);
4279 PUT_SINFO(PLINK_STATE, plink_state, u8);
Johannes Bergd686b922016-04-26 09:54:11 +02004280 PUT_SINFO_U64(RX_DURATION, rx_duration);
Johannes Berg319090b2014-11-17 14:08:11 +01004281
John W. Linville66266b32012-03-15 13:25:41 -04004282 switch (rdev->wiphy.signal_type) {
4283 case CFG80211_SIGNAL_TYPE_MBM:
Johannes Berg319090b2014-11-17 14:08:11 +01004284 PUT_SINFO(SIGNAL, signal, u8);
4285 PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
John W. Linville66266b32012-03-15 13:25:41 -04004286 break;
4287 default:
4288 break;
4289 }
Johannes Berg319090b2014-11-17 14:08:11 +01004290 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004291 if (!nl80211_put_signal(msg, sinfo->chains,
4292 sinfo->chain_signal,
4293 NL80211_STA_INFO_CHAIN_SIGNAL))
4294 goto nla_put_failure;
4295 }
Johannes Berg319090b2014-11-17 14:08:11 +01004296 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004297 if (!nl80211_put_signal(msg, sinfo->chains,
4298 sinfo->chain_signal_avg,
4299 NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
4300 goto nla_put_failure;
4301 }
Johannes Berg319090b2014-11-17 14:08:11 +01004302 if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004303 if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
4304 NL80211_STA_INFO_TX_BITRATE))
Henning Rogge420e7fa2008-12-11 22:04:19 +01004305 goto nla_put_failure;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004306 }
Johannes Berg319090b2014-11-17 14:08:11 +01004307 if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004308 if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
4309 NL80211_STA_INFO_RX_BITRATE))
4310 goto nla_put_failure;
Henning Rogge420e7fa2008-12-11 22:04:19 +01004311 }
Johannes Berg319090b2014-11-17 14:08:11 +01004312
4313 PUT_SINFO(RX_PACKETS, rx_packets, u32);
4314 PUT_SINFO(TX_PACKETS, tx_packets, u32);
4315 PUT_SINFO(TX_RETRIES, tx_retries, u32);
4316 PUT_SINFO(TX_FAILED, tx_failed, u32);
4317 PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
4318 PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
4319 PUT_SINFO(LOCAL_PM, local_pm, u32);
4320 PUT_SINFO(PEER_PM, peer_pm, u32);
4321 PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
4322
4323 if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
Paul Stewartf4263c92011-03-31 09:25:41 -07004324 bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
4325 if (!bss_param)
4326 goto nla_put_failure;
4327
David S. Miller9360ffd2012-03-29 04:41:26 -04004328 if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
4329 nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
4330 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
4331 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
4332 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
4333 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
4334 nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
4335 sinfo->bss_param.dtim_period) ||
4336 nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
4337 sinfo->bss_param.beacon_interval))
4338 goto nla_put_failure;
Paul Stewartf4263c92011-03-31 09:25:41 -07004339
4340 nla_nest_end(msg, bss_param);
4341 }
Johannes Berg319090b2014-11-17 14:08:11 +01004342 if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004343 nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
4344 sizeof(struct nl80211_sta_flag_update),
4345 &sinfo->sta_flags))
4346 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004347
Johannes Bergd686b922016-04-26 09:54:11 +02004348 PUT_SINFO_U64(T_OFFSET, t_offset);
4349 PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
4350 PUT_SINFO_U64(BEACON_RX, rx_beacon);
Johannes Berga76b1942014-11-17 14:12:22 +01004351 PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
Johannes Berg319090b2014-11-17 14:08:11 +01004352
4353#undef PUT_SINFO
Johannes Bergd686b922016-04-26 09:54:11 +02004354#undef PUT_SINFO_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004355
4356 if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
4357 struct nlattr *tidsattr;
4358 int tid;
4359
4360 tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS);
4361 if (!tidsattr)
4362 goto nla_put_failure;
4363
4364 for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
4365 struct cfg80211_tid_stats *tidstats;
4366 struct nlattr *tidattr;
4367
4368 tidstats = &sinfo->pertid[tid];
4369
4370 if (!tidstats->filled)
4371 continue;
4372
4373 tidattr = nla_nest_start(msg, tid + 1);
4374 if (!tidattr)
4375 goto nla_put_failure;
4376
Johannes Bergd686b922016-04-26 09:54:11 +02004377#define PUT_TIDVAL_U64(attr, memb) do { \
Johannes Berg6de39802014-12-19 12:34:00 +01004378 if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02004379 nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
4380 tidstats->memb, NL80211_TID_STATS_PAD)) \
Johannes Berg6de39802014-12-19 12:34:00 +01004381 goto nla_put_failure; \
4382 } while (0)
4383
Johannes Bergd686b922016-04-26 09:54:11 +02004384 PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
4385 PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
4386 PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
4387 PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
Johannes Berg6de39802014-12-19 12:34:00 +01004388
Johannes Bergd686b922016-04-26 09:54:11 +02004389#undef PUT_TIDVAL_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004390 nla_nest_end(msg, tidattr);
4391 }
4392
4393 nla_nest_end(msg, tidsattr);
4394 }
4395
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004396 nla_nest_end(msg, sinfoattr);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004397
Johannes Berg319090b2014-11-17 14:08:11 +01004398 if (sinfo->assoc_req_ies_len &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004399 nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
4400 sinfo->assoc_req_ies))
4401 goto nla_put_failure;
Jouni Malinen50d3dfb2011-08-08 12:11:52 +03004402
Johannes Berg053c0952015-01-16 22:09:00 +01004403 genlmsg_end(msg, hdr);
4404 return 0;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004405
4406 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07004407 genlmsg_cancel(msg, hdr);
4408 return -EMSGSIZE;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004409}
4410
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004411static int nl80211_dump_station(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004412 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004413{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004414 struct station_info sinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004415 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02004416 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004417 u8 mac_addr[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02004418 int sta_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004419 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004420
Johannes Berg56769e72017-03-15 14:26:04 +01004421 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004422 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02004423 if (err)
Johannes Berg56769e72017-03-15 14:26:04 +01004424 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004425
Johannes Berg97990a02013-04-19 01:02:55 +02004426 if (!wdev->netdev) {
4427 err = -EINVAL;
4428 goto out_err;
4429 }
4430
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004431 if (!rdev->ops->dump_station) {
Jouni Malineneec60b02009-03-20 21:21:19 +02004432 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004433 goto out_err;
4434 }
4435
Johannes Bergbba95fe2008-07-29 13:22:51 +02004436 while (1) {
Jouni Malinenf612ced2011-08-11 11:46:22 +03004437 memset(&sinfo, 0, sizeof(sinfo));
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004438 err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
Hila Gonene35e4d22012-06-27 17:19:42 +03004439 mac_addr, &sinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004440 if (err == -ENOENT)
4441 break;
4442 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01004443 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004444
Johannes Bergcf5ead82014-11-14 17:14:00 +01004445 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004446 NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004447 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004448 rdev, wdev->netdev, mac_addr,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004449 &sinfo) < 0)
4450 goto out;
4451
4452 sta_idx++;
4453 }
4454
Johannes Bergbba95fe2008-07-29 13:22:51 +02004455 out:
Johannes Berg97990a02013-04-19 01:02:55 +02004456 cb->args[2] = sta_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004457 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004458 out_err:
Johannes Berg56769e72017-03-15 14:26:04 +01004459 rtnl_unlock();
Johannes Bergbba95fe2008-07-29 13:22:51 +02004460
4461 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004462}
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004463
Johannes Berg5727ef12007-12-19 02:03:34 +01004464static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
4465{
Johannes Berg4c476992010-10-04 21:36:35 +02004466 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4467 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004468 struct station_info sinfo;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004469 struct sk_buff *msg;
4470 u8 *mac_addr = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02004471 int err;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004472
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004473 memset(&sinfo, 0, sizeof(sinfo));
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004474
4475 if (!info->attrs[NL80211_ATTR_MAC])
4476 return -EINVAL;
4477
4478 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4479
Johannes Berg4c476992010-10-04 21:36:35 +02004480 if (!rdev->ops->get_station)
4481 return -EOPNOTSUPP;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004482
Hila Gonene35e4d22012-06-27 17:19:42 +03004483 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004484 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02004485 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004486
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07004487 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004488 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02004489 return -ENOMEM;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004490
Johannes Bergcf5ead82014-11-14 17:14:00 +01004491 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
4492 info->snd_portid, info->snd_seq, 0,
John W. Linville66266b32012-03-15 13:25:41 -04004493 rdev, dev, mac_addr, &sinfo) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02004494 nlmsg_free(msg);
4495 return -ENOBUFS;
4496 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004497
Johannes Berg4c476992010-10-04 21:36:35 +02004498 return genlmsg_reply(msg, info);
Johannes Berg5727ef12007-12-19 02:03:34 +01004499}
4500
Johannes Berg77ee7c82013-02-15 00:48:33 +01004501int cfg80211_check_station_change(struct wiphy *wiphy,
4502 struct station_parameters *params,
4503 enum cfg80211_station_type statype)
4504{
Ayala Bekere4208422015-10-23 11:20:06 +03004505 if (params->listen_interval != -1 &&
4506 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004507 return -EINVAL;
Ayala Bekere4208422015-10-23 11:20:06 +03004508
Ayala Beker17b94242016-03-17 15:41:38 +02004509 if (params->support_p2p_ps != -1 &&
4510 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
4511 return -EINVAL;
4512
Arik Nemtsovc72e1142014-07-17 17:14:29 +03004513 if (params->aid &&
Ayala Bekere4208422015-10-23 11:20:06 +03004514 !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
4515 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004516 return -EINVAL;
4517
4518 /* When you run into this, adjust the code below for the new flag */
4519 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
4520
4521 switch (statype) {
Thomas Pederseneef941e2013-03-04 13:06:11 -08004522 case CFG80211_STA_MESH_PEER_KERNEL:
4523 case CFG80211_STA_MESH_PEER_USER:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004524 /*
4525 * No ignoring the TDLS flag here -- the userspace mesh
4526 * code doesn't have the bug of including TDLS in the
4527 * mask everywhere.
4528 */
4529 if (params->sta_flags_mask &
4530 ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4531 BIT(NL80211_STA_FLAG_MFP) |
4532 BIT(NL80211_STA_FLAG_AUTHORIZED)))
4533 return -EINVAL;
4534 break;
4535 case CFG80211_STA_TDLS_PEER_SETUP:
4536 case CFG80211_STA_TDLS_PEER_ACTIVE:
4537 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
4538 return -EINVAL;
4539 /* ignore since it can't change */
4540 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4541 break;
4542 default:
4543 /* disallow mesh-specific things */
4544 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
4545 return -EINVAL;
4546 if (params->local_pm)
4547 return -EINVAL;
4548 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4549 return -EINVAL;
4550 }
4551
4552 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4553 statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
4554 /* TDLS can't be set, ... */
4555 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
4556 return -EINVAL;
4557 /*
4558 * ... but don't bother the driver with it. This works around
4559 * a hostapd/wpa_supplicant issue -- it always includes the
4560 * TLDS_PEER flag in the mask even for AP mode.
4561 */
4562 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4563 }
4564
Ayala Beker47edb112015-09-21 15:49:53 +03004565 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4566 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004567 /* reject other things that can't change */
4568 if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
4569 return -EINVAL;
4570 if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
4571 return -EINVAL;
4572 if (params->supported_rates)
4573 return -EINVAL;
4574 if (params->ext_capab || params->ht_capa || params->vht_capa)
4575 return -EINVAL;
4576 }
4577
Ayala Beker47edb112015-09-21 15:49:53 +03004578 if (statype != CFG80211_STA_AP_CLIENT &&
4579 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004580 if (params->vlan)
4581 return -EINVAL;
4582 }
4583
4584 switch (statype) {
4585 case CFG80211_STA_AP_MLME_CLIENT:
4586 /* Use this only for authorizing/unauthorizing a station */
4587 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4588 return -EOPNOTSUPP;
4589 break;
4590 case CFG80211_STA_AP_CLIENT:
Ayala Beker47edb112015-09-21 15:49:53 +03004591 case CFG80211_STA_AP_CLIENT_UNASSOC:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004592 /* accept only the listed bits */
4593 if (params->sta_flags_mask &
4594 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4595 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4596 BIT(NL80211_STA_FLAG_ASSOCIATED) |
4597 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4598 BIT(NL80211_STA_FLAG_WME) |
4599 BIT(NL80211_STA_FLAG_MFP)))
4600 return -EINVAL;
4601
4602 /* but authenticated/associated only if driver handles it */
4603 if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
4604 params->sta_flags_mask &
4605 (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4606 BIT(NL80211_STA_FLAG_ASSOCIATED)))
4607 return -EINVAL;
4608 break;
4609 case CFG80211_STA_IBSS:
4610 case CFG80211_STA_AP_STA:
4611 /* reject any changes other than AUTHORIZED */
4612 if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
4613 return -EINVAL;
4614 break;
4615 case CFG80211_STA_TDLS_PEER_SETUP:
4616 /* reject any changes other than AUTHORIZED or WME */
4617 if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4618 BIT(NL80211_STA_FLAG_WME)))
4619 return -EINVAL;
4620 /* force (at least) rates when authorizing */
4621 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
4622 !params->supported_rates)
4623 return -EINVAL;
4624 break;
4625 case CFG80211_STA_TDLS_PEER_ACTIVE:
4626 /* reject any changes */
4627 return -EINVAL;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004628 case CFG80211_STA_MESH_PEER_KERNEL:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004629 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4630 return -EINVAL;
4631 break;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004632 case CFG80211_STA_MESH_PEER_USER:
Chun-Yeow Yeoh42925042015-04-18 01:30:02 +08004633 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
4634 params->plink_action != NL80211_PLINK_ACTION_BLOCK)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004635 return -EINVAL;
4636 break;
4637 }
4638
4639 return 0;
4640}
4641EXPORT_SYMBOL(cfg80211_check_station_change);
4642
Johannes Berg5727ef12007-12-19 02:03:34 +01004643/*
Felix Fietkauc258d2d2009-11-11 17:23:31 +01004644 * Get vlan interface making sure it is running and on the right wiphy.
Johannes Berg5727ef12007-12-19 02:03:34 +01004645 */
Johannes Berg80b99892011-11-18 16:23:01 +01004646static struct net_device *get_vlan(struct genl_info *info,
4647 struct cfg80211_registered_device *rdev)
Johannes Berg5727ef12007-12-19 02:03:34 +01004648{
Johannes Berg463d0182009-07-14 00:33:35 +02004649 struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
Johannes Berg80b99892011-11-18 16:23:01 +01004650 struct net_device *v;
4651 int ret;
Johannes Berg5727ef12007-12-19 02:03:34 +01004652
Johannes Berg80b99892011-11-18 16:23:01 +01004653 if (!vlanattr)
4654 return NULL;
4655
4656 v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
4657 if (!v)
4658 return ERR_PTR(-ENODEV);
4659
4660 if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
4661 ret = -EINVAL;
4662 goto error;
Johannes Berg5727ef12007-12-19 02:03:34 +01004663 }
Johannes Berg80b99892011-11-18 16:23:01 +01004664
Johannes Berg77ee7c82013-02-15 00:48:33 +01004665 if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
4666 v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4667 v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
4668 ret = -EINVAL;
4669 goto error;
4670 }
4671
Johannes Berg80b99892011-11-18 16:23:01 +01004672 if (!netif_running(v)) {
4673 ret = -ENETDOWN;
4674 goto error;
4675 }
4676
4677 return v;
4678 error:
4679 dev_put(v);
4680 return ERR_PTR(ret);
Johannes Berg5727ef12007-12-19 02:03:34 +01004681}
4682
Johannes Berg94e860f2014-01-20 23:58:15 +01004683static const struct nla_policy
4684nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
Jouni Malinendf881292013-02-14 21:10:54 +02004685 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
4686 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
4687};
4688
Johannes Bergff276692013-02-15 00:09:01 +01004689static int nl80211_parse_sta_wme(struct genl_info *info,
4690 struct station_parameters *params)
Jouni Malinendf881292013-02-14 21:10:54 +02004691{
Jouni Malinendf881292013-02-14 21:10:54 +02004692 struct nlattr *tb[NL80211_STA_WME_MAX + 1];
4693 struct nlattr *nla;
4694 int err;
4695
Jouni Malinendf881292013-02-14 21:10:54 +02004696 /* parse WME attributes if present */
4697 if (!info->attrs[NL80211_ATTR_STA_WME])
4698 return 0;
4699
4700 nla = info->attrs[NL80211_ATTR_STA_WME];
4701 err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
4702 nl80211_sta_wme_policy);
4703 if (err)
4704 return err;
4705
4706 if (tb[NL80211_STA_WME_UAPSD_QUEUES])
4707 params->uapsd_queues = nla_get_u8(
4708 tb[NL80211_STA_WME_UAPSD_QUEUES]);
4709 if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
4710 return -EINVAL;
4711
4712 if (tb[NL80211_STA_WME_MAX_SP])
4713 params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
4714
4715 if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
4716 return -EINVAL;
4717
4718 params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
4719
4720 return 0;
4721}
4722
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304723static int nl80211_parse_sta_channel_info(struct genl_info *info,
4724 struct station_parameters *params)
4725{
4726 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
4727 params->supported_channels =
4728 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4729 params->supported_channels_len =
4730 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4731 /*
4732 * Need to include at least one (first channel, number of
4733 * channels) tuple for each subband, and must have proper
4734 * tuples for the rest of the data as well.
4735 */
4736 if (params->supported_channels_len < 2)
4737 return -EINVAL;
4738 if (params->supported_channels_len % 2)
4739 return -EINVAL;
4740 }
4741
4742 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
4743 params->supported_oper_classes =
4744 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4745 params->supported_oper_classes_len =
4746 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4747 /*
4748 * The value of the Length field of the Supported Operating
4749 * Classes element is between 2 and 253.
4750 */
4751 if (params->supported_oper_classes_len < 2 ||
4752 params->supported_oper_classes_len > 253)
4753 return -EINVAL;
4754 }
4755 return 0;
4756}
4757
Johannes Bergff276692013-02-15 00:09:01 +01004758static int nl80211_set_station_tdls(struct genl_info *info,
4759 struct station_parameters *params)
4760{
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304761 int err;
Johannes Bergff276692013-02-15 00:09:01 +01004762 /* Dummy STA entry gets updated once the peer capabilities are known */
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004763 if (info->attrs[NL80211_ATTR_PEER_AID])
4764 params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Johannes Bergff276692013-02-15 00:09:01 +01004765 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
4766 params->ht_capa =
4767 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
4768 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
4769 params->vht_capa =
4770 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
4771
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304772 err = nl80211_parse_sta_channel_info(info, params);
4773 if (err)
4774 return err;
4775
Johannes Bergff276692013-02-15 00:09:01 +01004776 return nl80211_parse_sta_wme(info, params);
4777}
4778
Johannes Berg5727ef12007-12-19 02:03:34 +01004779static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
4780{
Johannes Berg4c476992010-10-04 21:36:35 +02004781 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02004782 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004783 struct station_parameters params;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004784 u8 *mac_addr;
4785 int err;
Johannes Berg5727ef12007-12-19 02:03:34 +01004786
4787 memset(&params, 0, sizeof(params));
4788
Johannes Berg77ee7c82013-02-15 00:48:33 +01004789 if (!rdev->ops->change_station)
4790 return -EOPNOTSUPP;
4791
Ayala Bekere4208422015-10-23 11:20:06 +03004792 /*
4793 * AID and listen_interval properties can be set only for unassociated
4794 * station. Include these parameters here and will check them in
4795 * cfg80211_check_station_change().
4796 */
Ayala Bekera9bc31e2015-11-26 16:26:12 +01004797 if (info->attrs[NL80211_ATTR_STA_AID])
4798 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Ayala Bekere4208422015-10-23 11:20:06 +03004799
4800 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4801 params.listen_interval =
4802 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
4803 else
4804 params.listen_interval = -1;
Johannes Berg5727ef12007-12-19 02:03:34 +01004805
Ayala Beker17b94242016-03-17 15:41:38 +02004806 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
4807 u8 tmp;
4808
4809 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
4810 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
4811 return -EINVAL;
4812
4813 params.support_p2p_ps = tmp;
4814 } else {
4815 params.support_p2p_ps = -1;
4816 }
4817
Johannes Berg5727ef12007-12-19 02:03:34 +01004818 if (!info->attrs[NL80211_ATTR_MAC])
4819 return -EINVAL;
4820
4821 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4822
4823 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
4824 params.supported_rates =
4825 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4826 params.supported_rates_len =
4827 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4828 }
4829
Jouni Malinen9d62a982013-02-14 21:10:13 +02004830 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
4831 params.capability =
4832 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
4833 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
4834 }
4835
4836 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
4837 params.ext_capab =
4838 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4839 params.ext_capab_len =
4840 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4841 }
4842
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004843 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01004844 return -EINVAL;
4845
Johannes Bergf8bacc22013-02-14 23:27:01 +01004846 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004847 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004848 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
4849 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
4850 return -EINVAL;
4851 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004852
Johannes Bergf8bacc22013-02-14 23:27:01 +01004853 if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
Javier Cardona9c3990a2011-05-03 16:57:11 -07004854 params.plink_state =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004855 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
4856 if (params.plink_state >= NUM_NL80211_PLINK_STATES)
4857 return -EINVAL;
Masashi Honma7d27a0b2016-07-01 10:19:34 +09004858 if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) {
4859 params.peer_aid = nla_get_u16(
4860 info->attrs[NL80211_ATTR_MESH_PEER_AID]);
4861 if (params.peer_aid > IEEE80211_MAX_AID)
4862 return -EINVAL;
4863 }
Johannes Bergf8bacc22013-02-14 23:27:01 +01004864 params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
4865 }
Javier Cardona9c3990a2011-05-03 16:57:11 -07004866
Marco Porsch3b1c5a52013-01-07 16:04:52 +01004867 if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
4868 enum nl80211_mesh_power_mode pm = nla_get_u32(
4869 info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
4870
4871 if (pm <= NL80211_MESH_POWER_UNKNOWN ||
4872 pm > NL80211_MESH_POWER_MAX)
4873 return -EINVAL;
4874
4875 params.local_pm = pm;
4876 }
4877
Johannes Berg77ee7c82013-02-15 00:48:33 +01004878 /* Include parameters for TDLS peer (will check later) */
4879 err = nl80211_set_station_tdls(info, &params);
4880 if (err)
4881 return err;
4882
4883 params.vlan = get_vlan(info, rdev);
4884 if (IS_ERR(params.vlan))
4885 return PTR_ERR(params.vlan);
4886
Johannes Berga97f4422009-06-18 17:23:43 +02004887 switch (dev->ieee80211_ptr->iftype) {
4888 case NL80211_IFTYPE_AP:
4889 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02004890 case NL80211_IFTYPE_P2P_GO:
Johannes Berg074ac8d2010-09-16 14:58:22 +02004891 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berga97f4422009-06-18 17:23:43 +02004892 case NL80211_IFTYPE_STATION:
Antonio Quartulli267335d2012-01-31 20:25:47 +01004893 case NL80211_IFTYPE_ADHOC:
Johannes Berga97f4422009-06-18 17:23:43 +02004894 case NL80211_IFTYPE_MESH_POINT:
Johannes Berga97f4422009-06-18 17:23:43 +02004895 break;
4896 default:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004897 err = -EOPNOTSUPP;
4898 goto out_put_vlan;
Johannes Berg034d6552009-05-27 10:35:29 +02004899 }
4900
Johannes Berg77ee7c82013-02-15 00:48:33 +01004901 /* driver will call cfg80211_check_station_change() */
Hila Gonene35e4d22012-06-27 17:19:42 +03004902 err = rdev_change_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01004903
Johannes Berg77ee7c82013-02-15 00:48:33 +01004904 out_put_vlan:
Johannes Berg5727ef12007-12-19 02:03:34 +01004905 if (params.vlan)
4906 dev_put(params.vlan);
Johannes Berg3b858752009-03-12 09:55:09 +01004907
Johannes Berg5727ef12007-12-19 02:03:34 +01004908 return err;
4909}
4910
4911static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
4912{
Johannes Berg4c476992010-10-04 21:36:35 +02004913 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg5727ef12007-12-19 02:03:34 +01004914 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004915 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004916 struct station_parameters params;
4917 u8 *mac_addr = NULL;
Johannes Bergbda95eb2015-11-26 16:26:13 +01004918 u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4919 BIT(NL80211_STA_FLAG_ASSOCIATED);
Johannes Berg5727ef12007-12-19 02:03:34 +01004920
4921 memset(&params, 0, sizeof(params));
4922
Johannes Berg984c3112013-02-14 23:43:25 +01004923 if (!rdev->ops->add_station)
4924 return -EOPNOTSUPP;
4925
Johannes Berg5727ef12007-12-19 02:03:34 +01004926 if (!info->attrs[NL80211_ATTR_MAC])
4927 return -EINVAL;
4928
Johannes Berg5727ef12007-12-19 02:03:34 +01004929 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4930 return -EINVAL;
4931
4932 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
4933 return -EINVAL;
4934
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004935 if (!info->attrs[NL80211_ATTR_STA_AID] &&
4936 !info->attrs[NL80211_ATTR_PEER_AID])
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02004937 return -EINVAL;
4938
Johannes Berg5727ef12007-12-19 02:03:34 +01004939 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4940 params.supported_rates =
4941 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4942 params.supported_rates_len =
4943 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4944 params.listen_interval =
4945 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02004946
Ayala Beker17b94242016-03-17 15:41:38 +02004947 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
4948 u8 tmp;
4949
4950 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
4951 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
4952 return -EINVAL;
4953
4954 params.support_p2p_ps = tmp;
4955 } else {
4956 /*
4957 * if not specified, assume it's supported for P2P GO interface,
4958 * and is NOT supported for AP interface
4959 */
4960 params.support_p2p_ps =
4961 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
4962 }
4963
Jouni Malinen3d124ea2013-05-27 18:24:02 +03004964 if (info->attrs[NL80211_ATTR_PEER_AID])
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004965 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Jouni Malinen3d124ea2013-05-27 18:24:02 +03004966 else
4967 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02004968 if (!params.aid || params.aid > IEEE80211_MAX_AID)
4969 return -EINVAL;
Johannes Berg51b50fb2009-05-24 16:42:30 +02004970
Jouni Malinen9d62a982013-02-14 21:10:13 +02004971 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
4972 params.capability =
4973 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
4974 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
4975 }
4976
4977 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
4978 params.ext_capab =
4979 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4980 params.ext_capab_len =
4981 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4982 }
4983
Jouni Malinen36aedc902008-08-25 11:58:58 +03004984 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
4985 params.ht_capa =
4986 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
Johannes Berg5727ef12007-12-19 02:03:34 +01004987
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +00004988 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
4989 params.vht_capa =
4990 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
4991
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +01004992 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
4993 params.opmode_notif_used = true;
4994 params.opmode_notif =
4995 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
4996 }
4997
Johannes Bergf8bacc22013-02-14 23:27:01 +01004998 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Javier Cardona96b78df2011-04-07 15:08:33 -07004999 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005000 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5001 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
5002 return -EINVAL;
5003 }
Javier Cardona96b78df2011-04-07 15:08:33 -07005004
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305005 err = nl80211_parse_sta_channel_info(info, &params);
5006 if (err)
5007 return err;
5008
Johannes Bergff276692013-02-15 00:09:01 +01005009 err = nl80211_parse_sta_wme(info, &params);
5010 if (err)
5011 return err;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005012
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005013 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01005014 return -EINVAL;
5015
Johannes Berg496fcc22015-03-12 08:53:27 +02005016 /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
5017 * as userspace might just pass through the capabilities from the IEs
5018 * directly, rather than enforcing this restriction and returning an
5019 * error in this case.
5020 */
5021 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
5022 params.ht_capa = NULL;
5023 params.vht_capa = NULL;
5024 }
5025
Johannes Berg77ee7c82013-02-15 00:48:33 +01005026 /* When you run into this, adjust the code below for the new flag */
5027 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5028
Johannes Bergbdd90d52011-12-14 12:20:27 +01005029 switch (dev->ieee80211_ptr->iftype) {
5030 case NL80211_IFTYPE_AP:
5031 case NL80211_IFTYPE_AP_VLAN:
5032 case NL80211_IFTYPE_P2P_GO:
Johannes Berg984c3112013-02-14 23:43:25 +01005033 /* ignore WME attributes if iface/sta is not capable */
5034 if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
5035 !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
5036 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005037
Johannes Bergbdd90d52011-12-14 12:20:27 +01005038 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005039 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5040 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005041 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005042 /* but don't bother the driver with it */
5043 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
Eliad Pellerc75786c2011-08-23 14:37:46 +03005044
Johannes Bergd582cff2012-10-26 17:53:44 +02005045 /* allow authenticated/associated only if driver handles it */
5046 if (!(rdev->wiphy.features &
5047 NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
Johannes Bergbda95eb2015-11-26 16:26:13 +01005048 params.sta_flags_mask & auth_assoc)
Johannes Bergd582cff2012-10-26 17:53:44 +02005049 return -EINVAL;
5050
Johannes Bergbda95eb2015-11-26 16:26:13 +01005051 /* Older userspace, or userspace wanting to be compatible with
5052 * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
5053 * and assoc flags in the mask, but assumes the station will be
5054 * added as associated anyway since this was the required driver
5055 * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
5056 * introduced.
5057 * In order to not bother drivers with this quirk in the API
5058 * set the flags in both the mask and set for new stations in
5059 * this case.
5060 */
5061 if (!(params.sta_flags_mask & auth_assoc)) {
5062 params.sta_flags_mask |= auth_assoc;
5063 params.sta_flags_set |= auth_assoc;
5064 }
5065
Johannes Bergbdd90d52011-12-14 12:20:27 +01005066 /* must be last in here for error handling */
5067 params.vlan = get_vlan(info, rdev);
5068 if (IS_ERR(params.vlan))
5069 return PTR_ERR(params.vlan);
5070 break;
5071 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg984c3112013-02-14 23:43:25 +01005072 /* ignore uAPSD data */
5073 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5074
Johannes Bergd582cff2012-10-26 17:53:44 +02005075 /* associated is disallowed */
5076 if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
5077 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005078 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005079 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5080 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005081 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005082 break;
5083 case NL80211_IFTYPE_STATION:
Johannes Berg93d08f02013-03-04 09:29:46 +01005084 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg984c3112013-02-14 23:43:25 +01005085 /* ignore uAPSD data */
5086 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5087
Johannes Berg77ee7c82013-02-15 00:48:33 +01005088 /* these are disallowed */
5089 if (params.sta_flags_mask &
5090 (BIT(NL80211_STA_FLAG_ASSOCIATED) |
5091 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
Johannes Bergd582cff2012-10-26 17:53:44 +02005092 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005093 /* Only TDLS peers can be added */
5094 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
5095 return -EINVAL;
5096 /* Can only add if TDLS ... */
5097 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
5098 return -EOPNOTSUPP;
5099 /* ... with external setup is supported */
5100 if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
5101 return -EOPNOTSUPP;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005102 /*
5103 * Older wpa_supplicant versions always mark the TDLS peer
5104 * as authorized, but it shouldn't yet be.
5105 */
5106 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
Johannes Bergbdd90d52011-12-14 12:20:27 +01005107 break;
5108 default:
5109 return -EOPNOTSUPP;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005110 }
5111
Johannes Bergbdd90d52011-12-14 12:20:27 +01005112 /* be aware of params.vlan when changing code here */
Johannes Berg5727ef12007-12-19 02:03:34 +01005113
Hila Gonene35e4d22012-06-27 17:19:42 +03005114 err = rdev_add_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005115
Johannes Berg5727ef12007-12-19 02:03:34 +01005116 if (params.vlan)
5117 dev_put(params.vlan);
Johannes Berg5727ef12007-12-19 02:03:34 +01005118 return err;
5119}
5120
5121static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
5122{
Johannes Berg4c476992010-10-04 21:36:35 +02005123 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5124 struct net_device *dev = info->user_ptr[1];
Jouni Malinen89c771e2014-10-10 20:52:40 +03005125 struct station_del_parameters params;
5126
5127 memset(&params, 0, sizeof(params));
Johannes Berg5727ef12007-12-19 02:03:34 +01005128
5129 if (info->attrs[NL80211_ATTR_MAC])
Jouni Malinen89c771e2014-10-10 20:52:40 +03005130 params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005131
Johannes Berge80cf852009-05-11 14:43:13 +02005132 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Marco Porschd5d9de02010-03-30 10:00:16 +02005133 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
Johannes Berg074ac8d2010-09-16 14:58:22 +02005134 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
Johannes Berg4c476992010-10-04 21:36:35 +02005135 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5136 return -EINVAL;
Johannes Berge80cf852009-05-11 14:43:13 +02005137
Johannes Berg4c476992010-10-04 21:36:35 +02005138 if (!rdev->ops->del_station)
5139 return -EOPNOTSUPP;
Johannes Berg5727ef12007-12-19 02:03:34 +01005140
Jouni Malinen98856862014-10-20 13:20:45 +03005141 if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
5142 params.subtype =
5143 nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
5144 if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
5145 params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
5146 return -EINVAL;
5147 } else {
5148 /* Default to Deauthentication frame */
5149 params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
5150 }
5151
5152 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
5153 params.reason_code =
5154 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
5155 if (params.reason_code == 0)
5156 return -EINVAL; /* 0 is reserved */
5157 } else {
5158 /* Default to reason code 2 */
5159 params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
5160 }
5161
Jouni Malinen89c771e2014-10-10 20:52:40 +03005162 return rdev_del_station(rdev, dev, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005163}
5164
Eric W. Biederman15e47302012-09-07 20:12:54 +00005165static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005166 int flags, struct net_device *dev,
5167 u8 *dst, u8 *next_hop,
5168 struct mpath_info *pinfo)
5169{
5170 void *hdr;
5171 struct nlattr *pinfoattr;
5172
Henning Rogge1ef4c852014-11-04 16:14:58 +01005173 hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005174 if (!hdr)
5175 return -1;
5176
David S. Miller9360ffd2012-03-29 04:41:26 -04005177 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5178 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
5179 nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
5180 nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
5181 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02005182
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005183 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
5184 if (!pinfoattr)
5185 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005186 if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
5187 nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
5188 pinfo->frame_qlen))
5189 goto nla_put_failure;
5190 if (((pinfo->filled & MPATH_INFO_SN) &&
5191 nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
5192 ((pinfo->filled & MPATH_INFO_METRIC) &&
5193 nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
5194 pinfo->metric)) ||
5195 ((pinfo->filled & MPATH_INFO_EXPTIME) &&
5196 nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
5197 pinfo->exptime)) ||
5198 ((pinfo->filled & MPATH_INFO_FLAGS) &&
5199 nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
5200 pinfo->flags)) ||
5201 ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
5202 nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
5203 pinfo->discovery_timeout)) ||
5204 ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
5205 nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
5206 pinfo->discovery_retries)))
5207 goto nla_put_failure;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005208
5209 nla_nest_end(msg, pinfoattr);
5210
Johannes Berg053c0952015-01-16 22:09:00 +01005211 genlmsg_end(msg, hdr);
5212 return 0;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005213
5214 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07005215 genlmsg_cancel(msg, hdr);
5216 return -EMSGSIZE;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005217}
5218
5219static int nl80211_dump_mpath(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005220 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005221{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005222 struct mpath_info pinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005223 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02005224 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005225 u8 dst[ETH_ALEN];
5226 u8 next_hop[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02005227 int path_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005228 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005229
Johannes Berg56769e72017-03-15 14:26:04 +01005230 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005231 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02005232 if (err)
Johannes Berg56769e72017-03-15 14:26:04 +01005233 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005234
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005235 if (!rdev->ops->dump_mpath) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005236 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005237 goto out_err;
5238 }
5239
Johannes Berg97990a02013-04-19 01:02:55 +02005240 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005241 err = -EOPNOTSUPP;
Roel Kluin0448b5f2009-08-22 21:15:49 +02005242 goto out_err;
Jouni Malineneec60b02009-03-20 21:21:19 +02005243 }
5244
Johannes Bergbba95fe2008-07-29 13:22:51 +02005245 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005246 err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
Johannes Berg97990a02013-04-19 01:02:55 +02005247 next_hop, &pinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005248 if (err == -ENOENT)
5249 break;
5250 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01005251 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005252
Eric W. Biederman15e47302012-09-07 20:12:54 +00005253 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005254 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg97990a02013-04-19 01:02:55 +02005255 wdev->netdev, dst, next_hop,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005256 &pinfo) < 0)
5257 goto out;
5258
5259 path_idx++;
5260 }
5261
Johannes Bergbba95fe2008-07-29 13:22:51 +02005262 out:
Johannes Berg97990a02013-04-19 01:02:55 +02005263 cb->args[2] = path_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005264 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005265 out_err:
Johannes Berg56769e72017-03-15 14:26:04 +01005266 rtnl_unlock();
Johannes Bergbba95fe2008-07-29 13:22:51 +02005267 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005268}
5269
5270static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
5271{
Johannes Berg4c476992010-10-04 21:36:35 +02005272 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005273 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02005274 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005275 struct mpath_info pinfo;
5276 struct sk_buff *msg;
5277 u8 *dst = NULL;
5278 u8 next_hop[ETH_ALEN];
5279
5280 memset(&pinfo, 0, sizeof(pinfo));
5281
5282 if (!info->attrs[NL80211_ATTR_MAC])
5283 return -EINVAL;
5284
5285 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5286
Johannes Berg4c476992010-10-04 21:36:35 +02005287 if (!rdev->ops->get_mpath)
5288 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005289
Johannes Berg4c476992010-10-04 21:36:35 +02005290 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5291 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005292
Hila Gonene35e4d22012-06-27 17:19:42 +03005293 err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005294 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005295 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005296
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005297 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005298 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02005299 return -ENOMEM;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005300
Eric W. Biederman15e47302012-09-07 20:12:54 +00005301 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg4c476992010-10-04 21:36:35 +02005302 dev, dst, next_hop, &pinfo) < 0) {
5303 nlmsg_free(msg);
5304 return -ENOBUFS;
5305 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005306
Johannes Berg4c476992010-10-04 21:36:35 +02005307 return genlmsg_reply(msg, info);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005308}
5309
5310static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
5311{
Johannes Berg4c476992010-10-04 21:36:35 +02005312 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5313 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005314 u8 *dst = NULL;
5315 u8 *next_hop = NULL;
5316
5317 if (!info->attrs[NL80211_ATTR_MAC])
5318 return -EINVAL;
5319
5320 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5321 return -EINVAL;
5322
5323 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5324 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5325
Johannes Berg4c476992010-10-04 21:36:35 +02005326 if (!rdev->ops->change_mpath)
5327 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005328
Johannes Berg4c476992010-10-04 21:36:35 +02005329 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5330 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005331
Hila Gonene35e4d22012-06-27 17:19:42 +03005332 return rdev_change_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005333}
Johannes Berg4c476992010-10-04 21:36:35 +02005334
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005335static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
5336{
Johannes Berg4c476992010-10-04 21:36:35 +02005337 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5338 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005339 u8 *dst = NULL;
5340 u8 *next_hop = NULL;
5341
5342 if (!info->attrs[NL80211_ATTR_MAC])
5343 return -EINVAL;
5344
5345 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5346 return -EINVAL;
5347
5348 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5349 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5350
Johannes Berg4c476992010-10-04 21:36:35 +02005351 if (!rdev->ops->add_mpath)
5352 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005353
Johannes Berg4c476992010-10-04 21:36:35 +02005354 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5355 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005356
Hila Gonene35e4d22012-06-27 17:19:42 +03005357 return rdev_add_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005358}
5359
5360static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
5361{
Johannes Berg4c476992010-10-04 21:36:35 +02005362 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5363 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005364 u8 *dst = NULL;
5365
5366 if (info->attrs[NL80211_ATTR_MAC])
5367 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5368
Johannes Berg4c476992010-10-04 21:36:35 +02005369 if (!rdev->ops->del_mpath)
5370 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005371
Hila Gonene35e4d22012-06-27 17:19:42 +03005372 return rdev_del_mpath(rdev, dev, dst);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005373}
5374
Henning Rogge66be7d22014-09-12 08:58:49 +02005375static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
5376{
5377 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5378 int err;
5379 struct net_device *dev = info->user_ptr[1];
5380 struct mpath_info pinfo;
5381 struct sk_buff *msg;
5382 u8 *dst = NULL;
5383 u8 mpp[ETH_ALEN];
5384
5385 memset(&pinfo, 0, sizeof(pinfo));
5386
5387 if (!info->attrs[NL80211_ATTR_MAC])
5388 return -EINVAL;
5389
5390 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5391
5392 if (!rdev->ops->get_mpp)
5393 return -EOPNOTSUPP;
5394
5395 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5396 return -EOPNOTSUPP;
5397
5398 err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
5399 if (err)
5400 return err;
5401
5402 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5403 if (!msg)
5404 return -ENOMEM;
5405
5406 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
5407 dev, dst, mpp, &pinfo) < 0) {
5408 nlmsg_free(msg);
5409 return -ENOBUFS;
5410 }
5411
5412 return genlmsg_reply(msg, info);
5413}
5414
5415static int nl80211_dump_mpp(struct sk_buff *skb,
5416 struct netlink_callback *cb)
5417{
5418 struct mpath_info pinfo;
5419 struct cfg80211_registered_device *rdev;
5420 struct wireless_dev *wdev;
5421 u8 dst[ETH_ALEN];
5422 u8 mpp[ETH_ALEN];
5423 int path_idx = cb->args[2];
5424 int err;
5425
Johannes Berg56769e72017-03-15 14:26:04 +01005426 rtnl_lock();
Henning Rogge66be7d22014-09-12 08:58:49 +02005427 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
5428 if (err)
Johannes Berg56769e72017-03-15 14:26:04 +01005429 goto out_err;
Henning Rogge66be7d22014-09-12 08:58:49 +02005430
5431 if (!rdev->ops->dump_mpp) {
5432 err = -EOPNOTSUPP;
5433 goto out_err;
5434 }
5435
5436 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
5437 err = -EOPNOTSUPP;
5438 goto out_err;
5439 }
5440
5441 while (1) {
5442 err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
5443 mpp, &pinfo);
5444 if (err == -ENOENT)
5445 break;
5446 if (err)
5447 goto out_err;
5448
5449 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
5450 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5451 wdev->netdev, dst, mpp,
5452 &pinfo) < 0)
5453 goto out;
5454
5455 path_idx++;
5456 }
5457
5458 out:
5459 cb->args[2] = path_idx;
5460 err = skb->len;
5461 out_err:
Johannes Berg56769e72017-03-15 14:26:04 +01005462 rtnl_unlock();
Henning Rogge66be7d22014-09-12 08:58:49 +02005463 return err;
5464}
5465
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005466static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
5467{
Johannes Berg4c476992010-10-04 21:36:35 +02005468 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5469 struct net_device *dev = info->user_ptr[1];
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005470 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005471 struct bss_parameters params;
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005472 int err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005473
5474 memset(&params, 0, sizeof(params));
5475 /* default to not changing parameters */
5476 params.use_cts_prot = -1;
5477 params.use_short_preamble = -1;
5478 params.use_short_slot_time = -1;
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005479 params.ap_isolate = -1;
Helmut Schaa50b12f52010-11-19 12:40:25 +01005480 params.ht_opmode = -1;
Johannes Berg53cabad2012-11-14 15:17:28 +01005481 params.p2p_ctwindow = -1;
5482 params.p2p_opp_ps = -1;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005483
5484 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
5485 params.use_cts_prot =
5486 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
5487 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
5488 params.use_short_preamble =
5489 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
5490 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
5491 params.use_short_slot_time =
5492 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
Jouni Malinen90c97a02008-10-30 16:59:22 +02005493 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
5494 params.basic_rates =
5495 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5496 params.basic_rates_len =
5497 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5498 }
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005499 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
5500 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
Helmut Schaa50b12f52010-11-19 12:40:25 +01005501 if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
5502 params.ht_opmode =
5503 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005504
Johannes Berg53cabad2012-11-14 15:17:28 +01005505 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
5506 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5507 return -EINVAL;
5508 params.p2p_ctwindow =
5509 nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
5510 if (params.p2p_ctwindow < 0)
5511 return -EINVAL;
5512 if (params.p2p_ctwindow != 0 &&
5513 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
5514 return -EINVAL;
5515 }
5516
5517 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
5518 u8 tmp;
5519
5520 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5521 return -EINVAL;
5522 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
5523 if (tmp > 1)
5524 return -EINVAL;
5525 params.p2p_opp_ps = tmp;
5526 if (params.p2p_opp_ps &&
5527 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
5528 return -EINVAL;
5529 }
5530
Johannes Berg4c476992010-10-04 21:36:35 +02005531 if (!rdev->ops->change_bss)
5532 return -EOPNOTSUPP;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005533
Johannes Berg074ac8d2010-09-16 14:58:22 +02005534 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berg4c476992010-10-04 21:36:35 +02005535 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5536 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005537
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005538 wdev_lock(wdev);
5539 err = rdev_change_bss(rdev, dev, &params);
5540 wdev_unlock(wdev);
5541
5542 return err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005543}
5544
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005545static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
5546{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005547 char *data = NULL;
Ilan peer05050752015-03-04 00:32:06 -05005548 bool is_indoor;
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005549 enum nl80211_user_reg_hint_type user_reg_hint_type;
Ilan peer05050752015-03-04 00:32:06 -05005550 u32 owner_nlportid;
5551
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005552 /*
5553 * You should only get this when cfg80211 hasn't yet initialized
5554 * completely when built-in to the kernel right between the time
5555 * window between nl80211_init() and regulatory_init(), if that is
5556 * even possible.
5557 */
Johannes Berg458f4f92012-12-06 15:47:38 +01005558 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
Luis R. Rodriguezfe33eb32009-02-21 00:04:30 -05005559 return -EINPROGRESS;
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005560
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005561 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
5562 user_reg_hint_type =
5563 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
5564 else
5565 user_reg_hint_type = NL80211_USER_REG_HINT_USER;
5566
5567 switch (user_reg_hint_type) {
5568 case NL80211_USER_REG_HINT_USER:
5569 case NL80211_USER_REG_HINT_CELL_BASE:
Ilan Peer52616f22014-02-25 16:26:00 +02005570 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
5571 return -EINVAL;
5572
5573 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
5574 return regulatory_hint_user(data, user_reg_hint_type);
5575 case NL80211_USER_REG_HINT_INDOOR:
Ilan peer05050752015-03-04 00:32:06 -05005576 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
5577 owner_nlportid = info->snd_portid;
5578 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
5579 } else {
5580 owner_nlportid = 0;
5581 is_indoor = true;
5582 }
5583
5584 return regulatory_hint_indoor(is_indoor, owner_nlportid);
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005585 default:
5586 return -EINVAL;
5587 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005588}
5589
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005590static int nl80211_get_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01005591 struct genl_info *info)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005592{
Johannes Berg4c476992010-10-04 21:36:35 +02005593 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02005594 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01005595 struct wireless_dev *wdev = dev->ieee80211_ptr;
5596 struct mesh_config cur_params;
5597 int err = 0;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005598 void *hdr;
5599 struct nlattr *pinfoattr;
5600 struct sk_buff *msg;
5601
Johannes Berg29cbe682010-12-03 09:20:44 +01005602 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
5603 return -EOPNOTSUPP;
5604
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005605 if (!rdev->ops->get_mesh_config)
Johannes Berg4c476992010-10-04 21:36:35 +02005606 return -EOPNOTSUPP;
Jouni Malinenf3f92582009-03-20 17:57:36 +02005607
Johannes Berg29cbe682010-12-03 09:20:44 +01005608 wdev_lock(wdev);
5609 /* If not connected, get default parameters */
5610 if (!wdev->mesh_id_len)
5611 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
5612 else
Hila Gonene35e4d22012-06-27 17:19:42 +03005613 err = rdev_get_mesh_config(rdev, dev, &cur_params);
Johannes Berg29cbe682010-12-03 09:20:44 +01005614 wdev_unlock(wdev);
5615
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005616 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005617 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005618
5619 /* Draw up a netlink message to send back */
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005620 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02005621 if (!msg)
5622 return -ENOMEM;
Eric W. Biederman15e47302012-09-07 20:12:54 +00005623 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005624 NL80211_CMD_GET_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005625 if (!hdr)
Julia Lawallefe1cf02011-01-28 15:17:11 +01005626 goto out;
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005627 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005628 if (!pinfoattr)
5629 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005630 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5631 nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
5632 cur_params.dot11MeshRetryTimeout) ||
5633 nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
5634 cur_params.dot11MeshConfirmTimeout) ||
5635 nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
5636 cur_params.dot11MeshHoldingTimeout) ||
5637 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
5638 cur_params.dot11MeshMaxPeerLinks) ||
5639 nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
5640 cur_params.dot11MeshMaxRetries) ||
5641 nla_put_u8(msg, NL80211_MESHCONF_TTL,
5642 cur_params.dot11MeshTTL) ||
5643 nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
5644 cur_params.element_ttl) ||
5645 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
5646 cur_params.auto_open_plinks) ||
John W. Linville7eab0f62012-04-12 14:25:14 -04005647 nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
5648 cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04005649 nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
5650 cur_params.dot11MeshHWMPmaxPREQretries) ||
5651 nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
5652 cur_params.path_refresh_time) ||
5653 nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
5654 cur_params.min_discovery_timeout) ||
5655 nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
5656 cur_params.dot11MeshHWMPactivePathTimeout) ||
5657 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
5658 cur_params.dot11MeshHWMPpreqMinInterval) ||
5659 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
5660 cur_params.dot11MeshHWMPperrMinInterval) ||
5661 nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
5662 cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
5663 nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
5664 cur_params.dot11MeshHWMPRootMode) ||
5665 nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
5666 cur_params.dot11MeshHWMPRannInterval) ||
5667 nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
5668 cur_params.dot11MeshGateAnnouncementProtocol) ||
5669 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
5670 cur_params.dot11MeshForwarding) ||
5671 nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
Ashok Nagarajan70c33ea2012-04-30 14:20:32 -07005672 cur_params.rssi_threshold) ||
5673 nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005674 cur_params.ht_opmode) ||
5675 nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
5676 cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
5677 nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005678 cur_params.dot11MeshHWMProotInterval) ||
5679 nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005680 cur_params.dot11MeshHWMPconfirmationInterval) ||
5681 nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
5682 cur_params.power_mode) ||
5683 nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005684 cur_params.dot11MeshAwakeWindowDuration) ||
5685 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
5686 cur_params.plink_timeout))
David S. Miller9360ffd2012-03-29 04:41:26 -04005687 goto nla_put_failure;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005688 nla_nest_end(msg, pinfoattr);
5689 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02005690 return genlmsg_reply(msg, info);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005691
Johannes Berg3b858752009-03-12 09:55:09 +01005692 nla_put_failure:
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005693 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01005694 out:
Yuri Ershovd080e272010-06-29 15:08:07 +04005695 nlmsg_free(msg);
Johannes Berg4c476992010-10-04 21:36:35 +02005696 return -ENOBUFS;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005697}
5698
Alexey Dobriyanb54452b2010-02-18 08:14:31 +00005699static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005700 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
5701 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
5702 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
5703 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
5704 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
5705 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
Javier Cardona45904f22010-12-03 09:20:40 +01005706 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005707 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
Javier Cardonad299a1f2012-03-31 11:31:33 -07005708 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005709 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
5710 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
5711 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
5712 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
5713 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
Thomas Pedersendca7e942011-11-24 17:15:24 -08005714 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005715 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
Javier Cardona699403d2011-08-09 16:45:09 -07005716 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
Javier Cardona0507e152011-08-09 16:45:10 -07005717 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
Javier Cardona16dd7262011-08-09 16:45:11 -07005718 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
Chun-Yeow Yeoh94f90652012-01-21 01:02:16 +08005719 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005720 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
5721 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005722 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
5723 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005724 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005725 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
5726 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005727 [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005728};
5729
Javier Cardonac80d5452010-12-16 17:37:49 -08005730static const struct nla_policy
5731 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
Javier Cardonad299a1f2012-03-31 11:31:33 -07005732 [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
Javier Cardonac80d5452010-12-16 17:37:49 -08005733 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
5734 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
Javier Cardona15d5dda2011-04-07 15:08:28 -07005735 [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
Colleen Twitty6e16d902013-05-08 11:45:59 -07005736 [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08005737 [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
Javier Cardona581a8b02011-04-07 15:08:27 -07005738 [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005739 .len = IEEE80211_MAX_DATA_LEN },
Javier Cardonab130e5c2011-05-03 16:57:07 -07005740 [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
Javier Cardonac80d5452010-12-16 17:37:49 -08005741};
5742
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005743static int nl80211_check_bool(const struct nlattr *nla, u8 min, u8 max, bool *out)
5744{
5745 u8 val = nla_get_u8(nla);
5746 if (val < min || val > max)
5747 return -EINVAL;
5748 *out = val;
5749 return 0;
5750}
5751
5752static int nl80211_check_u8(const struct nlattr *nla, u8 min, u8 max, u8 *out)
5753{
5754 u8 val = nla_get_u8(nla);
5755 if (val < min || val > max)
5756 return -EINVAL;
5757 *out = val;
5758 return 0;
5759}
5760
5761static int nl80211_check_u16(const struct nlattr *nla, u16 min, u16 max, u16 *out)
5762{
5763 u16 val = nla_get_u16(nla);
5764 if (val < min || val > max)
5765 return -EINVAL;
5766 *out = val;
5767 return 0;
5768}
5769
5770static int nl80211_check_u32(const struct nlattr *nla, u32 min, u32 max, u32 *out)
5771{
5772 u32 val = nla_get_u32(nla);
5773 if (val < min || val > max)
5774 return -EINVAL;
5775 *out = val;
5776 return 0;
5777}
5778
5779static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *out)
5780{
5781 s32 val = nla_get_s32(nla);
5782 if (val < min || val > max)
5783 return -EINVAL;
5784 *out = val;
5785 return 0;
5786}
5787
Johannes Bergff9a71a2016-08-11 14:59:53 +02005788static int nl80211_check_power_mode(const struct nlattr *nla,
5789 enum nl80211_mesh_power_mode min,
5790 enum nl80211_mesh_power_mode max,
5791 enum nl80211_mesh_power_mode *out)
5792{
5793 u32 val = nla_get_u32(nla);
5794 if (val < min || val > max)
5795 return -EINVAL;
5796 *out = val;
5797 return 0;
5798}
5799
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005800static int nl80211_parse_mesh_config(struct genl_info *info,
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005801 struct mesh_config *cfg,
5802 u32 *mask_out)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005803{
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005804 struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005805 u32 mask = 0;
Masashi Honma97572352016-08-03 10:07:44 +09005806 u16 ht_opmode;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005807
Marco Porschea54fba2013-01-07 16:04:48 +01005808#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
5809do { \
5810 if (tb[attr]) { \
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005811 if (fn(tb[attr], min, max, &cfg->param)) \
Marco Porschea54fba2013-01-07 16:04:48 +01005812 return -EINVAL; \
Marco Porschea54fba2013-01-07 16:04:48 +01005813 mask |= (1 << (attr - 1)); \
5814 } \
5815} while (0)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005816
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005817 if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005818 return -EINVAL;
5819 if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005820 info->attrs[NL80211_ATTR_MESH_CONFIG],
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005821 nl80211_meshconf_params_policy))
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005822 return -EINVAL;
5823
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005824 /* This makes sure that there aren't more than 32 mesh config
5825 * parameters (otherwise our bitfield scheme would not work.) */
5826 BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
5827
5828 /* Fill in the params struct */
Marco Porschea54fba2013-01-07 16:04:48 +01005829 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005830 mask, NL80211_MESHCONF_RETRY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005831 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005832 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005833 mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005834 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005835 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005836 mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005837 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005838 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005839 mask, NL80211_MESHCONF_MAX_PEER_LINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005840 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005841 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005842 mask, NL80211_MESHCONF_MAX_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005843 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005844 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005845 mask, NL80211_MESHCONF_TTL, nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005846 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005847 mask, NL80211_MESHCONF_ELEMENT_TTL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005848 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005849 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005850 mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005851 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005852 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
5853 1, 255, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005854 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005855 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005856 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005857 mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005858 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005859 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005860 mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005861 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005862 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005863 mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005864 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005865 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
5866 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005867 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005868 nl80211_check_u32);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005869 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005870 1, 65535, mask,
5871 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005872 nl80211_check_u16);
Thomas Pedersendca7e942011-11-24 17:15:24 -08005873 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005874 1, 65535, mask,
5875 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005876 nl80211_check_u16);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005877 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005878 dot11MeshHWMPnetDiameterTraversalTime,
5879 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005880 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005881 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005882 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
5883 mask, NL80211_MESHCONF_HWMP_ROOTMODE,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005884 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005885 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
5886 mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005887 nl80211_check_u16);
Rui Paulo63c57232009-11-09 23:46:57 +00005888 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005889 dot11MeshGateAnnouncementProtocol, 0, 1,
5890 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005891 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005892 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005893 mask, NL80211_MESHCONF_FORWARDING,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005894 nl80211_check_bool);
Chun-Yeow Yeoh83374fe2013-07-11 18:24:03 +08005895 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005896 mask, NL80211_MESHCONF_RSSI_THRESHOLD,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005897 nl80211_check_s32);
Masashi Honma97572352016-08-03 10:07:44 +09005898 /*
5899 * Check HT operation mode based on
5900 * IEEE 802.11 2012 8.4.2.59 HT Operation element.
5901 */
5902 if (tb[NL80211_MESHCONF_HT_OPMODE]) {
5903 ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
5904
5905 if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
5906 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
5907 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5908 return -EINVAL;
5909
5910 if ((ht_opmode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) &&
5911 (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5912 return -EINVAL;
5913
5914 switch (ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION) {
5915 case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
5916 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
5917 if (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT)
5918 return -EINVAL;
5919 break;
5920 case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
5921 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
5922 if (!(ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5923 return -EINVAL;
5924 break;
5925 }
5926 cfg->ht_opmode = ht_opmode;
Masashi Honmaf9bd7912017-01-26 08:56:13 +09005927 mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
Masashi Honma97572352016-08-03 10:07:44 +09005928 }
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005929 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
Marco Porschea54fba2013-01-07 16:04:48 +01005930 1, 65535, mask,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005931 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005932 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005933 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005934 mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005935 nl80211_check_u16);
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005936 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005937 dot11MeshHWMPconfirmationInterval,
5938 1, 65535, mask,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005939 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005940 nl80211_check_u16);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005941 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
5942 NL80211_MESH_POWER_ACTIVE,
5943 NL80211_MESH_POWER_MAX,
5944 mask, NL80211_MESHCONF_POWER_MODE,
Johannes Bergff9a71a2016-08-11 14:59:53 +02005945 nl80211_check_power_mode);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005946 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
5947 0, 65535, mask,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005948 NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
Masashi Honma31f909a2015-02-24 22:42:16 +09005949 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005950 mask, NL80211_MESHCONF_PLINK_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005951 nl80211_check_u32);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005952 if (mask_out)
5953 *mask_out = mask;
Javier Cardonac80d5452010-12-16 17:37:49 -08005954
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005955 return 0;
5956
5957#undef FILL_IN_MESH_PARAM_IF_SET
5958}
5959
Javier Cardonac80d5452010-12-16 17:37:49 -08005960static int nl80211_parse_mesh_setup(struct genl_info *info,
5961 struct mesh_setup *setup)
5962{
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08005963 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Javier Cardonac80d5452010-12-16 17:37:49 -08005964 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
5965
5966 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
5967 return -EINVAL;
5968 if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX,
5969 info->attrs[NL80211_ATTR_MESH_SETUP],
5970 nl80211_mesh_setup_params_policy))
5971 return -EINVAL;
5972
Javier Cardonad299a1f2012-03-31 11:31:33 -07005973 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
5974 setup->sync_method =
5975 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
5976 IEEE80211_SYNC_METHOD_VENDOR :
5977 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
5978
Javier Cardonac80d5452010-12-16 17:37:49 -08005979 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
5980 setup->path_sel_proto =
5981 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
5982 IEEE80211_PATH_PROTOCOL_VENDOR :
5983 IEEE80211_PATH_PROTOCOL_HWMP;
5984
5985 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
5986 setup->path_metric =
5987 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
5988 IEEE80211_PATH_METRIC_VENDOR :
5989 IEEE80211_PATH_METRIC_AIRTIME;
5990
Javier Cardona581a8b02011-04-07 15:08:27 -07005991 if (tb[NL80211_MESH_SETUP_IE]) {
Javier Cardonac80d5452010-12-16 17:37:49 -08005992 struct nlattr *ieattr =
Javier Cardona581a8b02011-04-07 15:08:27 -07005993 tb[NL80211_MESH_SETUP_IE];
Javier Cardonac80d5452010-12-16 17:37:49 -08005994 if (!is_valid_ie_attr(ieattr))
5995 return -EINVAL;
Javier Cardona581a8b02011-04-07 15:08:27 -07005996 setup->ie = nla_data(ieattr);
5997 setup->ie_len = nla_len(ieattr);
Javier Cardonac80d5452010-12-16 17:37:49 -08005998 }
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08005999 if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
6000 !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
6001 return -EINVAL;
6002 setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
Javier Cardonab130e5c2011-05-03 16:57:07 -07006003 setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
6004 setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006005 if (setup->is_secure)
6006 setup->user_mpm = true;
Javier Cardonac80d5452010-12-16 17:37:49 -08006007
Colleen Twitty6e16d902013-05-08 11:45:59 -07006008 if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
6009 if (!setup->user_mpm)
6010 return -EINVAL;
6011 setup->auth_id =
6012 nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
6013 }
6014
Javier Cardonac80d5452010-12-16 17:37:49 -08006015 return 0;
6016}
6017
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006018static int nl80211_update_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01006019 struct genl_info *info)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006020{
6021 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6022 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01006023 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006024 struct mesh_config cfg;
6025 u32 mask;
6026 int err;
6027
Johannes Berg29cbe682010-12-03 09:20:44 +01006028 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6029 return -EOPNOTSUPP;
6030
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006031 if (!rdev->ops->update_mesh_config)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006032 return -EOPNOTSUPP;
6033
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006034 err = nl80211_parse_mesh_config(info, &cfg, &mask);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006035 if (err)
6036 return err;
6037
Johannes Berg29cbe682010-12-03 09:20:44 +01006038 wdev_lock(wdev);
6039 if (!wdev->mesh_id_len)
6040 err = -ENOLINK;
6041
6042 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03006043 err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01006044
6045 wdev_unlock(wdev);
6046
6047 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006048}
6049
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006050static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
6051 struct sk_buff *msg)
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006052{
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006053 struct nlattr *nl_reg_rules;
6054 unsigned int i;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006055
Johannes Berg458f4f92012-12-06 15:47:38 +01006056 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
6057 (regdom->dfs_region &&
6058 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006059 goto nla_put_failure;
Johannes Berg458f4f92012-12-06 15:47:38 +01006060
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006061 nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
6062 if (!nl_reg_rules)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006063 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006064
Johannes Berg458f4f92012-12-06 15:47:38 +01006065 for (i = 0; i < regdom->n_reg_rules; i++) {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006066 struct nlattr *nl_reg_rule;
6067 const struct ieee80211_reg_rule *reg_rule;
6068 const struct ieee80211_freq_range *freq_range;
6069 const struct ieee80211_power_rule *power_rule;
Janusz Dziedzic97524822014-01-30 09:52:20 +01006070 unsigned int max_bandwidth_khz;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006071
Johannes Berg458f4f92012-12-06 15:47:38 +01006072 reg_rule = &regdom->reg_rules[i];
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006073 freq_range = &reg_rule->freq_range;
6074 power_rule = &reg_rule->power_rule;
6075
6076 nl_reg_rule = nla_nest_start(msg, i);
6077 if (!nl_reg_rule)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006078 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006079
Janusz Dziedzic97524822014-01-30 09:52:20 +01006080 max_bandwidth_khz = freq_range->max_bandwidth_khz;
6081 if (!max_bandwidth_khz)
6082 max_bandwidth_khz = reg_get_max_bandwidth(regdom,
6083 reg_rule);
6084
David S. Miller9360ffd2012-03-29 04:41:26 -04006085 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
6086 reg_rule->flags) ||
6087 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
6088 freq_range->start_freq_khz) ||
6089 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
6090 freq_range->end_freq_khz) ||
6091 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
Janusz Dziedzic97524822014-01-30 09:52:20 +01006092 max_bandwidth_khz) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04006093 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
6094 power_rule->max_antenna_gain) ||
6095 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
Janusz Dziedzic089027e2014-02-21 19:46:12 +01006096 power_rule->max_eirp) ||
6097 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
6098 reg_rule->dfs_cac_ms))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006099 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006100
6101 nla_nest_end(msg, nl_reg_rule);
6102 }
6103
6104 nla_nest_end(msg, nl_reg_rules);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006105 return 0;
6106
6107nla_put_failure:
6108 return -EMSGSIZE;
6109}
6110
6111static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
6112{
6113 const struct ieee80211_regdomain *regdom = NULL;
6114 struct cfg80211_registered_device *rdev;
6115 struct wiphy *wiphy = NULL;
6116 struct sk_buff *msg;
6117 void *hdr;
6118
6119 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6120 if (!msg)
6121 return -ENOBUFS;
6122
6123 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
6124 NL80211_CMD_GET_REG);
6125 if (!hdr)
6126 goto put_failure;
6127
6128 if (info->attrs[NL80211_ATTR_WIPHY]) {
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006129 bool self_managed;
6130
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006131 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
6132 if (IS_ERR(rdev)) {
6133 nlmsg_free(msg);
6134 return PTR_ERR(rdev);
6135 }
6136
6137 wiphy = &rdev->wiphy;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006138 self_managed = wiphy->regulatory_flags &
6139 REGULATORY_WIPHY_SELF_MANAGED;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006140 regdom = get_wiphy_regdom(wiphy);
6141
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006142 /* a self-managed-reg device must have a private regdom */
6143 if (WARN_ON(!regdom && self_managed)) {
6144 nlmsg_free(msg);
6145 return -EINVAL;
6146 }
6147
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006148 if (regdom &&
6149 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6150 goto nla_put_failure;
6151 }
6152
6153 if (!wiphy && reg_last_request_cell_base() &&
6154 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6155 NL80211_USER_REG_HINT_CELL_BASE))
6156 goto nla_put_failure;
6157
6158 rcu_read_lock();
6159
6160 if (!regdom)
6161 regdom = rcu_dereference(cfg80211_regdomain);
6162
6163 if (nl80211_put_regdom(regdom, msg))
6164 goto nla_put_failure_rcu;
6165
6166 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006167
6168 genlmsg_end(msg, hdr);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006169 return genlmsg_reply(msg, info);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006170
Johannes Berg458f4f92012-12-06 15:47:38 +01006171nla_put_failure_rcu:
6172 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006173nla_put_failure:
6174 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01006175put_failure:
Yuri Ershovd080e272010-06-29 15:08:07 +04006176 nlmsg_free(msg);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006177 return -EMSGSIZE;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006178}
6179
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006180static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
6181 u32 seq, int flags, struct wiphy *wiphy,
6182 const struct ieee80211_regdomain *regdom)
6183{
6184 void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
6185 NL80211_CMD_GET_REG);
6186
6187 if (!hdr)
6188 return -1;
6189
6190 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
6191
6192 if (nl80211_put_regdom(regdom, msg))
6193 goto nla_put_failure;
6194
6195 if (!wiphy && reg_last_request_cell_base() &&
6196 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6197 NL80211_USER_REG_HINT_CELL_BASE))
6198 goto nla_put_failure;
6199
6200 if (wiphy &&
6201 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6202 goto nla_put_failure;
6203
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006204 if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
6205 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
6206 goto nla_put_failure;
6207
Johannes Berg053c0952015-01-16 22:09:00 +01006208 genlmsg_end(msg, hdr);
6209 return 0;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006210
6211nla_put_failure:
6212 genlmsg_cancel(msg, hdr);
6213 return -EMSGSIZE;
6214}
6215
6216static int nl80211_get_reg_dump(struct sk_buff *skb,
6217 struct netlink_callback *cb)
6218{
6219 const struct ieee80211_regdomain *regdom = NULL;
6220 struct cfg80211_registered_device *rdev;
6221 int err, reg_idx, start = cb->args[2];
6222
6223 rtnl_lock();
6224
6225 if (cfg80211_regdomain && start == 0) {
6226 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6227 NLM_F_MULTI, NULL,
6228 rtnl_dereference(cfg80211_regdomain));
6229 if (err < 0)
6230 goto out_err;
6231 }
6232
6233 /* the global regdom is idx 0 */
6234 reg_idx = 1;
6235 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
6236 regdom = get_wiphy_regdom(&rdev->wiphy);
6237 if (!regdom)
6238 continue;
6239
6240 if (++reg_idx <= start)
6241 continue;
6242
6243 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6244 NLM_F_MULTI, &rdev->wiphy, regdom);
6245 if (err < 0) {
6246 reg_idx--;
6247 break;
6248 }
6249 }
6250
6251 cb->args[2] = reg_idx;
6252 err = skb->len;
6253out_err:
6254 rtnl_unlock();
6255 return err;
6256}
6257
Johannes Bergb6863032015-10-15 09:25:18 +02006258#ifdef CONFIG_CFG80211_CRDA_SUPPORT
6259static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
6260 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
6261 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
6262 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
6263 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
6264 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
6265 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
6266 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
6267};
6268
6269static int parse_reg_rule(struct nlattr *tb[],
6270 struct ieee80211_reg_rule *reg_rule)
6271{
6272 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
6273 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
6274
6275 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
6276 return -EINVAL;
6277 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
6278 return -EINVAL;
6279 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
6280 return -EINVAL;
6281 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
6282 return -EINVAL;
6283 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
6284 return -EINVAL;
6285
6286 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
6287
6288 freq_range->start_freq_khz =
6289 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
6290 freq_range->end_freq_khz =
6291 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
6292 freq_range->max_bandwidth_khz =
6293 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
6294
6295 power_rule->max_eirp =
6296 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
6297
6298 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
6299 power_rule->max_antenna_gain =
6300 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
6301
6302 if (tb[NL80211_ATTR_DFS_CAC_TIME])
6303 reg_rule->dfs_cac_ms =
6304 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
6305
6306 return 0;
6307}
6308
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006309static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
6310{
6311 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
6312 struct nlattr *nl_reg_rule;
Johannes Bergea372c52014-11-28 14:54:31 +01006313 char *alpha2;
6314 int rem_reg_rules, r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006315 u32 num_rules = 0, rule_idx = 0, size_of_regd;
Luis R. Rodriguez4c7d3982013-11-13 18:54:02 +01006316 enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
Johannes Bergea372c52014-11-28 14:54:31 +01006317 struct ieee80211_regdomain *rd;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006318
6319 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
6320 return -EINVAL;
6321
6322 if (!info->attrs[NL80211_ATTR_REG_RULES])
6323 return -EINVAL;
6324
6325 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
6326
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006327 if (info->attrs[NL80211_ATTR_DFS_REGION])
6328 dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
6329
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006330 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006331 rem_reg_rules) {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006332 num_rules++;
6333 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
Luis R. Rodriguez4776c6e2009-05-13 17:04:39 -04006334 return -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006335 }
6336
Luis R. Rodrigueze4387682013-11-05 09:18:01 -08006337 if (!reg_is_valid_request(alpha2))
6338 return -EINVAL;
6339
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006340 size_of_regd = sizeof(struct ieee80211_regdomain) +
Johannes Berg1a919312012-12-03 17:21:11 +01006341 num_rules * sizeof(struct ieee80211_reg_rule);
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006342
6343 rd = kzalloc(size_of_regd, GFP_KERNEL);
Johannes Berg6913b492012-12-04 00:48:59 +01006344 if (!rd)
6345 return -ENOMEM;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006346
6347 rd->n_reg_rules = num_rules;
6348 rd->alpha2[0] = alpha2[0];
6349 rd->alpha2[1] = alpha2[1];
6350
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006351 /*
6352 * Disable DFS master mode if the DFS region was
6353 * not supported or known on this kernel.
6354 */
6355 if (reg_supported_dfs_region(dfs_region))
6356 rd->dfs_region = dfs_region;
6357
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006358 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006359 rem_reg_rules) {
Johannes Bergae811e22014-01-24 10:17:47 +01006360 r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
6361 nla_data(nl_reg_rule), nla_len(nl_reg_rule),
6362 reg_rule_policy);
6363 if (r)
6364 goto bad_reg;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006365 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
6366 if (r)
6367 goto bad_reg;
6368
6369 rule_idx++;
6370
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006371 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
6372 r = -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006373 goto bad_reg;
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006374 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006375 }
6376
Johannes Berg06627992016-06-09 10:40:09 +02006377 /* set_regdom takes ownership of rd */
6378 return set_regdom(rd, REGD_SOURCE_CRDA);
Johannes Bergd2372b32008-10-24 20:32:20 +02006379 bad_reg:
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006380 kfree(rd);
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006381 return r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006382}
Johannes Bergb6863032015-10-15 09:25:18 +02006383#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006384
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006385static int validate_scan_freqs(struct nlattr *freqs)
6386{
6387 struct nlattr *attr1, *attr2;
6388 int n_channels = 0, tmp1, tmp2;
6389
Srinivas Dasarie4712902017-07-07 01:43:42 +03006390 nla_for_each_nested(attr1, freqs, tmp1)
6391 if (nla_len(attr1) != sizeof(u32))
6392 return 0;
6393
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006394 nla_for_each_nested(attr1, freqs, tmp1) {
6395 n_channels++;
6396 /*
6397 * Some hardware has a limited channel list for
6398 * scanning, and it is pretty much nonsensical
6399 * to scan for a channel twice, so disallow that
6400 * and don't require drivers to check that the
6401 * channel list they get isn't longer than what
6402 * they can scan, as long as they can scan all
6403 * the channels they registered at once.
6404 */
6405 nla_for_each_nested(attr2, freqs, tmp2)
6406 if (attr1 != attr2 &&
6407 nla_get_u32(attr1) == nla_get_u32(attr2))
6408 return 0;
6409 }
6410
6411 return n_channels;
6412}
6413
Johannes Berg57fbcce2016-04-12 15:56:15 +02006414static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
Arend van Spriel38de03d2016-03-02 20:37:18 +01006415{
Johannes Berg57fbcce2016-04-12 15:56:15 +02006416 return b < NUM_NL80211_BANDS && wiphy->bands[b];
Arend van Spriel38de03d2016-03-02 20:37:18 +01006417}
6418
6419static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
6420 struct cfg80211_bss_selection *bss_select)
6421{
6422 struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
6423 struct nlattr *nest;
6424 int err;
6425 bool found = false;
6426 int i;
6427
6428 /* only process one nested attribute */
6429 nest = nla_data(nla);
6430 if (!nla_ok(nest, nla_len(nest)))
6431 return -EINVAL;
6432
6433 err = nla_parse(attr, NL80211_BSS_SELECT_ATTR_MAX, nla_data(nest),
6434 nla_len(nest), nl80211_bss_select_policy);
6435 if (err)
6436 return err;
6437
6438 /* only one attribute may be given */
6439 for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
6440 if (attr[i]) {
6441 if (found)
6442 return -EINVAL;
6443 found = true;
6444 }
6445 }
6446
6447 bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
6448
6449 if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
6450 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
6451
6452 if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
6453 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
6454 bss_select->param.band_pref =
6455 nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
6456 if (!is_band_valid(wiphy, bss_select->param.band_pref))
6457 return -EINVAL;
6458 }
6459
6460 if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
6461 struct nl80211_bss_select_rssi_adjust *adj_param;
6462
6463 adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
6464 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
6465 bss_select->param.adjust.band = adj_param->band;
6466 bss_select->param.adjust.delta = adj_param->delta;
6467 if (!is_band_valid(wiphy, bss_select->param.adjust.band))
6468 return -EINVAL;
6469 }
6470
6471 /* user-space did not provide behaviour attribute */
6472 if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
6473 return -EINVAL;
6474
6475 if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
6476 return -EINVAL;
6477
6478 return 0;
6479}
6480
Johannes Bergad2b26a2014-06-12 21:39:05 +02006481static int nl80211_parse_random_mac(struct nlattr **attrs,
6482 u8 *mac_addr, u8 *mac_addr_mask)
6483{
6484 int i;
6485
6486 if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
Joe Perchesd2beae12015-03-02 19:54:58 -08006487 eth_zero_addr(mac_addr);
6488 eth_zero_addr(mac_addr_mask);
Johannes Bergad2b26a2014-06-12 21:39:05 +02006489 mac_addr[0] = 0x2;
6490 mac_addr_mask[0] = 0x3;
6491
6492 return 0;
6493 }
6494
6495 /* need both or none */
6496 if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
6497 return -EINVAL;
6498
6499 memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
6500 memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
6501
6502 /* don't allow or configure an mcast address */
6503 if (!is_multicast_ether_addr(mac_addr_mask) ||
6504 is_multicast_ether_addr(mac_addr))
6505 return -EINVAL;
6506
6507 /*
6508 * allow users to pass a MAC address that has bits set outside
6509 * of the mask, but don't bother drivers with having to deal
6510 * with such bits
6511 */
6512 for (i = 0; i < ETH_ALEN; i++)
6513 mac_addr[i] &= mac_addr_mask[i];
6514
6515 return 0;
6516}
6517
Johannes Berg2a519312009-02-10 21:25:55 +01006518static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
6519{
Johannes Berg4c476992010-10-04 21:36:35 +02006520 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfd014282012-06-18 19:17:03 +02006521 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2a519312009-02-10 21:25:55 +01006522 struct cfg80211_scan_request *request;
Johannes Berg2a519312009-02-10 21:25:55 +01006523 struct nlattr *attr;
6524 struct wiphy *wiphy;
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006525 int err, tmp, n_ssids = 0, n_channels, i;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006526 size_t ie_len;
Johannes Berg2a519312009-02-10 21:25:55 +01006527
Johannes Bergf4a11bb2009-03-27 12:40:28 +01006528 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
6529 return -EINVAL;
6530
Johannes Berg79c97e92009-07-07 03:56:12 +02006531 wiphy = &rdev->wiphy;
Johannes Berg2a519312009-02-10 21:25:55 +01006532
Ayala Bekercb3b7d82016-09-20 17:31:13 +03006533 if (wdev->iftype == NL80211_IFTYPE_NAN)
6534 return -EOPNOTSUPP;
6535
Johannes Berg4c476992010-10-04 21:36:35 +02006536 if (!rdev->ops->scan)
6537 return -EOPNOTSUPP;
Johannes Berg2a519312009-02-10 21:25:55 +01006538
Johannes Bergf9d15d12014-01-22 11:14:19 +02006539 if (rdev->scan_req || rdev->scan_msg) {
Johannes Bergf9f47522013-03-19 15:04:07 +01006540 err = -EBUSY;
6541 goto unlock;
6542 }
Johannes Berg2a519312009-02-10 21:25:55 +01006543
6544 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006545 n_channels = validate_scan_freqs(
6546 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Johannes Bergf9f47522013-03-19 15:04:07 +01006547 if (!n_channels) {
6548 err = -EINVAL;
6549 goto unlock;
6550 }
Johannes Berg2a519312009-02-10 21:25:55 +01006551 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006552 n_channels = ieee80211_get_num_supported_channels(wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01006553 }
6554
6555 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
6556 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
6557 n_ssids++;
6558
Johannes Bergf9f47522013-03-19 15:04:07 +01006559 if (n_ssids > wiphy->max_scan_ssids) {
6560 err = -EINVAL;
6561 goto unlock;
6562 }
Johannes Berg2a519312009-02-10 21:25:55 +01006563
Jouni Malinen70692ad2009-02-16 19:39:13 +02006564 if (info->attrs[NL80211_ATTR_IE])
6565 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6566 else
6567 ie_len = 0;
6568
Johannes Bergf9f47522013-03-19 15:04:07 +01006569 if (ie_len > wiphy->max_scan_ie_len) {
6570 err = -EINVAL;
6571 goto unlock;
6572 }
Johannes Berg18a83652009-03-31 12:12:05 +02006573
Johannes Berg2a519312009-02-10 21:25:55 +01006574 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03006575 + sizeof(*request->ssids) * n_ssids
6576 + sizeof(*request->channels) * n_channels
Jouni Malinen70692ad2009-02-16 19:39:13 +02006577 + ie_len, GFP_KERNEL);
Johannes Bergf9f47522013-03-19 15:04:07 +01006578 if (!request) {
6579 err = -ENOMEM;
6580 goto unlock;
6581 }
Johannes Berg2a519312009-02-10 21:25:55 +01006582
Johannes Berg2a519312009-02-10 21:25:55 +01006583 if (n_ssids)
Johannes Berg5ba63532009-08-07 17:54:07 +02006584 request->ssids = (void *)&request->channels[n_channels];
Johannes Berg2a519312009-02-10 21:25:55 +01006585 request->n_ssids = n_ssids;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006586 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01006587 if (n_ssids)
Jouni Malinen70692ad2009-02-16 19:39:13 +02006588 request->ie = (void *)(request->ssids + n_ssids);
6589 else
6590 request->ie = (void *)(request->channels + n_channels);
6591 }
Johannes Berg2a519312009-02-10 21:25:55 +01006592
Johannes Berg584991d2009-11-02 13:32:03 +01006593 i = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01006594 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
6595 /* user specified, bail out if channel not found */
Johannes Berg2a519312009-02-10 21:25:55 +01006596 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
Johannes Berg584991d2009-11-02 13:32:03 +01006597 struct ieee80211_channel *chan;
6598
6599 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
6600
6601 if (!chan) {
Johannes Berg2a519312009-02-10 21:25:55 +01006602 err = -EINVAL;
6603 goto out_free;
6604 }
Johannes Berg584991d2009-11-02 13:32:03 +01006605
6606 /* ignore disabled channels */
6607 if (chan->flags & IEEE80211_CHAN_DISABLED)
6608 continue;
6609
6610 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006611 i++;
6612 }
6613 } else {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006614 enum nl80211_band band;
Johannes Berg34850ab2011-07-18 18:08:35 +02006615
Johannes Berg2a519312009-02-10 21:25:55 +01006616 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006617 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Johannes Berg2a519312009-02-10 21:25:55 +01006618 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07006619
Johannes Berg2a519312009-02-10 21:25:55 +01006620 if (!wiphy->bands[band])
6621 continue;
6622 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
Johannes Berg584991d2009-11-02 13:32:03 +01006623 struct ieee80211_channel *chan;
6624
6625 chan = &wiphy->bands[band]->channels[j];
6626
6627 if (chan->flags & IEEE80211_CHAN_DISABLED)
6628 continue;
6629
6630 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006631 i++;
6632 }
6633 }
6634 }
6635
Johannes Berg584991d2009-11-02 13:32:03 +01006636 if (!i) {
6637 err = -EINVAL;
6638 goto out_free;
6639 }
6640
6641 request->n_channels = i;
6642
Johannes Berg2a519312009-02-10 21:25:55 +01006643 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01006644 if (n_ssids) {
Johannes Berg2a519312009-02-10 21:25:55 +01006645 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03006646 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Johannes Berg2a519312009-02-10 21:25:55 +01006647 err = -EINVAL;
6648 goto out_free;
6649 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03006650 request->ssids[i].ssid_len = nla_len(attr);
Johannes Berg2a519312009-02-10 21:25:55 +01006651 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
Johannes Berg2a519312009-02-10 21:25:55 +01006652 i++;
6653 }
6654 }
6655
Jouni Malinen70692ad2009-02-16 19:39:13 +02006656 if (info->attrs[NL80211_ATTR_IE]) {
6657 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Johannes Bergde95a542009-04-01 11:58:36 +02006658 memcpy((void *)request->ie,
6659 nla_data(info->attrs[NL80211_ATTR_IE]),
Jouni Malinen70692ad2009-02-16 19:39:13 +02006660 request->ie_len);
6661 }
6662
Johannes Berg57fbcce2016-04-12 15:56:15 +02006663 for (i = 0; i < NUM_NL80211_BANDS; i++)
Johannes Berga401d2b2011-07-20 00:52:16 +02006664 if (wiphy->bands[i])
6665 request->rates[i] =
6666 (1 << wiphy->bands[i]->n_bitrates) - 1;
Johannes Berg34850ab2011-07-18 18:08:35 +02006667
6668 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
6669 nla_for_each_nested(attr,
6670 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
6671 tmp) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006672 enum nl80211_band band = nla_type(attr);
Johannes Berg34850ab2011-07-18 18:08:35 +02006673
Johannes Berg57fbcce2016-04-12 15:56:15 +02006674 if (band < 0 || band >= NUM_NL80211_BANDS) {
Johannes Berg34850ab2011-07-18 18:08:35 +02006675 err = -EINVAL;
6676 goto out_free;
6677 }
Felix Fietkau1b09cd82013-11-20 19:40:41 +01006678
6679 if (!wiphy->bands[band])
6680 continue;
6681
Johannes Berg34850ab2011-07-18 18:08:35 +02006682 err = ieee80211_get_ratemask(wiphy->bands[band],
6683 nla_data(attr),
6684 nla_len(attr),
6685 &request->rates[band]);
6686 if (err)
6687 goto out_free;
6688 }
6689 }
6690
Avraham Stern1d762502016-07-05 17:10:13 +03006691 if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
6692 if (!wiphy_ext_feature_isset(wiphy,
6693 NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
6694 err = -EOPNOTSUPP;
6695 goto out_free;
6696 }
6697
6698 request->duration =
6699 nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
6700 request->duration_mandatory =
6701 nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
6702 }
6703
Sam Leffler46856bb2012-10-11 21:03:32 -07006704 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
Sam Lefflered4737712012-10-11 21:03:31 -07006705 request->flags = nla_get_u32(
6706 info->attrs[NL80211_ATTR_SCAN_FLAGS]);
Srinivas Dasaridf7d3c62018-01-17 16:44:16 +05306707 if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
6708 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
6709 ((request->flags & NL80211_SCAN_FLAG_LOW_SPAN) &&
6710 !wiphy_ext_feature_isset(wiphy,
6711 NL80211_EXT_FEATURE_LOW_SPAN_SCAN)) ||
6712 ((request->flags & NL80211_SCAN_FLAG_LOW_POWER) &&
6713 !wiphy_ext_feature_isset(wiphy,
6714 NL80211_EXT_FEATURE_LOW_POWER_SCAN)) ||
6715 ((request->flags & NL80211_SCAN_FLAG_HIGH_ACCURACY) &&
6716 !wiphy_ext_feature_isset(wiphy,
6717 NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN))) {
Sam Leffler46856bb2012-10-11 21:03:32 -07006718 err = -EOPNOTSUPP;
6719 goto out_free;
6720 }
Johannes Bergad2b26a2014-06-12 21:39:05 +02006721
6722 if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
6723 if (!(wiphy->features &
6724 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) {
6725 err = -EOPNOTSUPP;
6726 goto out_free;
6727 }
6728
6729 if (wdev->current_bss) {
6730 err = -EOPNOTSUPP;
6731 goto out_free;
6732 }
6733
6734 err = nl80211_parse_random_mac(info->attrs,
6735 request->mac_addr,
6736 request->mac_addr_mask);
6737 if (err)
6738 goto out_free;
6739 }
Sam Leffler46856bb2012-10-11 21:03:32 -07006740 }
Sam Lefflered4737712012-10-11 21:03:31 -07006741
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05306742 request->no_cck =
6743 nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
6744
Vamsi Krishna45816392016-12-02 23:59:08 +02006745 /* Initial implementation used NL80211_ATTR_MAC to set the specific
6746 * BSSID to scan for. This was problematic because that same attribute
6747 * was already used for another purpose (local random MAC address). The
6748 * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
6749 * compatibility with older userspace components, also use the
6750 * NL80211_ATTR_MAC value here if it can be determined to be used for
6751 * the specific BSSID use case instead of the random MAC address
6752 * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
6753 */
6754 if (info->attrs[NL80211_ATTR_BSSID])
6755 memcpy(request->bssid,
6756 nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
6757 else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
6758 info->attrs[NL80211_ATTR_MAC])
Jouni Malinen818965d2016-02-26 22:12:47 +02006759 memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
6760 ETH_ALEN);
6761 else
6762 eth_broadcast_addr(request->bssid);
6763
Johannes Bergfd014282012-06-18 19:17:03 +02006764 request->wdev = wdev;
Johannes Berg79c97e92009-07-07 03:56:12 +02006765 request->wiphy = &rdev->wiphy;
Sam Leffler15d60302012-10-11 21:03:34 -07006766 request->scan_start = jiffies;
Johannes Berg2a519312009-02-10 21:25:55 +01006767
Johannes Berg79c97e92009-07-07 03:56:12 +02006768 rdev->scan_req = request;
Hila Gonene35e4d22012-06-27 17:19:42 +03006769 err = rdev_scan(rdev, request);
Johannes Berg2a519312009-02-10 21:25:55 +01006770
Johannes Berg463d0182009-07-14 00:33:35 +02006771 if (!err) {
Johannes Bergfd014282012-06-18 19:17:03 +02006772 nl80211_send_scan_start(rdev, wdev);
6773 if (wdev->netdev)
6774 dev_hold(wdev->netdev);
Johannes Berg4c476992010-10-04 21:36:35 +02006775 } else {
Johannes Berg2a519312009-02-10 21:25:55 +01006776 out_free:
Johannes Berg79c97e92009-07-07 03:56:12 +02006777 rdev->scan_req = NULL;
Johannes Berg2a519312009-02-10 21:25:55 +01006778 kfree(request);
6779 }
Johannes Berg3b858752009-03-12 09:55:09 +01006780
Johannes Bergf9f47522013-03-19 15:04:07 +01006781 unlock:
Johannes Berg2a519312009-02-10 21:25:55 +01006782 return err;
6783}
6784
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +05306785static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
6786{
6787 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6788 struct wireless_dev *wdev = info->user_ptr[1];
6789
6790 if (!rdev->ops->abort_scan)
6791 return -EOPNOTSUPP;
6792
6793 if (rdev->scan_msg)
6794 return 0;
6795
6796 if (!rdev->scan_req)
6797 return -ENOENT;
6798
6799 rdev_abort_scan(rdev, wdev);
6800 return 0;
6801}
6802
Avraham Stern3b06d272015-10-12 09:51:34 +03006803static int
6804nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
6805 struct cfg80211_sched_scan_request *request,
6806 struct nlattr **attrs)
6807{
6808 int tmp, err, i = 0;
6809 struct nlattr *attr;
6810
6811 if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
6812 u32 interval;
6813
6814 /*
6815 * If scan plans are not specified,
6816 * %NL80211_ATTR_SCHED_SCAN_INTERVAL must be specified. In this
6817 * case one scan plan will be set with the specified scan
6818 * interval and infinite number of iterations.
6819 */
6820 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
6821 return -EINVAL;
6822
6823 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
6824 if (!interval)
6825 return -EINVAL;
6826
6827 request->scan_plans[0].interval =
6828 DIV_ROUND_UP(interval, MSEC_PER_SEC);
6829 if (!request->scan_plans[0].interval)
6830 return -EINVAL;
6831
6832 if (request->scan_plans[0].interval >
6833 wiphy->max_sched_scan_plan_interval)
6834 request->scan_plans[0].interval =
6835 wiphy->max_sched_scan_plan_interval;
6836
6837 return 0;
6838 }
6839
6840 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
6841 struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
6842
6843 if (WARN_ON(i >= n_plans))
6844 return -EINVAL;
6845
6846 err = nla_parse(plan, NL80211_SCHED_SCAN_PLAN_MAX,
6847 nla_data(attr), nla_len(attr),
6848 nl80211_plan_policy);
6849 if (err)
6850 return err;
6851
6852 if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
6853 return -EINVAL;
6854
6855 request->scan_plans[i].interval =
6856 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
6857 if (!request->scan_plans[i].interval ||
6858 request->scan_plans[i].interval >
6859 wiphy->max_sched_scan_plan_interval)
6860 return -EINVAL;
6861
6862 if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
6863 request->scan_plans[i].iterations =
6864 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
6865 if (!request->scan_plans[i].iterations ||
6866 (request->scan_plans[i].iterations >
6867 wiphy->max_sched_scan_plan_iterations))
6868 return -EINVAL;
6869 } else if (i < n_plans - 1) {
6870 /*
6871 * All scan plans but the last one must specify
6872 * a finite number of iterations
6873 */
6874 return -EINVAL;
6875 }
6876
6877 i++;
6878 }
6879
6880 /*
6881 * The last scan plan must not specify the number of
6882 * iterations, it is supposed to run infinitely
6883 */
6884 if (request->scan_plans[n_plans - 1].iterations)
6885 return -EINVAL;
6886
6887 return 0;
6888}
6889
Luciano Coelho256da022014-11-10 16:13:46 +02006890static struct cfg80211_sched_scan_request *
Johannes Bergad2b26a2014-06-12 21:39:05 +02006891nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
Luciano Coelho256da022014-11-10 16:13:46 +02006892 struct nlattr **attrs)
Luciano Coelho807f8a82011-05-11 17:09:35 +03006893{
6894 struct cfg80211_sched_scan_request *request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006895 struct nlattr *attr;
Avraham Stern3b06d272015-10-12 09:51:34 +03006896 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02006897 enum nl80211_band band;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006898 size_t ie_len;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006899 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
Johannes Bergea73cbc2014-01-24 10:53:53 +01006900 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006901
Luciano Coelho256da022014-11-10 16:13:46 +02006902 if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
6903 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006904
Luciano Coelho256da022014-11-10 16:13:46 +02006905 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03006906 n_channels = validate_scan_freqs(
Luciano Coelho256da022014-11-10 16:13:46 +02006907 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006908 if (!n_channels)
Luciano Coelho256da022014-11-10 16:13:46 +02006909 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006910 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006911 n_channels = ieee80211_get_num_supported_channels(wiphy);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006912 }
6913
Luciano Coelho256da022014-11-10 16:13:46 +02006914 if (attrs[NL80211_ATTR_SCAN_SSIDS])
6915 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03006916 tmp)
6917 n_ssids++;
6918
Luciano Coelho93b6aa62011-07-13 14:57:28 +03006919 if (n_ssids > wiphy->max_sched_scan_ssids)
Luciano Coelho256da022014-11-10 16:13:46 +02006920 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006921
Johannes Bergea73cbc2014-01-24 10:53:53 +01006922 /*
6923 * First, count the number of 'real' matchsets. Due to an issue with
6924 * the old implementation, matchsets containing only the RSSI attribute
6925 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
6926 * RSSI for all matchsets, rather than their own matchset for reporting
6927 * all APs with a strong RSSI. This is needed to be compatible with
6928 * older userspace that treated a matchset with only the RSSI as the
6929 * global RSSI for all other matchsets - if there are other matchsets.
6930 */
Luciano Coelho256da022014-11-10 16:13:46 +02006931 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006932 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02006933 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Johannes Bergea73cbc2014-01-24 10:53:53 +01006934 tmp) {
6935 struct nlattr *rssi;
6936
6937 err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
6938 nla_data(attr), nla_len(attr),
6939 nl80211_match_policy);
6940 if (err)
Luciano Coelho256da022014-11-10 16:13:46 +02006941 return ERR_PTR(err);
Johannes Bergea73cbc2014-01-24 10:53:53 +01006942 /* add other standalone attributes here */
6943 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
6944 n_match_sets++;
6945 continue;
6946 }
6947 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
6948 if (rssi)
6949 default_match_rssi = nla_get_s32(rssi);
6950 }
6951 }
6952
6953 /* However, if there's no other matchset, add the RSSI one */
6954 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
6955 n_match_sets = 1;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006956
6957 if (n_match_sets > wiphy->max_match_sets)
Luciano Coelho256da022014-11-10 16:13:46 +02006958 return ERR_PTR(-EINVAL);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006959
Luciano Coelho256da022014-11-10 16:13:46 +02006960 if (attrs[NL80211_ATTR_IE])
6961 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006962 else
6963 ie_len = 0;
6964
Luciano Coelho5a865ba2011-07-13 14:57:29 +03006965 if (ie_len > wiphy->max_sched_scan_ie_len)
Luciano Coelho256da022014-11-10 16:13:46 +02006966 return ERR_PTR(-EINVAL);
Luciano Coelhoc10841c2011-06-30 08:32:41 +03006967
Avraham Stern3b06d272015-10-12 09:51:34 +03006968 if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
6969 /*
6970 * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
6971 * each scan plan already specifies its own interval
6972 */
6973 if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
6974 return ERR_PTR(-EINVAL);
6975
6976 nla_for_each_nested(attr,
6977 attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
6978 n_plans++;
6979 } else {
6980 /*
6981 * The scan interval attribute is kept for backward
6982 * compatibility. If no scan plans are specified and sched scan
6983 * interval is specified, one scan plan will be set with this
6984 * scan interval and infinite number of iterations.
6985 */
6986 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
6987 return ERR_PTR(-EINVAL);
6988
6989 n_plans = 1;
6990 }
6991
6992 if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
6993 return ERR_PTR(-EINVAL);
6994
vamsi krishnaf4f1a542017-01-13 01:12:20 +02006995 if (!wiphy_ext_feature_isset(
6996 wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
6997 (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
6998 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
6999 return ERR_PTR(-EINVAL);
7000
Luciano Coelho807f8a82011-05-11 17:09:35 +03007001 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007002 + sizeof(*request->ssids) * n_ssids
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007003 + sizeof(*request->match_sets) * n_match_sets
Avraham Stern3b06d272015-10-12 09:51:34 +03007004 + sizeof(*request->scan_plans) * n_plans
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007005 + sizeof(*request->channels) * n_channels
Luciano Coelho807f8a82011-05-11 17:09:35 +03007006 + ie_len, GFP_KERNEL);
Luciano Coelho256da022014-11-10 16:13:46 +02007007 if (!request)
7008 return ERR_PTR(-ENOMEM);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007009
7010 if (n_ssids)
7011 request->ssids = (void *)&request->channels[n_channels];
7012 request->n_ssids = n_ssids;
7013 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01007014 if (n_ssids)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007015 request->ie = (void *)(request->ssids + n_ssids);
7016 else
7017 request->ie = (void *)(request->channels + n_channels);
7018 }
7019
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007020 if (n_match_sets) {
7021 if (request->ie)
7022 request->match_sets = (void *)(request->ie + ie_len);
Johannes Berg13874e42015-01-23 11:25:20 +01007023 else if (n_ssids)
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007024 request->match_sets =
7025 (void *)(request->ssids + n_ssids);
7026 else
7027 request->match_sets =
7028 (void *)(request->channels + n_channels);
7029 }
7030 request->n_match_sets = n_match_sets;
7031
Avraham Stern3b06d272015-10-12 09:51:34 +03007032 if (n_match_sets)
7033 request->scan_plans = (void *)(request->match_sets +
7034 n_match_sets);
7035 else if (request->ie)
7036 request->scan_plans = (void *)(request->ie + ie_len);
7037 else if (n_ssids)
7038 request->scan_plans = (void *)(request->ssids + n_ssids);
7039 else
7040 request->scan_plans = (void *)(request->channels + n_channels);
7041
7042 request->n_scan_plans = n_plans;
7043
Luciano Coelho807f8a82011-05-11 17:09:35 +03007044 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007045 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007046 /* user specified, bail out if channel not found */
7047 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007048 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007049 tmp) {
7050 struct ieee80211_channel *chan;
7051
7052 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
7053
7054 if (!chan) {
7055 err = -EINVAL;
7056 goto out_free;
7057 }
7058
7059 /* ignore disabled channels */
7060 if (chan->flags & IEEE80211_CHAN_DISABLED)
7061 continue;
7062
7063 request->channels[i] = chan;
7064 i++;
7065 }
7066 } else {
7067 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007068 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007069 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007070
Luciano Coelho807f8a82011-05-11 17:09:35 +03007071 if (!wiphy->bands[band])
7072 continue;
7073 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
7074 struct ieee80211_channel *chan;
7075
7076 chan = &wiphy->bands[band]->channels[j];
7077
7078 if (chan->flags & IEEE80211_CHAN_DISABLED)
7079 continue;
7080
7081 request->channels[i] = chan;
7082 i++;
7083 }
7084 }
7085 }
7086
7087 if (!i) {
7088 err = -EINVAL;
7089 goto out_free;
7090 }
7091
7092 request->n_channels = i;
7093
7094 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01007095 if (n_ssids) {
Luciano Coelho256da022014-11-10 16:13:46 +02007096 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007097 tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03007098 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007099 err = -EINVAL;
7100 goto out_free;
7101 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03007102 request->ssids[i].ssid_len = nla_len(attr);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007103 memcpy(request->ssids[i].ssid, nla_data(attr),
7104 nla_len(attr));
Luciano Coelho807f8a82011-05-11 17:09:35 +03007105 i++;
7106 }
7107 }
7108
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007109 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007110 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007111 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007112 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007113 tmp) {
Thomas Pedersen88e920b2012-06-21 11:09:54 -07007114 struct nlattr *ssid, *rssi;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007115
Johannes Bergae811e22014-01-24 10:17:47 +01007116 err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
7117 nla_data(attr), nla_len(attr),
7118 nl80211_match_policy);
7119 if (err)
7120 goto out_free;
Johannes Berg4a4ab0d2012-06-13 11:17:11 +02007121 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007122 if (ssid) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01007123 if (WARN_ON(i >= n_match_sets)) {
7124 /* this indicates a programming error,
7125 * the loop above should have verified
7126 * things properly
7127 */
7128 err = -EINVAL;
7129 goto out_free;
7130 }
7131
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007132 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
7133 err = -EINVAL;
7134 goto out_free;
7135 }
7136 memcpy(request->match_sets[i].ssid.ssid,
7137 nla_data(ssid), nla_len(ssid));
7138 request->match_sets[i].ssid.ssid_len =
7139 nla_len(ssid);
Kirtika Ruchandani56ab3642016-05-29 19:54:10 -07007140 /* special attribute - old implementation w/a */
Johannes Bergea73cbc2014-01-24 10:53:53 +01007141 request->match_sets[i].rssi_thold =
7142 default_match_rssi;
7143 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7144 if (rssi)
7145 request->match_sets[i].rssi_thold =
7146 nla_get_s32(rssi);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007147 }
7148 i++;
7149 }
Johannes Bergea73cbc2014-01-24 10:53:53 +01007150
7151 /* there was no other matchset, so the RSSI one is alone */
Luciano Coelhof89f46c2014-12-01 11:32:09 +02007152 if (i == 0 && n_match_sets)
Johannes Bergea73cbc2014-01-24 10:53:53 +01007153 request->match_sets[0].rssi_thold = default_match_rssi;
7154
7155 request->min_rssi_thold = INT_MAX;
7156 for (i = 0; i < n_match_sets; i++)
7157 request->min_rssi_thold =
7158 min(request->match_sets[i].rssi_thold,
7159 request->min_rssi_thold);
7160 } else {
7161 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007162 }
7163
Johannes Berg9900e482014-02-04 21:01:25 +01007164 if (ie_len) {
7165 request->ie_len = ie_len;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007166 memcpy((void *)request->ie,
Luciano Coelho256da022014-11-10 16:13:46 +02007167 nla_data(attrs[NL80211_ATTR_IE]),
Luciano Coelho807f8a82011-05-11 17:09:35 +03007168 request->ie_len);
7169 }
7170
Luciano Coelho256da022014-11-10 16:13:46 +02007171 if (attrs[NL80211_ATTR_SCAN_FLAGS]) {
Sam Lefflered4737712012-10-11 21:03:31 -07007172 request->flags = nla_get_u32(
Luciano Coelho256da022014-11-10 16:13:46 +02007173 attrs[NL80211_ATTR_SCAN_FLAGS]);
Johannes Berg00c3a6e2013-10-26 17:14:38 +02007174 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
7175 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
Sam Leffler46856bb2012-10-11 21:03:32 -07007176 err = -EOPNOTSUPP;
7177 goto out_free;
7178 }
Johannes Bergad2b26a2014-06-12 21:39:05 +02007179
7180 if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
7181 u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7182
7183 if (!wdev) /* must be net-detect */
7184 flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7185
7186 if (!(wiphy->features & flg)) {
7187 err = -EOPNOTSUPP;
7188 goto out_free;
7189 }
7190
7191 if (wdev && wdev->current_bss) {
7192 err = -EOPNOTSUPP;
7193 goto out_free;
7194 }
7195
7196 err = nl80211_parse_random_mac(attrs, request->mac_addr,
7197 request->mac_addr_mask);
7198 if (err)
7199 goto out_free;
7200 }
Sam Leffler46856bb2012-10-11 21:03:32 -07007201 }
Sam Lefflered4737712012-10-11 21:03:31 -07007202
Luciano Coelho9c748932015-01-16 16:04:09 +02007203 if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
7204 request->delay =
7205 nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
7206
vamsi krishnaf4f1a542017-01-13 01:12:20 +02007207 if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
7208 request->relative_rssi = nla_get_s8(
7209 attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
7210 request->relative_rssi_set = true;
7211 }
7212
7213 if (request->relative_rssi_set &&
7214 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
7215 struct nl80211_bss_select_rssi_adjust *rssi_adjust;
7216
7217 rssi_adjust = nla_data(
7218 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
7219 request->rssi_adjust.band = rssi_adjust->band;
7220 request->rssi_adjust.delta = rssi_adjust->delta;
7221 if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
7222 err = -EINVAL;
7223 goto out_free;
7224 }
7225 }
7226
Avraham Stern3b06d272015-10-12 09:51:34 +03007227 err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
7228 if (err)
7229 goto out_free;
7230
Sam Leffler15d60302012-10-11 21:03:34 -07007231 request->scan_start = jiffies;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007232
Luciano Coelho256da022014-11-10 16:13:46 +02007233 return request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007234
7235out_free:
7236 kfree(request);
Luciano Coelho256da022014-11-10 16:13:46 +02007237 return ERR_PTR(err);
7238}
7239
7240static int nl80211_start_sched_scan(struct sk_buff *skb,
7241 struct genl_info *info)
7242{
7243 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7244 struct net_device *dev = info->user_ptr[1];
Johannes Bergad2b26a2014-06-12 21:39:05 +02007245 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007246 struct cfg80211_sched_scan_request *sched_scan_req;
Luciano Coelho256da022014-11-10 16:13:46 +02007247 int err;
7248
7249 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
7250 !rdev->ops->sched_scan_start)
7251 return -EOPNOTSUPP;
7252
7253 if (rdev->sched_scan_req)
7254 return -EINPROGRESS;
7255
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007256 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
7257 info->attrs);
7258
7259 err = PTR_ERR_OR_ZERO(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007260 if (err)
7261 goto out_err;
7262
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007263 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007264 if (err)
7265 goto out_free;
7266
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007267 sched_scan_req->dev = dev;
7268 sched_scan_req->wiphy = &rdev->wiphy;
7269
Jukka Rissanen93a1e862014-12-15 13:25:39 +02007270 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
7271 sched_scan_req->owner_nlportid = info->snd_portid;
7272
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007273 rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007274
7275 nl80211_send_sched_scan(rdev, dev,
7276 NL80211_CMD_START_SCHED_SCAN);
7277 return 0;
7278
7279out_free:
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007280 kfree(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007281out_err:
Luciano Coelho807f8a82011-05-11 17:09:35 +03007282 return err;
7283}
7284
7285static int nl80211_stop_sched_scan(struct sk_buff *skb,
7286 struct genl_info *info)
7287{
7288 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7289
7290 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
7291 !rdev->ops->sched_scan_stop)
7292 return -EOPNOTSUPP;
7293
Johannes Berg5fe231e2013-05-08 21:45:15 +02007294 return __cfg80211_stop_sched_scan(rdev, false);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007295}
7296
Simon Wunderlich04f39042013-02-08 18:16:19 +01007297static int nl80211_start_radar_detection(struct sk_buff *skb,
7298 struct genl_info *info)
7299{
7300 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7301 struct net_device *dev = info->user_ptr[1];
7302 struct wireless_dev *wdev = dev->ieee80211_ptr;
7303 struct cfg80211_chan_def chandef;
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007304 enum nl80211_dfs_regions dfs_region;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007305 unsigned int cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007306 int err;
7307
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007308 dfs_region = reg_get_dfs_region(wdev->wiphy);
7309 if (dfs_region == NL80211_DFS_UNSET)
7310 return -EINVAL;
7311
Simon Wunderlich04f39042013-02-08 18:16:19 +01007312 err = nl80211_parse_chandef(rdev, info, &chandef);
7313 if (err)
7314 return err;
7315
Simon Wunderlichff311bc2013-09-03 19:43:18 +02007316 if (netif_carrier_ok(dev))
7317 return -EBUSY;
7318
Amar Singhal42839af2014-03-19 18:36:58 -07007319 if (rdev->wiphy.flags & WIPHY_FLAG_DFS_OFFLOAD)
7320 return -EOPNOTSUPP;
7321
Simon Wunderlich04f39042013-02-08 18:16:19 +01007322 if (wdev->cac_started)
7323 return -EBUSY;
7324
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007325 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
Luciano Coelho00ec75f2014-05-15 13:05:39 +03007326 wdev->iftype);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007327 if (err < 0)
7328 return err;
7329
7330 if (err == 0)
7331 return -EINVAL;
7332
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +01007333 if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
Simon Wunderlich04f39042013-02-08 18:16:19 +01007334 return -EINVAL;
7335
7336 if (!rdev->ops->start_radar_detection)
7337 return -EOPNOTSUPP;
7338
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007339 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
7340 if (WARN_ON(!cac_time_ms))
7341 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
7342
Ilan Peera1056b12015-10-22 22:27:46 +03007343 err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007344 if (!err) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01007345 wdev->chandef = chandef;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007346 wdev->cac_started = true;
7347 wdev->cac_start_time = jiffies;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007348 wdev->cac_time_ms = cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007349 }
Simon Wunderlich04f39042013-02-08 18:16:19 +01007350 return err;
7351}
7352
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007353static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
7354{
7355 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7356 struct net_device *dev = info->user_ptr[1];
7357 struct wireless_dev *wdev = dev->ieee80211_ptr;
7358 struct cfg80211_csa_settings params;
7359 /* csa_attrs is defined static to avoid waste of stack size - this
7360 * function is called under RTNL lock, so this should not be a problem.
7361 */
7362 static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007363 int err;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007364 bool need_new_beacon = false;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007365 int len, i;
Luciano Coelho252e07c2014-10-08 09:48:34 +03007366 u32 cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007367
7368 if (!rdev->ops->channel_switch ||
7369 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
7370 return -EOPNOTSUPP;
7371
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007372 switch (dev->ieee80211_ptr->iftype) {
7373 case NL80211_IFTYPE_AP:
7374 case NL80211_IFTYPE_P2P_GO:
7375 need_new_beacon = true;
7376
7377 /* useless if AP is not running */
7378 if (!wdev->beacon_interval)
Johannes Berg1ff79df2014-01-22 10:05:27 +01007379 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007380 break;
7381 case NL80211_IFTYPE_ADHOC:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007382 if (!wdev->ssid_len)
7383 return -ENOTCONN;
7384 break;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07007385 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007386 if (!wdev->mesh_id_len)
7387 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007388 break;
7389 default:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007390 return -EOPNOTSUPP;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007391 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007392
7393 memset(&params, 0, sizeof(params));
7394
7395 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
7396 !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
7397 return -EINVAL;
7398
7399 /* only important for AP, IBSS and mesh create IEs internally */
Andrei Otcheretianskid0a361a2013-10-17 10:52:17 +02007400 if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007401 return -EINVAL;
7402
Luciano Coelho252e07c2014-10-08 09:48:34 +03007403 /* Even though the attribute is u32, the specification says
7404 * u8, so let's make sure we don't overflow.
7405 */
7406 cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
7407 if (cs_count > 255)
7408 return -EINVAL;
7409
7410 params.count = cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007411
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007412 if (!need_new_beacon)
7413 goto skip_beacons;
7414
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007415 err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
7416 if (err)
7417 return err;
7418
7419 err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
7420 info->attrs[NL80211_ATTR_CSA_IES],
7421 nl80211_policy);
7422 if (err)
7423 return err;
7424
7425 err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
7426 if (err)
7427 return err;
7428
7429 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
7430 return -EINVAL;
7431
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007432 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7433 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007434 return -EINVAL;
7435
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007436 params.n_counter_offsets_beacon = len / sizeof(u16);
7437 if (rdev->wiphy.max_num_csa_counters &&
7438 (params.n_counter_offsets_beacon >
7439 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007440 return -EINVAL;
7441
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007442 params.counter_offsets_beacon =
7443 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7444
7445 /* sanity checks - counters should fit and be the same */
7446 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
7447 u16 offset = params.counter_offsets_beacon[i];
7448
7449 if (offset >= params.beacon_csa.tail_len)
7450 return -EINVAL;
7451
7452 if (params.beacon_csa.tail[offset] != params.count)
7453 return -EINVAL;
7454 }
7455
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007456 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007457 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
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_presp = len / sizeof(u16);
7462 if (rdev->wiphy.max_num_csa_counters &&
Johannes Bergad5987b2016-09-13 15:53:55 +02007463 (params.n_counter_offsets_presp >
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007464 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007465 return -EINVAL;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007466
7467 params.counter_offsets_presp =
7468 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7469
7470 /* sanity checks - counters should fit and be the same */
7471 for (i = 0; i < params.n_counter_offsets_presp; i++) {
7472 u16 offset = params.counter_offsets_presp[i];
7473
7474 if (offset >= params.beacon_csa.probe_resp_len)
7475 return -EINVAL;
7476
7477 if (params.beacon_csa.probe_resp[offset] !=
7478 params.count)
7479 return -EINVAL;
7480 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007481 }
7482
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007483skip_beacons:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007484 err = nl80211_parse_chandef(rdev, info, &params.chandef);
7485 if (err)
7486 return err;
7487
Arik Nemtsov923b3522015-07-08 15:41:44 +03007488 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
7489 wdev->iftype))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007490 return -EINVAL;
7491
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007492 err = cfg80211_chandef_dfs_required(wdev->wiphy,
7493 &params.chandef,
7494 wdev->iftype);
7495 if (err < 0)
7496 return err;
7497
Fabian Frederickdcc6c2f2014-10-25 17:57:35 +02007498 if (err > 0)
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007499 params.radar_required = true;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007500
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007501 if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
7502 params.block_tx = true;
7503
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007504 wdev_lock(wdev);
7505 err = rdev_channel_switch(rdev, dev, &params);
7506 wdev_unlock(wdev);
7507
7508 return err;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007509}
7510
Johannes Berg9720bb32011-06-21 09:45:33 +02007511static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
7512 u32 seq, int flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007513 struct cfg80211_registered_device *rdev,
Johannes Berg48ab9052009-07-10 18:42:31 +02007514 struct wireless_dev *wdev,
7515 struct cfg80211_internal_bss *intbss)
Johannes Berg2a519312009-02-10 21:25:55 +01007516{
Johannes Berg48ab9052009-07-10 18:42:31 +02007517 struct cfg80211_bss *res = &intbss->pub;
Johannes Berg9caf0362012-11-29 01:25:20 +01007518 const struct cfg80211_bss_ies *ies;
Johannes Berg2a519312009-02-10 21:25:55 +01007519 void *hdr;
7520 struct nlattr *bss;
Johannes Berg48ab9052009-07-10 18:42:31 +02007521
7522 ASSERT_WDEV_LOCK(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007523
Eric W. Biederman15e47302012-09-07 20:12:54 +00007524 hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007525 NL80211_CMD_NEW_SCAN_RESULTS);
7526 if (!hdr)
7527 return -1;
7528
Johannes Berg9720bb32011-06-21 09:45:33 +02007529 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
7530
Johannes Berg97990a02013-04-19 01:02:55 +02007531 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
7532 goto nla_put_failure;
7533 if (wdev->netdev &&
David S. Miller9360ffd2012-03-29 04:41:26 -04007534 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
7535 goto nla_put_failure;
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007536 if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
7537 NL80211_ATTR_PAD))
Johannes Berg97990a02013-04-19 01:02:55 +02007538 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007539
7540 bss = nla_nest_start(msg, NL80211_ATTR_BSS);
7541 if (!bss)
7542 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04007543 if ((!is_zero_ether_addr(res->bssid) &&
Johannes Berg9caf0362012-11-29 01:25:20 +01007544 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
David S. Miller9360ffd2012-03-29 04:41:26 -04007545 goto nla_put_failure;
Johannes Berg9caf0362012-11-29 01:25:20 +01007546
7547 rcu_read_lock();
Johannes Berg0e227082014-08-12 20:34:30 +02007548 /* indicate whether we have probe response data or not */
7549 if (rcu_access_pointer(res->proberesp_ies) &&
7550 nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
7551 goto fail_unlock_rcu;
7552
7553 /* this pointer prefers to be pointed to probe response data
7554 * but is always valid
7555 */
Johannes Berg9caf0362012-11-29 01:25:20 +01007556 ies = rcu_dereference(res->ies);
Johannes Berg8cef2c92013-02-05 16:54:31 +01007557 if (ies) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007558 if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
7559 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007560 goto fail_unlock_rcu;
Johannes Berg8cef2c92013-02-05 16:54:31 +01007561 if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
7562 ies->len, ies->data))
7563 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007564 }
Johannes Berg0e227082014-08-12 20:34:30 +02007565
7566 /* and this pointer is always (unless driver didn't know) beacon data */
Johannes Berg9caf0362012-11-29 01:25:20 +01007567 ies = rcu_dereference(res->beacon_ies);
Johannes Berg0e227082014-08-12 20:34:30 +02007568 if (ies && ies->from_beacon) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007569 if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
7570 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007571 goto fail_unlock_rcu;
7572 if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
7573 ies->len, ies->data))
7574 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007575 }
7576 rcu_read_unlock();
7577
David S. Miller9360ffd2012-03-29 04:41:26 -04007578 if (res->beacon_interval &&
7579 nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
7580 goto nla_put_failure;
7581 if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
7582 nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
Simon Wunderlichdcd6eac2013-07-08 16:55:49 +02007583 nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007584 nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
7585 jiffies_to_msecs(jiffies - intbss->ts)))
7586 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007587
Avraham Stern1d762502016-07-05 17:10:13 +03007588 if (intbss->parent_tsf &&
7589 (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
7590 intbss->parent_tsf, NL80211_BSS_PAD) ||
7591 nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
7592 intbss->parent_bssid)))
7593 goto nla_put_failure;
7594
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007595 if (intbss->ts_boottime &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007596 nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
7597 intbss->ts_boottime, NL80211_BSS_PAD))
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007598 goto nla_put_failure;
7599
Sunil Dutt0c868482017-12-13 19:51:36 +02007600 if (!nl80211_put_signal(msg, intbss->pub.chains,
7601 intbss->pub.chain_signal,
7602 NL80211_BSS_CHAIN_SIGNAL))
7603 goto nla_put_failure;
7604
Johannes Berg77965c92009-02-18 18:45:06 +01007605 switch (rdev->wiphy.signal_type) {
Johannes Berg2a519312009-02-10 21:25:55 +01007606 case CFG80211_SIGNAL_TYPE_MBM:
David S. Miller9360ffd2012-03-29 04:41:26 -04007607 if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
7608 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007609 break;
7610 case CFG80211_SIGNAL_TYPE_UNSPEC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007611 if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
7612 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007613 break;
7614 default:
7615 break;
7616 }
7617
Johannes Berg48ab9052009-07-10 18:42:31 +02007618 switch (wdev->iftype) {
Johannes Berg074ac8d2010-09-16 14:58:22 +02007619 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg48ab9052009-07-10 18:42:31 +02007620 case NL80211_IFTYPE_STATION:
David S. Miller9360ffd2012-03-29 04:41:26 -04007621 if (intbss == wdev->current_bss &&
7622 nla_put_u32(msg, NL80211_BSS_STATUS,
7623 NL80211_BSS_STATUS_ASSOCIATED))
7624 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007625 break;
7626 case NL80211_IFTYPE_ADHOC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007627 if (intbss == wdev->current_bss &&
7628 nla_put_u32(msg, NL80211_BSS_STATUS,
7629 NL80211_BSS_STATUS_IBSS_JOINED))
7630 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007631 break;
7632 default:
7633 break;
7634 }
7635
Johannes Berg2a519312009-02-10 21:25:55 +01007636 nla_nest_end(msg, bss);
7637
Johannes Berg053c0952015-01-16 22:09:00 +01007638 genlmsg_end(msg, hdr);
7639 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007640
Johannes Berg8cef2c92013-02-05 16:54:31 +01007641 fail_unlock_rcu:
7642 rcu_read_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01007643 nla_put_failure:
7644 genlmsg_cancel(msg, hdr);
7645 return -EMSGSIZE;
7646}
7647
Johannes Berg97990a02013-04-19 01:02:55 +02007648static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
Johannes Berg2a519312009-02-10 21:25:55 +01007649{
Johannes Berg48ab9052009-07-10 18:42:31 +02007650 struct cfg80211_registered_device *rdev;
Johannes Berg2a519312009-02-10 21:25:55 +01007651 struct cfg80211_internal_bss *scan;
Johannes Berg48ab9052009-07-10 18:42:31 +02007652 struct wireless_dev *wdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007653 int start = cb->args[2], idx = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007654 int err;
7655
Johannes Berg56769e72017-03-15 14:26:04 +01007656 rtnl_lock();
Johannes Berg97990a02013-04-19 01:02:55 +02007657 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg56769e72017-03-15 14:26:04 +01007658 if (err) {
7659 rtnl_unlock();
Johannes Berg67748892010-10-04 21:14:06 +02007660 return err;
Johannes Berg56769e72017-03-15 14:26:04 +01007661 }
Johannes Berg2a519312009-02-10 21:25:55 +01007662
Johannes Berg48ab9052009-07-10 18:42:31 +02007663 wdev_lock(wdev);
7664 spin_lock_bh(&rdev->bss_lock);
7665 cfg80211_bss_expire(rdev);
7666
Johannes Berg9720bb32011-06-21 09:45:33 +02007667 cb->seq = rdev->bss_generation;
7668
Johannes Berg48ab9052009-07-10 18:42:31 +02007669 list_for_each_entry(scan, &rdev->bss_list, list) {
Johannes Berg2a519312009-02-10 21:25:55 +01007670 if (++idx <= start)
7671 continue;
Johannes Berg9720bb32011-06-21 09:45:33 +02007672 if (nl80211_send_bss(skb, cb,
Johannes Berg2a519312009-02-10 21:25:55 +01007673 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg48ab9052009-07-10 18:42:31 +02007674 rdev, wdev, scan) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +01007675 idx--;
Johannes Berg67748892010-10-04 21:14:06 +02007676 break;
Johannes Berg2a519312009-02-10 21:25:55 +01007677 }
7678 }
7679
Johannes Berg48ab9052009-07-10 18:42:31 +02007680 spin_unlock_bh(&rdev->bss_lock);
7681 wdev_unlock(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007682
Johannes Berg97990a02013-04-19 01:02:55 +02007683 cb->args[2] = idx;
Johannes Berg56769e72017-03-15 14:26:04 +01007684 rtnl_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01007685
Johannes Berg67748892010-10-04 21:14:06 +02007686 return skb->len;
Johannes Berg2a519312009-02-10 21:25:55 +01007687}
7688
Eric W. Biederman15e47302012-09-07 20:12:54 +00007689static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007690 int flags, struct net_device *dev,
7691 bool allow_radio_stats,
7692 struct survey_info *survey)
Holger Schurig61fa7132009-11-11 12:25:40 +01007693{
7694 void *hdr;
7695 struct nlattr *infoattr;
7696
Johannes Berg11f78ac2014-11-14 16:43:50 +01007697 /* skip radio stats if userspace didn't request them */
7698 if (!survey->channel && !allow_radio_stats)
7699 return 0;
7700
Eric W. Biederman15e47302012-09-07 20:12:54 +00007701 hdr = nl80211hdr_put(msg, portid, seq, flags,
Holger Schurig61fa7132009-11-11 12:25:40 +01007702 NL80211_CMD_NEW_SURVEY_RESULTS);
7703 if (!hdr)
7704 return -ENOMEM;
7705
David S. Miller9360ffd2012-03-29 04:41:26 -04007706 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
7707 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007708
7709 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
7710 if (!infoattr)
7711 goto nla_put_failure;
7712
Johannes Berg11f78ac2014-11-14 16:43:50 +01007713 if (survey->channel &&
7714 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
David S. Miller9360ffd2012-03-29 04:41:26 -04007715 survey->channel->center_freq))
7716 goto nla_put_failure;
7717
7718 if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
7719 nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
7720 goto nla_put_failure;
7721 if ((survey->filled & SURVEY_INFO_IN_USE) &&
7722 nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
7723 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007724 if ((survey->filled & SURVEY_INFO_TIME) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007725 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
7726 survey->time, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007727 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007728 if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007729 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
7730 survey->time_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007731 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007732 if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007733 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
7734 survey->time_ext_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007735 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007736 if ((survey->filled & SURVEY_INFO_TIME_RX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007737 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
7738 survey->time_rx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007739 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007740 if ((survey->filled & SURVEY_INFO_TIME_TX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007741 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
7742 survey->time_tx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007743 goto nla_put_failure;
Johannes Berg052536a2014-11-14 16:44:11 +01007744 if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007745 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
7746 survey->time_scan, NL80211_SURVEY_INFO_PAD))
Johannes Berg052536a2014-11-14 16:44:11 +01007747 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007748
7749 nla_nest_end(msg, infoattr);
7750
Johannes Berg053c0952015-01-16 22:09:00 +01007751 genlmsg_end(msg, hdr);
7752 return 0;
Holger Schurig61fa7132009-11-11 12:25:40 +01007753
7754 nla_put_failure:
7755 genlmsg_cancel(msg, hdr);
7756 return -EMSGSIZE;
7757}
7758
Johannes Berg11f78ac2014-11-14 16:43:50 +01007759static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
Holger Schurig61fa7132009-11-11 12:25:40 +01007760{
7761 struct survey_info survey;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007762 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007763 struct wireless_dev *wdev;
7764 int survey_idx = cb->args[2];
Holger Schurig61fa7132009-11-11 12:25:40 +01007765 int res;
Johannes Berg11f78ac2014-11-14 16:43:50 +01007766 bool radio_stats;
Holger Schurig61fa7132009-11-11 12:25:40 +01007767
Johannes Berg56769e72017-03-15 14:26:04 +01007768 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007769 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007770 if (res)
Johannes Berg56769e72017-03-15 14:26:04 +01007771 goto out_err;
Holger Schurig61fa7132009-11-11 12:25:40 +01007772
Johannes Berg11f78ac2014-11-14 16:43:50 +01007773 /* prepare_wdev_dump parsed the attributes */
7774 radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
7775
Johannes Berg97990a02013-04-19 01:02:55 +02007776 if (!wdev->netdev) {
7777 res = -EINVAL;
7778 goto out_err;
7779 }
7780
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007781 if (!rdev->ops->dump_survey) {
Holger Schurig61fa7132009-11-11 12:25:40 +01007782 res = -EOPNOTSUPP;
7783 goto out_err;
7784 }
7785
7786 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007787 res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
Holger Schurig61fa7132009-11-11 12:25:40 +01007788 if (res == -ENOENT)
7789 break;
7790 if (res)
7791 goto out_err;
7792
Johannes Berg11f78ac2014-11-14 16:43:50 +01007793 /* don't send disabled channels, but do send non-channel data */
7794 if (survey.channel &&
7795 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
Luis R. Rodriguez180cdc72011-05-27 07:24:02 -07007796 survey_idx++;
7797 continue;
7798 }
7799
Holger Schurig61fa7132009-11-11 12:25:40 +01007800 if (nl80211_send_survey(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00007801 NETLINK_CB(cb->skb).portid,
Holger Schurig61fa7132009-11-11 12:25:40 +01007802 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007803 wdev->netdev, radio_stats, &survey) < 0)
Holger Schurig61fa7132009-11-11 12:25:40 +01007804 goto out;
7805 survey_idx++;
7806 }
7807
7808 out:
Johannes Berg97990a02013-04-19 01:02:55 +02007809 cb->args[2] = survey_idx;
Holger Schurig61fa7132009-11-11 12:25:40 +01007810 res = skb->len;
7811 out_err:
Johannes Berg56769e72017-03-15 14:26:04 +01007812 rtnl_unlock();
Holger Schurig61fa7132009-11-11 12:25:40 +01007813 return res;
7814}
7815
Samuel Ortizb23aa672009-07-01 21:26:54 +02007816static bool nl80211_valid_wpa_versions(u32 wpa_versions)
7817{
7818 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
7819 NL80211_WPA_VERSION_2));
7820}
7821
Jouni Malinen636a5d32009-03-19 13:39:22 +02007822static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
7823{
Johannes Berg4c476992010-10-04 21:36:35 +02007824 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7825 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02007826 struct ieee80211_channel *chan;
Jouni Malinen3255b4a2016-10-27 00:41:58 +03007827 const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
7828 int err, ssid_len, ie_len = 0, auth_data_len = 0;
Johannes Berg19957bb2009-07-02 17:20:43 +02007829 enum nl80211_auth_type auth_type;
Johannes Bergfffd0932009-07-08 14:22:54 +02007830 struct key_parse key;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03007831 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007832
Johannes Bergf4a11bb2009-03-27 12:40:28 +01007833 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
7834 return -EINVAL;
7835
7836 if (!info->attrs[NL80211_ATTR_MAC])
7837 return -EINVAL;
7838
Jouni Malinen17780922009-03-27 20:52:47 +02007839 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
7840 return -EINVAL;
7841
Johannes Berg19957bb2009-07-02 17:20:43 +02007842 if (!info->attrs[NL80211_ATTR_SSID])
7843 return -EINVAL;
7844
7845 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
7846 return -EINVAL;
7847
Johannes Bergfffd0932009-07-08 14:22:54 +02007848 err = nl80211_parse_key(info, &key);
7849 if (err)
7850 return err;
7851
7852 if (key.idx >= 0) {
Johannes Berge31b8212010-10-05 19:39:30 +02007853 if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
7854 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02007855 if (!key.p.key || !key.p.key_len)
7856 return -EINVAL;
7857 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
7858 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
7859 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
7860 key.p.key_len != WLAN_KEY_LEN_WEP104))
7861 return -EINVAL;
Johannes Bergb6b55552016-09-13 16:25:58 +02007862 if (key.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +02007863 return -EINVAL;
7864 } else {
7865 key.p.key_len = 0;
7866 key.p.key = NULL;
7867 }
7868
Johannes Bergafea0b72010-08-10 09:46:42 +02007869 if (key.idx >= 0) {
7870 int i;
7871 bool ok = false;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007872
Johannes Bergafea0b72010-08-10 09:46:42 +02007873 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
7874 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
7875 ok = true;
7876 break;
7877 }
7878 }
Johannes Berg4c476992010-10-04 21:36:35 +02007879 if (!ok)
7880 return -EINVAL;
Johannes Bergafea0b72010-08-10 09:46:42 +02007881 }
7882
Johannes Berg4c476992010-10-04 21:36:35 +02007883 if (!rdev->ops->auth)
7884 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007885
Johannes Berg074ac8d2010-09-16 14:58:22 +02007886 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02007887 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
7888 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02007889
Johannes Berg19957bb2009-07-02 17:20:43 +02007890 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen664834d2014-01-15 00:01:44 +02007891 chan = nl80211_get_valid_chan(&rdev->wiphy,
7892 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
7893 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02007894 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007895
Johannes Berg19957bb2009-07-02 17:20:43 +02007896 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
7897 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
7898
7899 if (info->attrs[NL80211_ATTR_IE]) {
7900 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
7901 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
7902 }
7903
7904 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03007905 if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
Johannes Berg4c476992010-10-04 21:36:35 +02007906 return -EINVAL;
Johannes Berg19957bb2009-07-02 17:20:43 +02007907
Jouni Malinene20f90f2016-10-27 00:42:02 +03007908 if ((auth_type == NL80211_AUTHTYPE_SAE ||
7909 auth_type == NL80211_AUTHTYPE_FILS_SK ||
7910 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
7911 auth_type == NL80211_AUTHTYPE_FILS_PK) &&
Jouni Malinen3255b4a2016-10-27 00:41:58 +03007912 !info->attrs[NL80211_ATTR_AUTH_DATA])
Jouni Malinene39e5b52012-09-30 19:29:39 +03007913 return -EINVAL;
7914
Jouni Malinen3255b4a2016-10-27 00:41:58 +03007915 if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
Jouni Malinene20f90f2016-10-27 00:42:02 +03007916 if (auth_type != NL80211_AUTHTYPE_SAE &&
7917 auth_type != NL80211_AUTHTYPE_FILS_SK &&
7918 auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
7919 auth_type != NL80211_AUTHTYPE_FILS_PK)
Jouni Malinene39e5b52012-09-30 19:29:39 +03007920 return -EINVAL;
Jouni Malinen3255b4a2016-10-27 00:41:58 +03007921 auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
7922 auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03007923 /* need to include at least Auth Transaction and Status Code */
Jouni Malinen3255b4a2016-10-27 00:41:58 +03007924 if (auth_data_len < 4)
Jouni Malinene39e5b52012-09-30 19:29:39 +03007925 return -EINVAL;
7926 }
7927
Jouni Malinend5cdfac2010-04-04 09:37:19 +03007928 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
7929
Johannes Berg95de8172012-01-20 13:55:25 +01007930 /*
7931 * Since we no longer track auth state, ignore
7932 * requests to only change local state.
7933 */
7934 if (local_state_change)
7935 return 0;
7936
Johannes Berg91bf9b22013-05-15 17:44:01 +02007937 wdev_lock(dev->ieee80211_ptr);
7938 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
7939 ssid, ssid_len, ie, ie_len,
7940 key.p.key, key.p.key_len, key.idx,
Jouni Malinen3255b4a2016-10-27 00:41:58 +03007941 auth_data, auth_data_len);
Johannes Berg91bf9b22013-05-15 17:44:01 +02007942 wdev_unlock(dev->ieee80211_ptr);
7943 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007944}
7945
Johannes Bergc0692b82010-08-27 14:26:53 +03007946static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
7947 struct genl_info *info,
Johannes Berg3dc27d22009-07-02 21:36:37 +02007948 struct cfg80211_crypto_settings *settings,
7949 int cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02007950{
Johannes Bergc0b2bbd2009-07-25 16:54:36 +02007951 memset(settings, 0, sizeof(*settings));
7952
Samuel Ortizb23aa672009-07-01 21:26:54 +02007953 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
7954
Johannes Bergc0692b82010-08-27 14:26:53 +03007955 if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
7956 u16 proto;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007957
Johannes Bergc0692b82010-08-27 14:26:53 +03007958 proto = nla_get_u16(
7959 info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
7960 settings->control_port_ethertype = cpu_to_be16(proto);
7961 if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
7962 proto != ETH_P_PAE)
7963 return -EINVAL;
7964 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
7965 settings->control_port_no_encrypt = true;
7966 } else
7967 settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
7968
Samuel Ortizb23aa672009-07-01 21:26:54 +02007969 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
7970 void *data;
7971 int len, i;
7972
7973 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
7974 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
7975 settings->n_ciphers_pairwise = len / sizeof(u32);
7976
7977 if (len % sizeof(u32))
7978 return -EINVAL;
7979
Johannes Berg3dc27d22009-07-02 21:36:37 +02007980 if (settings->n_ciphers_pairwise > cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02007981 return -EINVAL;
7982
7983 memcpy(settings->ciphers_pairwise, data, len);
7984
7985 for (i = 0; i < settings->n_ciphers_pairwise; i++)
Jouni Malinen38ba3c52011-09-21 18:14:56 +03007986 if (!cfg80211_supported_cipher_suite(
7987 &rdev->wiphy,
Samuel Ortizb23aa672009-07-01 21:26:54 +02007988 settings->ciphers_pairwise[i]))
7989 return -EINVAL;
7990 }
7991
7992 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
7993 settings->cipher_group =
7994 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
Jouni Malinen38ba3c52011-09-21 18:14:56 +03007995 if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
7996 settings->cipher_group))
Samuel Ortizb23aa672009-07-01 21:26:54 +02007997 return -EINVAL;
7998 }
7999
8000 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
8001 settings->wpa_versions =
8002 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
8003 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
8004 return -EINVAL;
8005 }
8006
8007 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
8008 void *data;
Jouni Malinen6d302402011-09-21 18:11:33 +03008009 int len;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008010
8011 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
8012 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
8013 settings->n_akm_suites = len / sizeof(u32);
8014
8015 if (len % sizeof(u32))
8016 return -EINVAL;
8017
Jouni Malinen1b9ca022011-09-21 16:13:07 +03008018 if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
8019 return -EINVAL;
8020
Samuel Ortizb23aa672009-07-01 21:26:54 +02008021 memcpy(settings->akm_suites, data, len);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008022 }
8023
8024 return 0;
8025}
8026
Jouni Malinen636a5d32009-03-19 13:39:22 +02008027static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
8028{
Johannes Berg4c476992010-10-04 21:36:35 +02008029 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8030 struct net_device *dev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02008031 struct ieee80211_channel *chan;
Johannes Bergf62fab72013-02-21 20:09:09 +01008032 struct cfg80211_assoc_request req = {};
8033 const u8 *bssid, *ssid;
8034 int err, ssid_len = 0;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008035
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008036 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8037 return -EINVAL;
8038
8039 if (!info->attrs[NL80211_ATTR_MAC] ||
Johannes Berg19957bb2009-07-02 17:20:43 +02008040 !info->attrs[NL80211_ATTR_SSID] ||
8041 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008042 return -EINVAL;
8043
Johannes Berg4c476992010-10-04 21:36:35 +02008044 if (!rdev->ops->assoc)
8045 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008046
Johannes Berg074ac8d2010-09-16 14:58:22 +02008047 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008048 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8049 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008050
Johannes Berg19957bb2009-07-02 17:20:43 +02008051 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008052
Jouni Malinen664834d2014-01-15 00:01:44 +02008053 chan = nl80211_get_valid_chan(&rdev->wiphy,
8054 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8055 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02008056 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008057
Johannes Berg19957bb2009-07-02 17:20:43 +02008058 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8059 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008060
8061 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008062 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8063 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008064 }
8065
Jouni Malinendc6382c2009-05-06 22:09:37 +03008066 if (info->attrs[NL80211_ATTR_USE_MFP]) {
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008067 enum nl80211_mfp mfp =
Jouni Malinendc6382c2009-05-06 22:09:37 +03008068 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008069 if (mfp == NL80211_MFP_REQUIRED)
Johannes Bergf62fab72013-02-21 20:09:09 +01008070 req.use_mfp = true;
Johannes Berg4c476992010-10-04 21:36:35 +02008071 else if (mfp != NL80211_MFP_NO)
8072 return -EINVAL;
Jouni Malinendc6382c2009-05-06 22:09:37 +03008073 }
8074
Johannes Berg3e5d7642009-07-07 14:37:26 +02008075 if (info->attrs[NL80211_ATTR_PREV_BSSID])
Johannes Bergf62fab72013-02-21 20:09:09 +01008076 req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
Johannes Berg3e5d7642009-07-07 14:37:26 +02008077
Ben Greear7e7c8922011-11-18 11:31:59 -08008078 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008079 req.flags |= ASSOC_REQ_DISABLE_HT;
Ben Greear7e7c8922011-11-18 11:31:59 -08008080
8081 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008082 memcpy(&req.ht_capa_mask,
8083 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8084 sizeof(req.ht_capa_mask));
Ben Greear7e7c8922011-11-18 11:31:59 -08008085
8086 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008087 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Ben Greear7e7c8922011-11-18 11:31:59 -08008088 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008089 memcpy(&req.ht_capa,
8090 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8091 sizeof(req.ht_capa));
Ben Greear7e7c8922011-11-18 11:31:59 -08008092 }
8093
Johannes Bergee2aca32013-02-21 17:36:01 +01008094 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008095 req.flags |= ASSOC_REQ_DISABLE_VHT;
Johannes Bergee2aca32013-02-21 17:36:01 +01008096
8097 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008098 memcpy(&req.vht_capa_mask,
8099 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8100 sizeof(req.vht_capa_mask));
Johannes Bergee2aca32013-02-21 17:36:01 +01008101
8102 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008103 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergee2aca32013-02-21 17:36:01 +01008104 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008105 memcpy(&req.vht_capa,
8106 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8107 sizeof(req.vht_capa));
Johannes Bergee2aca32013-02-21 17:36:01 +01008108 }
8109
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008110 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008111 if (!((rdev->wiphy.features &
8112 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8113 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8114 !wiphy_ext_feature_isset(&rdev->wiphy,
8115 NL80211_EXT_FEATURE_RRM))
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008116 return -EINVAL;
8117 req.flags |= ASSOC_REQ_USE_RRM;
8118 }
8119
Jouni Malinenc9a63622016-10-27 00:42:03 +03008120 if (info->attrs[NL80211_ATTR_FILS_KEK]) {
8121 req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
8122 req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
8123 if (!info->attrs[NL80211_ATTR_FILS_NONCES])
8124 return -EINVAL;
8125 req.fils_nonces =
8126 nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
8127 }
8128
Johannes Bergf62fab72013-02-21 20:09:09 +01008129 err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008130 if (!err) {
8131 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowski5f3f4d32018-02-04 21:57:28 +05308132
Johannes Bergf62fab72013-02-21 20:09:09 +01008133 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
8134 ssid, ssid_len, &req);
Andrzej Zaborowski5f3f4d32018-02-04 21:57:28 +05308135
8136 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8137 dev->ieee80211_ptr->conn_owner_nlportid =
8138 info->snd_portid;
8139 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8140 bssid, ETH_ALEN);
8141 }
8142
Johannes Berg91bf9b22013-05-15 17:44:01 +02008143 wdev_unlock(dev->ieee80211_ptr);
8144 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008145
Jouni Malinen636a5d32009-03-19 13:39:22 +02008146 return err;
8147}
8148
8149static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
8150{
Johannes Berg4c476992010-10-04 21:36:35 +02008151 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8152 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008153 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008154 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008155 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008156 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008157
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008158 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8159 return -EINVAL;
8160
8161 if (!info->attrs[NL80211_ATTR_MAC])
8162 return -EINVAL;
8163
8164 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8165 return -EINVAL;
8166
Johannes Berg4c476992010-10-04 21:36:35 +02008167 if (!rdev->ops->deauth)
8168 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008169
Johannes Berg074ac8d2010-09-16 14:58:22 +02008170 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008171 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8172 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008173
Johannes Berg19957bb2009-07-02 17:20:43 +02008174 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008175
Johannes Berg19957bb2009-07-02 17:20:43 +02008176 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8177 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008178 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008179 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008180 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008181
8182 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008183 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8184 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008185 }
8186
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008187 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8188
Johannes Berg91bf9b22013-05-15 17:44:01 +02008189 wdev_lock(dev->ieee80211_ptr);
8190 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
8191 local_state_change);
8192 wdev_unlock(dev->ieee80211_ptr);
8193 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008194}
8195
8196static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
8197{
Johannes Berg4c476992010-10-04 21:36:35 +02008198 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8199 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008200 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008201 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008202 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008203 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008204
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008205 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8206 return -EINVAL;
8207
8208 if (!info->attrs[NL80211_ATTR_MAC])
8209 return -EINVAL;
8210
8211 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8212 return -EINVAL;
8213
Johannes Berg4c476992010-10-04 21:36:35 +02008214 if (!rdev->ops->disassoc)
8215 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008216
Johannes Berg074ac8d2010-09-16 14:58:22 +02008217 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008218 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8219 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008220
Johannes Berg19957bb2009-07-02 17:20:43 +02008221 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008222
Johannes Berg19957bb2009-07-02 17:20:43 +02008223 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8224 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008225 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008226 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008227 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008228
8229 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008230 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8231 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008232 }
8233
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008234 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8235
Johannes Berg91bf9b22013-05-15 17:44:01 +02008236 wdev_lock(dev->ieee80211_ptr);
8237 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
8238 local_state_change);
8239 wdev_unlock(dev->ieee80211_ptr);
8240 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008241}
8242
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008243static bool
8244nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
Johannes Berg57fbcce2016-04-12 15:56:15 +02008245 int mcast_rate[NUM_NL80211_BANDS],
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008246 int rateval)
8247{
8248 struct wiphy *wiphy = &rdev->wiphy;
8249 bool found = false;
8250 int band, i;
8251
Johannes Berg57fbcce2016-04-12 15:56:15 +02008252 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008253 struct ieee80211_supported_band *sband;
8254
8255 sband = wiphy->bands[band];
8256 if (!sband)
8257 continue;
8258
8259 for (i = 0; i < sband->n_bitrates; i++) {
8260 if (sband->bitrates[i].bitrate == rateval) {
8261 mcast_rate[band] = i + 1;
8262 found = true;
8263 break;
8264 }
8265 }
8266 }
8267
8268 return found;
8269}
8270
Johannes Berg04a773a2009-04-19 21:24:32 +02008271static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
8272{
Johannes Berg4c476992010-10-04 21:36:35 +02008273 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8274 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008275 struct cfg80211_ibss_params ibss;
8276 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008277 struct cfg80211_cached_keys *connkeys = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +02008278 int err;
8279
Johannes Berg8e30bc52009-04-22 17:45:38 +02008280 memset(&ibss, 0, sizeof(ibss));
8281
Johannes Berg04a773a2009-04-19 21:24:32 +02008282 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8283 return -EINVAL;
8284
Johannes Berg683b6d32012-11-08 21:25:48 +01008285 if (!info->attrs[NL80211_ATTR_SSID] ||
Johannes Berg04a773a2009-04-19 21:24:32 +02008286 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8287 return -EINVAL;
8288
Johannes Berg8e30bc52009-04-22 17:45:38 +02008289 ibss.beacon_interval = 100;
8290
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308291 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
Johannes Berg8e30bc52009-04-22 17:45:38 +02008292 ibss.beacon_interval =
8293 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308294
Purushottam Kushwahac6800ff2016-10-12 18:26:51 +05308295 err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
8296 ibss.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308297 if (err)
8298 return err;
Johannes Berg8e30bc52009-04-22 17:45:38 +02008299
Johannes Berg4c476992010-10-04 21:36:35 +02008300 if (!rdev->ops->join_ibss)
8301 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008302
Johannes Berg4c476992010-10-04 21:36:35 +02008303 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8304 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008305
Johannes Berg79c97e92009-07-07 03:56:12 +02008306 wiphy = &rdev->wiphy;
Johannes Berg04a773a2009-04-19 21:24:32 +02008307
Johannes Berg39193492011-09-16 13:45:25 +02008308 if (info->attrs[NL80211_ATTR_MAC]) {
Johannes Berg04a773a2009-04-19 21:24:32 +02008309 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg39193492011-09-16 13:45:25 +02008310
8311 if (!is_valid_ether_addr(ibss.bssid))
8312 return -EINVAL;
8313 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008314 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8315 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8316
8317 if (info->attrs[NL80211_ATTR_IE]) {
8318 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8319 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8320 }
8321
Johannes Berg683b6d32012-11-08 21:25:48 +01008322 err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
8323 if (err)
8324 return err;
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008325
Ilan Peer174e0cd2014-02-23 09:13:01 +02008326 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
8327 NL80211_IFTYPE_ADHOC))
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008328 return -EINVAL;
8329
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008330 switch (ibss.chandef.width) {
Simon Wunderlichbf372642013-07-08 16:55:58 +02008331 case NL80211_CHAN_WIDTH_5:
8332 case NL80211_CHAN_WIDTH_10:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008333 case NL80211_CHAN_WIDTH_20_NOHT:
8334 break;
8335 case NL80211_CHAN_WIDTH_20:
8336 case NL80211_CHAN_WIDTH_40:
Janusz.Dziedzic@tieto.comffc11992015-02-21 16:52:39 +01008337 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8338 return -EINVAL;
8339 break;
8340 case NL80211_CHAN_WIDTH_80:
8341 case NL80211_CHAN_WIDTH_80P80:
8342 case NL80211_CHAN_WIDTH_160:
8343 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8344 return -EINVAL;
8345 if (!wiphy_ext_feature_isset(&rdev->wiphy,
8346 NL80211_EXT_FEATURE_VHT_IBSS))
8347 return -EINVAL;
8348 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008349 default:
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008350 return -EINVAL;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008351 }
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008352
Johannes Berg04a773a2009-04-19 21:24:32 +02008353 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
Johannes Bergfffd0932009-07-08 14:22:54 +02008354 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg04a773a2009-04-19 21:24:32 +02008355
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008356 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
8357 u8 *rates =
8358 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8359 int n_rates =
8360 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8361 struct ieee80211_supported_band *sband =
Johannes Berg683b6d32012-11-08 21:25:48 +01008362 wiphy->bands[ibss.chandef.chan->band];
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008363
Johannes Berg34850ab2011-07-18 18:08:35 +02008364 err = ieee80211_get_ratemask(sband, rates, n_rates,
8365 &ibss.basic_rates);
8366 if (err)
8367 return err;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008368 }
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008369
Simon Wunderlich803768f2013-06-28 10:39:58 +02008370 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8371 memcpy(&ibss.ht_capa_mask,
8372 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8373 sizeof(ibss.ht_capa_mask));
8374
8375 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
8376 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8377 return -EINVAL;
8378 memcpy(&ibss.ht_capa,
8379 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8380 sizeof(ibss.ht_capa));
8381 }
8382
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008383 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
8384 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
8385 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
8386 return -EINVAL;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008387
Johannes Berg4c476992010-10-04 21:36:35 +02008388 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Sujith Manoharande7044e2012-10-18 10:19:28 +05308389 bool no_ht = false;
8390
Johannes Berg4c476992010-10-04 21:36:35 +02008391 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308392 info->attrs[NL80211_ATTR_KEYS],
8393 &no_ht);
Johannes Berg4c476992010-10-04 21:36:35 +02008394 if (IS_ERR(connkeys))
8395 return PTR_ERR(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308396
Johannes Berg3d9d1d62012-11-08 23:14:50 +01008397 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
8398 no_ht) {
Ola Olsson5e950a72016-02-11 01:00:22 +01008399 kzfree(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308400 return -EINVAL;
8401 }
Johannes Berg4c476992010-10-04 21:36:35 +02008402 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008403
Antonio Quartulli267335d2012-01-31 20:25:47 +01008404 ibss.control_port =
8405 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
8406
Simon Wunderlich5336fa82013-10-07 18:41:05 +02008407 ibss.userspace_handles_dfs =
8408 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
8409
Johannes Berg4c476992010-10-04 21:36:35 +02008410 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008411 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008412 kzfree(connkeys);
Johannes Berg04a773a2009-04-19 21:24:32 +02008413 return err;
8414}
8415
8416static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
8417{
Johannes Berg4c476992010-10-04 21:36:35 +02008418 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8419 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008420
Johannes Berg4c476992010-10-04 21:36:35 +02008421 if (!rdev->ops->leave_ibss)
8422 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008423
Johannes Berg4c476992010-10-04 21:36:35 +02008424 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8425 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008426
Johannes Berg4c476992010-10-04 21:36:35 +02008427 return cfg80211_leave_ibss(rdev, dev, false);
Johannes Berg04a773a2009-04-19 21:24:32 +02008428}
8429
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008430static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
8431{
8432 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8433 struct net_device *dev = info->user_ptr[1];
Johannes Berg57fbcce2016-04-12 15:56:15 +02008434 int mcast_rate[NUM_NL80211_BANDS];
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008435 u32 nla_rate;
8436 int err;
8437
8438 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
Bertold Van den Bergh876dc932015-08-05 16:02:21 +02008439 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
8440 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008441 return -EOPNOTSUPP;
8442
8443 if (!rdev->ops->set_mcast_rate)
8444 return -EOPNOTSUPP;
8445
8446 memset(mcast_rate, 0, sizeof(mcast_rate));
8447
8448 if (!info->attrs[NL80211_ATTR_MCAST_RATE])
8449 return -EINVAL;
8450
8451 nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
8452 if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
8453 return -EINVAL;
8454
Ilan Peera1056b12015-10-22 22:27:46 +03008455 err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008456
8457 return err;
8458}
8459
Johannes Bergad7e7182013-11-13 13:37:47 +01008460static struct sk_buff *
8461__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008462 struct wireless_dev *wdev, int approxlen,
8463 u32 portid, u32 seq, enum nl80211_commands cmd,
Johannes Berg567ffc32013-12-18 14:43:31 +01008464 enum nl80211_attrs attr,
8465 const struct nl80211_vendor_cmd_info *info,
8466 gfp_t gfp)
Johannes Bergad7e7182013-11-13 13:37:47 +01008467{
8468 struct sk_buff *skb;
8469 void *hdr;
8470 struct nlattr *data;
8471
8472 skb = nlmsg_new(approxlen + 100, gfp);
8473 if (!skb)
8474 return NULL;
8475
8476 hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
8477 if (!hdr) {
8478 kfree_skb(skb);
8479 return NULL;
8480 }
8481
8482 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
8483 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01008484
8485 if (info) {
8486 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
8487 info->vendor_id))
8488 goto nla_put_failure;
8489 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
8490 info->subcmd))
8491 goto nla_put_failure;
8492 }
8493
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008494 if (wdev) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008495 if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
8496 wdev_id(wdev), NL80211_ATTR_PAD))
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008497 goto nla_put_failure;
8498 if (wdev->netdev &&
8499 nla_put_u32(skb, NL80211_ATTR_IFINDEX,
8500 wdev->netdev->ifindex))
8501 goto nla_put_failure;
8502 }
8503
Johannes Bergad7e7182013-11-13 13:37:47 +01008504 data = nla_nest_start(skb, attr);
Johannes Berg76e1fb42016-09-14 09:55:57 +02008505 if (!data)
8506 goto nla_put_failure;
Johannes Bergad7e7182013-11-13 13:37:47 +01008507
8508 ((void **)skb->cb)[0] = rdev;
8509 ((void **)skb->cb)[1] = hdr;
8510 ((void **)skb->cb)[2] = data;
8511
8512 return skb;
8513
8514 nla_put_failure:
8515 kfree_skb(skb);
8516 return NULL;
8517}
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008518
Johannes Berge03ad6e2014-01-01 17:22:30 +01008519struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008520 struct wireless_dev *wdev,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008521 enum nl80211_commands cmd,
8522 enum nl80211_attrs attr,
8523 int vendor_event_idx,
8524 int approxlen, gfp_t gfp)
8525{
Zhao, Gangf26cbf42014-04-21 12:53:03 +08008526 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berge03ad6e2014-01-01 17:22:30 +01008527 const struct nl80211_vendor_cmd_info *info;
8528
8529 switch (cmd) {
8530 case NL80211_CMD_TESTMODE:
8531 if (WARN_ON(vendor_event_idx != -1))
8532 return NULL;
8533 info = NULL;
8534 break;
8535 case NL80211_CMD_VENDOR:
8536 if (WARN_ON(vendor_event_idx < 0 ||
8537 vendor_event_idx >= wiphy->n_vendor_events))
8538 return NULL;
8539 info = &wiphy->vendor_events[vendor_event_idx];
8540 break;
8541 default:
8542 WARN_ON(1);
8543 return NULL;
8544 }
8545
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008546 return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008547 cmd, attr, info, gfp);
8548}
8549EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
8550
8551void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
8552{
8553 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
8554 void *hdr = ((void **)skb->cb)[1];
8555 struct nlattr *data = ((void **)skb->cb)[2];
8556 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
8557
Johannes Bergbd8c78e2014-07-30 14:55:26 +02008558 /* clear CB data for netlink core to own from now on */
8559 memset(skb->cb, 0, sizeof(skb->cb));
8560
Johannes Berge03ad6e2014-01-01 17:22:30 +01008561 nla_nest_end(skb, data);
8562 genlmsg_end(skb, hdr);
8563
8564 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
8565 mcgrp = NL80211_MCGRP_VENDOR;
8566
8567 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
8568 mcgrp, gfp);
8569}
8570EXPORT_SYMBOL(__cfg80211_send_event_skb);
8571
Johannes Bergaff89a92009-07-01 21:26:51 +02008572#ifdef CONFIG_NL80211_TESTMODE
Johannes Bergaff89a92009-07-01 21:26:51 +02008573static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
8574{
Johannes Berg4c476992010-10-04 21:36:35 +02008575 struct cfg80211_registered_device *rdev = info->user_ptr[0];
David Spinadelfc73f112013-07-31 18:04:15 +03008576 struct wireless_dev *wdev =
8577 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
Johannes Bergaff89a92009-07-01 21:26:51 +02008578 int err;
8579
David Spinadelfc73f112013-07-31 18:04:15 +03008580 if (!rdev->ops->testmode_cmd)
8581 return -EOPNOTSUPP;
8582
8583 if (IS_ERR(wdev)) {
8584 err = PTR_ERR(wdev);
8585 if (err != -EINVAL)
8586 return err;
8587 wdev = NULL;
8588 } else if (wdev->wiphy != &rdev->wiphy) {
8589 return -EINVAL;
8590 }
8591
Johannes Bergaff89a92009-07-01 21:26:51 +02008592 if (!info->attrs[NL80211_ATTR_TESTDATA])
8593 return -EINVAL;
8594
Johannes Bergad7e7182013-11-13 13:37:47 +01008595 rdev->cur_cmd_info = info;
David Spinadelfc73f112013-07-31 18:04:15 +03008596 err = rdev_testmode_cmd(rdev, wdev,
Johannes Bergaff89a92009-07-01 21:26:51 +02008597 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
8598 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
Johannes Bergad7e7182013-11-13 13:37:47 +01008599 rdev->cur_cmd_info = NULL;
Johannes Bergaff89a92009-07-01 21:26:51 +02008600
Johannes Bergaff89a92009-07-01 21:26:51 +02008601 return err;
8602}
8603
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008604static int nl80211_testmode_dump(struct sk_buff *skb,
8605 struct netlink_callback *cb)
8606{
Johannes Berg00918d32011-12-13 17:22:05 +01008607 struct cfg80211_registered_device *rdev;
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008608 int err;
8609 long phy_idx;
8610 void *data = NULL;
8611 int data_len = 0;
8612
Johannes Berg5fe231e2013-05-08 21:45:15 +02008613 rtnl_lock();
8614
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008615 if (cb->args[0]) {
8616 /*
8617 * 0 is a valid index, but not valid for args[0],
8618 * so we need to offset by 1.
8619 */
8620 phy_idx = cb->args[0] - 1;
8621 } else {
8622 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
8623 nl80211_fam.attrbuf, nl80211_fam.maxattr,
8624 nl80211_policy);
8625 if (err)
Johannes Berg5fe231e2013-05-08 21:45:15 +02008626 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008627
Johannes Berg2bd7e352012-06-15 14:23:16 +02008628 rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
8629 nl80211_fam.attrbuf);
8630 if (IS_ERR(rdev)) {
Johannes Berg5fe231e2013-05-08 21:45:15 +02008631 err = PTR_ERR(rdev);
8632 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008633 }
Johannes Berg2bd7e352012-06-15 14:23:16 +02008634 phy_idx = rdev->wiphy_idx;
8635 rdev = NULL;
Johannes Berg2bd7e352012-06-15 14:23:16 +02008636
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008637 if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
8638 cb->args[1] =
8639 (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
8640 }
8641
8642 if (cb->args[1]) {
8643 data = nla_data((void *)cb->args[1]);
8644 data_len = nla_len((void *)cb->args[1]);
8645 }
8646
Johannes Berg00918d32011-12-13 17:22:05 +01008647 rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
8648 if (!rdev) {
Johannes Berg5fe231e2013-05-08 21:45:15 +02008649 err = -ENOENT;
8650 goto out_err;
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008651 }
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008652
Johannes Berg00918d32011-12-13 17:22:05 +01008653 if (!rdev->ops->testmode_dump) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008654 err = -EOPNOTSUPP;
8655 goto out_err;
8656 }
8657
8658 while (1) {
Eric W. Biederman15e47302012-09-07 20:12:54 +00008659 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008660 cb->nlh->nlmsg_seq, NLM_F_MULTI,
8661 NL80211_CMD_TESTMODE);
8662 struct nlattr *tmdata;
8663
Dan Carpentercb35fba2013-08-14 14:50:01 +03008664 if (!hdr)
8665 break;
8666
David S. Miller9360ffd2012-03-29 04:41:26 -04008667 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008668 genlmsg_cancel(skb, hdr);
8669 break;
8670 }
8671
8672 tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
8673 if (!tmdata) {
8674 genlmsg_cancel(skb, hdr);
8675 break;
8676 }
Hila Gonene35e4d22012-06-27 17:19:42 +03008677 err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008678 nla_nest_end(skb, tmdata);
8679
8680 if (err == -ENOBUFS || err == -ENOENT) {
8681 genlmsg_cancel(skb, hdr);
8682 break;
8683 } else if (err) {
8684 genlmsg_cancel(skb, hdr);
8685 goto out_err;
8686 }
8687
8688 genlmsg_end(skb, hdr);
8689 }
8690
8691 err = skb->len;
8692 /* see above */
8693 cb->args[0] = phy_idx + 1;
8694 out_err:
Johannes Berg5fe231e2013-05-08 21:45:15 +02008695 rtnl_unlock();
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008696 return err;
8697}
Johannes Bergaff89a92009-07-01 21:26:51 +02008698#endif
8699
Samuel Ortizb23aa672009-07-01 21:26:54 +02008700static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
8701{
Johannes Berg4c476992010-10-04 21:36:35 +02008702 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8703 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02008704 struct cfg80211_connect_params connect;
8705 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008706 struct cfg80211_cached_keys *connkeys = NULL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008707 int err;
8708
8709 memset(&connect, 0, sizeof(connect));
8710
8711 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8712 return -EINVAL;
8713
8714 if (!info->attrs[NL80211_ATTR_SSID] ||
8715 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8716 return -EINVAL;
8717
8718 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
8719 connect.auth_type =
8720 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008721 if (!nl80211_valid_auth_type(rdev, connect.auth_type,
8722 NL80211_CMD_CONNECT))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008723 return -EINVAL;
8724 } else
8725 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
8726
8727 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
8728
Johannes Bergc0692b82010-08-27 14:26:53 +03008729 err = nl80211_crypto_settings(rdev, info, &connect.crypto,
Johannes Berg3dc27d22009-07-02 21:36:37 +02008730 NL80211_MAX_NR_CIPHER_SUITES);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008731 if (err)
8732 return err;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008733
Johannes Berg074ac8d2010-09-16 14:58:22 +02008734 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008735 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8736 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008737
Johannes Berg79c97e92009-07-07 03:56:12 +02008738 wiphy = &rdev->wiphy;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008739
Bala Shanmugam4486ea92012-03-07 17:27:12 +05308740 connect.bg_scan_period = -1;
8741 if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
8742 (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
8743 connect.bg_scan_period =
8744 nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
8745 }
8746
Samuel Ortizb23aa672009-07-01 21:26:54 +02008747 if (info->attrs[NL80211_ATTR_MAC])
8748 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen1df4a512014-01-15 00:00:47 +02008749 else if (info->attrs[NL80211_ATTR_MAC_HINT])
8750 connect.bssid_hint =
8751 nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008752 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8753 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8754
8755 if (info->attrs[NL80211_ATTR_IE]) {
8756 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8757 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8758 }
8759
Jouni Malinencee00a92013-01-15 17:15:57 +02008760 if (info->attrs[NL80211_ATTR_USE_MFP]) {
8761 connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
8762 if (connect.mfp != NL80211_MFP_REQUIRED &&
8763 connect.mfp != NL80211_MFP_NO)
8764 return -EINVAL;
8765 } else {
8766 connect.mfp = NL80211_MFP_NO;
8767 }
8768
Jouni Malinenba6fbac2016-03-29 13:53:27 +03008769 if (info->attrs[NL80211_ATTR_PREV_BSSID])
8770 connect.prev_bssid =
8771 nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
8772
Samuel Ortizb23aa672009-07-01 21:26:54 +02008773 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02008774 connect.channel = nl80211_get_valid_chan(
8775 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8776 if (!connect.channel)
Johannes Berg4c476992010-10-04 21:36:35 +02008777 return -EINVAL;
Jouni Malinen1df4a512014-01-15 00:00:47 +02008778 } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02008779 connect.channel_hint = nl80211_get_valid_chan(
8780 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
8781 if (!connect.channel_hint)
Jouni Malinen1df4a512014-01-15 00:00:47 +02008782 return -EINVAL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008783 }
8784
Johannes Bergfffd0932009-07-08 14:22:54 +02008785 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
8786 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308787 info->attrs[NL80211_ATTR_KEYS], NULL);
Johannes Berg4c476992010-10-04 21:36:35 +02008788 if (IS_ERR(connkeys))
8789 return PTR_ERR(connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008790 }
8791
Ben Greear7e7c8922011-11-18 11:31:59 -08008792 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
8793 connect.flags |= ASSOC_REQ_DISABLE_HT;
8794
8795 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8796 memcpy(&connect.ht_capa_mask,
8797 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8798 sizeof(connect.ht_capa_mask));
8799
8800 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Wei Yongjunb4e4f472012-09-02 21:41:04 +08008801 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03008802 kzfree(connkeys);
Ben Greear7e7c8922011-11-18 11:31:59 -08008803 return -EINVAL;
Wei Yongjunb4e4f472012-09-02 21:41:04 +08008804 }
Ben Greear7e7c8922011-11-18 11:31:59 -08008805 memcpy(&connect.ht_capa,
8806 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8807 sizeof(connect.ht_capa));
8808 }
8809
Johannes Bergee2aca32013-02-21 17:36:01 +01008810 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
8811 connect.flags |= ASSOC_REQ_DISABLE_VHT;
8812
8813 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
8814 memcpy(&connect.vht_capa_mask,
8815 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8816 sizeof(connect.vht_capa_mask));
8817
8818 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
8819 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03008820 kzfree(connkeys);
Johannes Bergee2aca32013-02-21 17:36:01 +01008821 return -EINVAL;
8822 }
8823 memcpy(&connect.vht_capa,
8824 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8825 sizeof(connect.vht_capa));
8826 }
8827
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008828 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008829 if (!((rdev->wiphy.features &
8830 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8831 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8832 !wiphy_ext_feature_isset(&rdev->wiphy,
8833 NL80211_EXT_FEATURE_RRM)) {
Ola Olsson707554b2015-12-11 21:04:52 +01008834 kzfree(connkeys);
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008835 return -EINVAL;
Ola Olsson707554b2015-12-11 21:04:52 +01008836 }
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008837 connect.flags |= ASSOC_REQ_USE_RRM;
8838 }
8839
Lior David34d50512016-01-28 10:58:25 +02008840 connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
Johannes Berg57fbcce2016-04-12 15:56:15 +02008841 if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
Lior David34d50512016-01-28 10:58:25 +02008842 kzfree(connkeys);
8843 return -EOPNOTSUPP;
8844 }
8845
Arend van Spriel38de03d2016-03-02 20:37:18 +01008846 if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
8847 /* bss selection makes no sense if bssid is set */
8848 if (connect.bssid) {
8849 kzfree(connkeys);
8850 return -EINVAL;
8851 }
8852
8853 err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
8854 wiphy, &connect.bss_select);
8855 if (err) {
8856 kzfree(connkeys);
8857 return err;
8858 }
8859 }
8860
Vidyullatha Kanchanapally36eabf62017-03-31 00:22:34 +03008861 if (wiphy_ext_feature_isset(&rdev->wiphy,
8862 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
8863 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
8864 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
8865 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
8866 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
8867 connect.fils_erp_username =
8868 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
8869 connect.fils_erp_username_len =
8870 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
8871 connect.fils_erp_realm =
8872 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
8873 connect.fils_erp_realm_len =
8874 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
8875 connect.fils_erp_next_seq_num =
8876 nla_get_u16(
8877 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
8878 connect.fils_erp_rrk =
8879 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
8880 connect.fils_erp_rrk_len =
8881 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
8882 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
8883 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
8884 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
8885 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
8886 kzfree(connkeys);
8887 return -EINVAL;
8888 }
8889
Johannes Berg83739b02013-05-15 17:44:01 +02008890 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowski5f3f4d32018-02-04 21:57:28 +05308891
Jouni Malinen4ce2bd92016-03-29 13:53:28 +03008892 err = cfg80211_connect(rdev, dev, &connect, connkeys,
8893 connect.prev_bssid);
Johannes Bergfffd0932009-07-08 14:22:54 +02008894 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008895 kzfree(connkeys);
Andrzej Zaborowski5f3f4d32018-02-04 21:57:28 +05308896
8897 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8898 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
8899 if (connect.bssid)
8900 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8901 connect.bssid, ETH_ALEN);
8902 else
8903 memset(dev->ieee80211_ptr->disconnect_bssid,
8904 0, ETH_ALEN);
8905 }
8906
8907 wdev_unlock(dev->ieee80211_ptr);
8908
Samuel Ortizb23aa672009-07-01 21:26:54 +02008909 return err;
8910}
8911
vamsi krishna30da4e82016-10-27 16:51:11 +03008912static int nl80211_update_connect_params(struct sk_buff *skb,
8913 struct genl_info *info)
8914{
8915 struct cfg80211_connect_params connect = {};
8916 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8917 struct net_device *dev = info->user_ptr[1];
8918 struct wireless_dev *wdev = dev->ieee80211_ptr;
8919 u32 changed = 0;
8920 int ret;
8921
8922 if (!rdev->ops->update_connect_params)
8923 return -EOPNOTSUPP;
8924
8925 if (info->attrs[NL80211_ATTR_IE]) {
8926 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8927 return -EINVAL;
8928 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8929 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8930 changed |= UPDATE_ASSOC_IES;
8931 }
8932
Vidyullatha Kanchanapally5f5a26b2017-08-02 16:31:40 +05308933 if (wiphy_ext_feature_isset(&rdev->wiphy,
8934 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
8935 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
8936 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
8937 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
8938 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
8939 connect.fils_erp_username =
8940 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
8941 connect.fils_erp_username_len =
8942 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
8943 connect.fils_erp_realm =
8944 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
8945 connect.fils_erp_realm_len =
8946 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
8947 connect.fils_erp_next_seq_num =
8948 nla_get_u16(
8949 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
8950 connect.fils_erp_rrk =
8951 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
8952 connect.fils_erp_rrk_len =
8953 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
8954 changed |= UPDATE_FILS_ERP_INFO;
8955 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
8956 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
8957 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
8958 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
8959 return -EINVAL;
8960 }
8961
8962 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
8963 u32 auth_type =
8964 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
8965 if (!nl80211_valid_auth_type(rdev, auth_type,
8966 NL80211_CMD_CONNECT))
8967 return -EINVAL;
8968 connect.auth_type = auth_type;
8969 changed |= UPDATE_AUTH_TYPE;
8970 }
8971
vamsi krishna30da4e82016-10-27 16:51:11 +03008972 wdev_lock(dev->ieee80211_ptr);
8973 if (!wdev->current_bss)
8974 ret = -ENOLINK;
8975 else
8976 ret = rdev_update_connect_params(rdev, dev, &connect, changed);
8977 wdev_unlock(dev->ieee80211_ptr);
8978
8979 return ret;
8980}
8981
Samuel Ortizb23aa672009-07-01 21:26:54 +02008982static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
8983{
Johannes Berg4c476992010-10-04 21:36:35 +02008984 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8985 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02008986 u16 reason;
Johannes Berg83739b02013-05-15 17:44:01 +02008987 int ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008988
8989 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8990 reason = WLAN_REASON_DEAUTH_LEAVING;
8991 else
8992 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8993
8994 if (reason == 0)
8995 return -EINVAL;
8996
Johannes Berg074ac8d2010-09-16 14:58:22 +02008997 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008998 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8999 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009000
Johannes Berg83739b02013-05-15 17:44:01 +02009001 wdev_lock(dev->ieee80211_ptr);
9002 ret = cfg80211_disconnect(rdev, dev, reason, true);
9003 wdev_unlock(dev->ieee80211_ptr);
9004 return ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009005}
9006
Johannes Berg463d0182009-07-14 00:33:35 +02009007static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
9008{
Johannes Berg4c476992010-10-04 21:36:35 +02009009 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg463d0182009-07-14 00:33:35 +02009010 struct net *net;
9011 int err;
Johannes Berg463d0182009-07-14 00:33:35 +02009012
Vadim Kochan4b681c82015-01-12 16:34:05 +02009013 if (info->attrs[NL80211_ATTR_PID]) {
9014 u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
9015
9016 net = get_net_ns_by_pid(pid);
9017 } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
9018 u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
9019
9020 net = get_net_ns_by_fd(fd);
9021 } else {
Johannes Berg463d0182009-07-14 00:33:35 +02009022 return -EINVAL;
Vadim Kochan4b681c82015-01-12 16:34:05 +02009023 }
Johannes Berg463d0182009-07-14 00:33:35 +02009024
Johannes Berg4c476992010-10-04 21:36:35 +02009025 if (IS_ERR(net))
9026 return PTR_ERR(net);
Johannes Berg463d0182009-07-14 00:33:35 +02009027
9028 err = 0;
9029
9030 /* check if anything to do */
Johannes Berg4c476992010-10-04 21:36:35 +02009031 if (!net_eq(wiphy_net(&rdev->wiphy), net))
9032 err = cfg80211_switch_netns(rdev, net);
Johannes Berg463d0182009-07-14 00:33:35 +02009033
Johannes Berg463d0182009-07-14 00:33:35 +02009034 put_net(net);
Johannes Berg463d0182009-07-14 00:33:35 +02009035 return err;
9036}
9037
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009038static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
9039{
Johannes Berg4c476992010-10-04 21:36:35 +02009040 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009041 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
9042 struct cfg80211_pmksa *pmksa) = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02009043 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009044 struct cfg80211_pmksa pmksa;
9045
9046 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
9047
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009048 if (!info->attrs[NL80211_ATTR_PMKID])
9049 return -EINVAL;
9050
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009051 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
Vidyullatha Kanchanapally36eabf62017-03-31 00:22:34 +03009052
9053 if (info->attrs[NL80211_ATTR_MAC]) {
9054 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9055 } else if (info->attrs[NL80211_ATTR_SSID] &&
9056 info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
9057 (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
9058 info->attrs[NL80211_ATTR_PMK])) {
9059 pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9060 pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9061 pmksa.cache_id =
9062 nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
9063 } else {
9064 return -EINVAL;
9065 }
9066 if (info->attrs[NL80211_ATTR_PMK]) {
9067 pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
9068 pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
9069 }
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009070
Johannes Berg074ac8d2010-09-16 14:58:22 +02009071 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009072 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9073 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009074
9075 switch (info->genlhdr->cmd) {
9076 case NL80211_CMD_SET_PMKSA:
9077 rdev_ops = rdev->ops->set_pmksa;
9078 break;
9079 case NL80211_CMD_DEL_PMKSA:
9080 rdev_ops = rdev->ops->del_pmksa;
9081 break;
9082 default:
9083 WARN_ON(1);
9084 break;
9085 }
9086
Johannes Berg4c476992010-10-04 21:36:35 +02009087 if (!rdev_ops)
9088 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009089
Johannes Berg4c476992010-10-04 21:36:35 +02009090 return rdev_ops(&rdev->wiphy, dev, &pmksa);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009091}
9092
9093static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
9094{
Johannes Berg4c476992010-10-04 21:36:35 +02009095 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9096 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009097
Johannes Berg074ac8d2010-09-16 14:58:22 +02009098 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009099 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9100 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009101
Johannes Berg4c476992010-10-04 21:36:35 +02009102 if (!rdev->ops->flush_pmksa)
9103 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009104
Hila Gonene35e4d22012-06-27 17:19:42 +03009105 return rdev_flush_pmksa(rdev, dev);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009106}
9107
Arik Nemtsov109086c2011-09-28 14:12:50 +03009108static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
9109{
9110 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9111 struct net_device *dev = info->user_ptr[1];
9112 u8 action_code, dialog_token;
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309113 u32 peer_capability = 0;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009114 u16 status_code;
9115 u8 *peer;
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009116 bool initiator;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009117
9118 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9119 !rdev->ops->tdls_mgmt)
9120 return -EOPNOTSUPP;
9121
9122 if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
9123 !info->attrs[NL80211_ATTR_STATUS_CODE] ||
9124 !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
9125 !info->attrs[NL80211_ATTR_IE] ||
9126 !info->attrs[NL80211_ATTR_MAC])
9127 return -EINVAL;
9128
9129 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9130 action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
9131 status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
9132 dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009133 initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309134 if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
9135 peer_capability =
9136 nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009137
Hila Gonene35e4d22012-06-27 17:19:42 +03009138 return rdev_tdls_mgmt(rdev, dev, peer, action_code,
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309139 dialog_token, status_code, peer_capability,
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009140 initiator,
Hila Gonene35e4d22012-06-27 17:19:42 +03009141 nla_data(info->attrs[NL80211_ATTR_IE]),
9142 nla_len(info->attrs[NL80211_ATTR_IE]));
Arik Nemtsov109086c2011-09-28 14:12:50 +03009143}
9144
9145static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
9146{
9147 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9148 struct net_device *dev = info->user_ptr[1];
9149 enum nl80211_tdls_operation operation;
9150 u8 *peer;
9151
9152 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9153 !rdev->ops->tdls_oper)
9154 return -EOPNOTSUPP;
9155
9156 if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
9157 !info->attrs[NL80211_ATTR_MAC])
9158 return -EINVAL;
9159
9160 operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
9161 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9162
Hila Gonene35e4d22012-06-27 17:19:42 +03009163 return rdev_tdls_oper(rdev, dev, peer, operation);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009164}
9165
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009166static int nl80211_remain_on_channel(struct sk_buff *skb,
9167 struct genl_info *info)
9168{
Johannes Berg4c476992010-10-04 21:36:35 +02009169 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009170 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009171 struct cfg80211_chan_def chandef;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009172 struct sk_buff *msg;
9173 void *hdr;
9174 u64 cookie;
Johannes Berg683b6d32012-11-08 21:25:48 +01009175 u32 duration;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009176 int err;
9177
9178 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
9179 !info->attrs[NL80211_ATTR_DURATION])
9180 return -EINVAL;
9181
9182 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
9183
Johannes Berg7c4ef712011-11-18 15:33:48 +01009184 if (!rdev->ops->remain_on_channel ||
9185 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
Johannes Berg4c476992010-10-04 21:36:35 +02009186 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009187
Johannes Bergebf348f2012-06-01 12:50:54 +02009188 /*
9189 * We should be on that channel for at least a minimum amount of
9190 * time (10ms) but no longer than the driver supports.
9191 */
9192 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9193 duration > rdev->wiphy.max_remain_on_channel_duration)
9194 return -EINVAL;
9195
Johannes Berg683b6d32012-11-08 21:25:48 +01009196 err = nl80211_parse_chandef(rdev, info, &chandef);
9197 if (err)
9198 return err;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009199
9200 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009201 if (!msg)
9202 return -ENOMEM;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009203
Eric W. Biederman15e47302012-09-07 20:12:54 +00009204 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009205 NL80211_CMD_REMAIN_ON_CHANNEL);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009206 if (!hdr) {
9207 err = -ENOBUFS;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009208 goto free_msg;
9209 }
9210
Johannes Berg683b6d32012-11-08 21:25:48 +01009211 err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
9212 duration, &cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009213
9214 if (err)
9215 goto free_msg;
9216
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009217 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9218 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009219 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009220
9221 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009222
9223 return genlmsg_reply(msg, info);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009224
9225 nla_put_failure:
9226 err = -ENOBUFS;
9227 free_msg:
9228 nlmsg_free(msg);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009229 return err;
9230}
9231
9232static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
9233 struct genl_info *info)
9234{
Johannes Berg4c476992010-10-04 21:36:35 +02009235 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009236 struct wireless_dev *wdev = info->user_ptr[1];
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009237 u64 cookie;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009238
9239 if (!info->attrs[NL80211_ATTR_COOKIE])
9240 return -EINVAL;
9241
Johannes Berg4c476992010-10-04 21:36:35 +02009242 if (!rdev->ops->cancel_remain_on_channel)
9243 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009244
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009245 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9246
Hila Gonene35e4d22012-06-27 17:19:42 +03009247 return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009248}
9249
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009250static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
9251 struct genl_info *info)
9252{
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009253 struct cfg80211_bitrate_mask mask;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309254 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009255 struct net_device *dev = info->user_ptr[1];
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309256 int err;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009257
Johannes Berg4c476992010-10-04 21:36:35 +02009258 if (!rdev->ops->set_bitrate_mask)
9259 return -EOPNOTSUPP;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009260
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309261 err = nl80211_parse_tx_bitrate_mask(info, &mask);
9262 if (err)
9263 return err;
Janusz Dziedzic78693032013-12-03 09:50:44 +01009264
Hila Gonene35e4d22012-06-27 17:19:42 +03009265 return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009266}
9267
Johannes Berg2e161f72010-08-12 15:38:38 +02009268static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009269{
Johannes Berg4c476992010-10-04 21:36:35 +02009270 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009271 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2e161f72010-08-12 15:38:38 +02009272 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
Jouni Malinen026331c2010-02-15 12:53:10 +02009273
9274 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
9275 return -EINVAL;
9276
Johannes Berg2e161f72010-08-12 15:38:38 +02009277 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
9278 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
Jouni Malinen026331c2010-02-15 12:53:10 +02009279
Johannes Berg71bbc992012-06-15 15:30:18 +02009280 switch (wdev->iftype) {
9281 case NL80211_IFTYPE_STATION:
9282 case NL80211_IFTYPE_ADHOC:
9283 case NL80211_IFTYPE_P2P_CLIENT:
9284 case NL80211_IFTYPE_AP:
9285 case NL80211_IFTYPE_AP_VLAN:
9286 case NL80211_IFTYPE_MESH_POINT:
9287 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009288 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009289 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009290 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009291 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009292 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009293 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009294
9295 /* not much point in registering if we can't reply */
Johannes Berg4c476992010-10-04 21:36:35 +02009296 if (!rdev->ops->mgmt_tx)
9297 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009298
Eric W. Biederman15e47302012-09-07 20:12:54 +00009299 return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
Jouni Malinen026331c2010-02-15 12:53:10 +02009300 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
9301 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
Jouni Malinen026331c2010-02-15 12:53:10 +02009302}
9303
Johannes Berg2e161f72010-08-12 15:38:38 +02009304static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009305{
Johannes Berg4c476992010-10-04 21:36:35 +02009306 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009307 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009308 struct cfg80211_chan_def chandef;
Jouni Malinen026331c2010-02-15 12:53:10 +02009309 int err;
Johannes Bergd64d3732011-11-10 09:44:46 +01009310 void *hdr = NULL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009311 u64 cookie;
Johannes Berge247bd902011-11-04 11:18:21 +01009312 struct sk_buff *msg = NULL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009313 struct cfg80211_mgmt_tx_params params = {
9314 .dont_wait_for_ack =
9315 info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
9316 };
Jouni Malinen026331c2010-02-15 12:53:10 +02009317
Johannes Berg683b6d32012-11-08 21:25:48 +01009318 if (!info->attrs[NL80211_ATTR_FRAME])
Jouni Malinen026331c2010-02-15 12:53:10 +02009319 return -EINVAL;
9320
Johannes Berg4c476992010-10-04 21:36:35 +02009321 if (!rdev->ops->mgmt_tx)
9322 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009323
Johannes Berg71bbc992012-06-15 15:30:18 +02009324 switch (wdev->iftype) {
Antonio Quartulliea141b752013-06-11 14:20:03 +02009325 case NL80211_IFTYPE_P2P_DEVICE:
9326 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
9327 return -EINVAL;
Johannes Berg71bbc992012-06-15 15:30:18 +02009328 case NL80211_IFTYPE_STATION:
9329 case NL80211_IFTYPE_ADHOC:
9330 case NL80211_IFTYPE_P2P_CLIENT:
9331 case NL80211_IFTYPE_AP:
9332 case NL80211_IFTYPE_AP_VLAN:
9333 case NL80211_IFTYPE_MESH_POINT:
9334 case NL80211_IFTYPE_P2P_GO:
9335 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009336 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009337 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009338 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009339 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009340
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009341 if (info->attrs[NL80211_ATTR_DURATION]) {
Johannes Berg7c4ef712011-11-18 15:33:48 +01009342 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009343 return -EINVAL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009344 params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
Johannes Bergebf348f2012-06-01 12:50:54 +02009345
9346 /*
9347 * We should wait on the channel for at least a minimum amount
9348 * of time (10ms) but no longer than the driver supports.
9349 */
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009350 if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9351 params.wait > rdev->wiphy.max_remain_on_channel_duration)
Johannes Bergebf348f2012-06-01 12:50:54 +02009352 return -EINVAL;
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009353 }
9354
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009355 params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009356
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009357 if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Berg7c4ef712011-11-18 15:33:48 +01009358 return -EINVAL;
9359
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009360 params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05309361
Antonio Quartulliea141b752013-06-11 14:20:03 +02009362 /* get the channel if any has been specified, otherwise pass NULL to
9363 * the driver. The latter will use the current one
9364 */
9365 chandef.chan = NULL;
9366 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
9367 err = nl80211_parse_chandef(rdev, info, &chandef);
9368 if (err)
9369 return err;
9370 }
9371
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009372 if (!chandef.chan && params.offchan)
Antonio Quartulliea141b752013-06-11 14:20:03 +02009373 return -EINVAL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009374
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +03009375 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
9376 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
9377
9378 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
9379 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9380 int i;
9381
9382 if (len % sizeof(u16))
9383 return -EINVAL;
9384
9385 params.n_csa_offsets = len / sizeof(u16);
9386 params.csa_offsets =
9387 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9388
9389 /* check that all the offsets fit the frame */
9390 for (i = 0; i < params.n_csa_offsets; i++) {
9391 if (params.csa_offsets[i] >= params.len)
9392 return -EINVAL;
9393 }
9394 }
9395
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009396 if (!params.dont_wait_for_ack) {
Johannes Berge247bd902011-11-04 11:18:21 +01009397 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9398 if (!msg)
9399 return -ENOMEM;
Jouni Malinen026331c2010-02-15 12:53:10 +02009400
Eric W. Biederman15e47302012-09-07 20:12:54 +00009401 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berge247bd902011-11-04 11:18:21 +01009402 NL80211_CMD_FRAME);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009403 if (!hdr) {
9404 err = -ENOBUFS;
Johannes Berge247bd902011-11-04 11:18:21 +01009405 goto free_msg;
9406 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009407 }
Johannes Berge247bd902011-11-04 11:18:21 +01009408
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009409 params.chan = chandef.chan;
9410 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
Jouni Malinen026331c2010-02-15 12:53:10 +02009411 if (err)
9412 goto free_msg;
9413
Johannes Berge247bd902011-11-04 11:18:21 +01009414 if (msg) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009415 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9416 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009417 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +02009418
Johannes Berge247bd902011-11-04 11:18:21 +01009419 genlmsg_end(msg, hdr);
9420 return genlmsg_reply(msg, info);
9421 }
9422
9423 return 0;
Jouni Malinen026331c2010-02-15 12:53:10 +02009424
9425 nla_put_failure:
9426 err = -ENOBUFS;
9427 free_msg:
9428 nlmsg_free(msg);
Jouni Malinen026331c2010-02-15 12:53:10 +02009429 return err;
9430}
9431
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009432static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
9433{
9434 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009435 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009436 u64 cookie;
9437
9438 if (!info->attrs[NL80211_ATTR_COOKIE])
9439 return -EINVAL;
9440
9441 if (!rdev->ops->mgmt_tx_cancel_wait)
9442 return -EOPNOTSUPP;
9443
Johannes Berg71bbc992012-06-15 15:30:18 +02009444 switch (wdev->iftype) {
9445 case NL80211_IFTYPE_STATION:
9446 case NL80211_IFTYPE_ADHOC:
9447 case NL80211_IFTYPE_P2P_CLIENT:
9448 case NL80211_IFTYPE_AP:
9449 case NL80211_IFTYPE_AP_VLAN:
9450 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009451 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009452 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009453 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009454 default:
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009455 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009456 }
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009457
9458 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9459
Hila Gonene35e4d22012-06-27 17:19:42 +03009460 return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009461}
9462
Kalle Valoffb9eb32010-02-17 17:58:10 +02009463static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
9464{
Johannes Berg4c476992010-10-04 21:36:35 +02009465 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009466 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009467 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009468 u8 ps_state;
9469 bool state;
9470 int err;
9471
Johannes Berg4c476992010-10-04 21:36:35 +02009472 if (!info->attrs[NL80211_ATTR_PS_STATE])
9473 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009474
9475 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
9476
Johannes Berg4c476992010-10-04 21:36:35 +02009477 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
9478 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009479
9480 wdev = dev->ieee80211_ptr;
9481
Johannes Berg4c476992010-10-04 21:36:35 +02009482 if (!rdev->ops->set_power_mgmt)
9483 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009484
9485 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
9486
9487 if (state == wdev->ps)
Johannes Berg4c476992010-10-04 21:36:35 +02009488 return 0;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009489
Hila Gonene35e4d22012-06-27 17:19:42 +03009490 err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
Johannes Berg4c476992010-10-04 21:36:35 +02009491 if (!err)
9492 wdev->ps = state;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009493 return err;
9494}
9495
9496static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
9497{
Johannes Berg4c476992010-10-04 21:36:35 +02009498 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009499 enum nl80211_ps_state ps_state;
9500 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009501 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009502 struct sk_buff *msg;
9503 void *hdr;
9504 int err;
9505
Kalle Valoffb9eb32010-02-17 17:58:10 +02009506 wdev = dev->ieee80211_ptr;
9507
Johannes Berg4c476992010-10-04 21:36:35 +02009508 if (!rdev->ops->set_power_mgmt)
9509 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009510
9511 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009512 if (!msg)
9513 return -ENOMEM;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009514
Eric W. Biederman15e47302012-09-07 20:12:54 +00009515 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Kalle Valoffb9eb32010-02-17 17:58:10 +02009516 NL80211_CMD_GET_POWER_SAVE);
9517 if (!hdr) {
Johannes Berg4c476992010-10-04 21:36:35 +02009518 err = -ENOBUFS;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009519 goto free_msg;
9520 }
9521
9522 if (wdev->ps)
9523 ps_state = NL80211_PS_ENABLED;
9524 else
9525 ps_state = NL80211_PS_DISABLED;
9526
David S. Miller9360ffd2012-03-29 04:41:26 -04009527 if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
9528 goto nla_put_failure;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009529
9530 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009531 return genlmsg_reply(msg, info);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009532
Johannes Berg4c476992010-10-04 21:36:35 +02009533 nla_put_failure:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009534 err = -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +02009535 free_msg:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009536 nlmsg_free(msg);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009537 return err;
9538}
9539
Johannes Berg94e860f2014-01-20 23:58:15 +01009540static const struct nla_policy
9541nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009542 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
9543 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
9544 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
Thomas Pedersen84f10702012-07-12 16:17:33 -07009545 [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
9546 [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
9547 [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009548};
9549
Thomas Pedersen84f10702012-07-12 16:17:33 -07009550static int nl80211_set_cqm_txe(struct genl_info *info,
Johannes Bergd9d8b012012-11-26 12:51:52 +01009551 u32 rate, u32 pkts, u32 intvl)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009552{
9553 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Thomas Pedersen84f10702012-07-12 16:17:33 -07009554 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009555 struct wireless_dev *wdev = dev->ieee80211_ptr;
Thomas Pedersen84f10702012-07-12 16:17:33 -07009556
Johannes Bergd9d8b012012-11-26 12:51:52 +01009557 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009558 return -EINVAL;
9559
Thomas Pedersen84f10702012-07-12 16:17:33 -07009560 if (!rdev->ops->set_cqm_txe_config)
9561 return -EOPNOTSUPP;
9562
9563 if (wdev->iftype != NL80211_IFTYPE_STATION &&
9564 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9565 return -EOPNOTSUPP;
9566
Hila Gonene35e4d22012-06-27 17:19:42 +03009567 return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
Thomas Pedersen84f10702012-07-12 16:17:33 -07009568}
9569
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009570static int nl80211_set_cqm_rssi(struct genl_info *info,
9571 s32 threshold, u32 hysteresis)
9572{
Johannes Berg4c476992010-10-04 21:36:35 +02009573 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009574 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009575 struct wireless_dev *wdev = dev->ieee80211_ptr;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009576
9577 if (threshold > 0)
9578 return -EINVAL;
9579
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009580 /* disabling - hysteresis should also be zero then */
9581 if (threshold == 0)
9582 hysteresis = 0;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009583
Johannes Berg4c476992010-10-04 21:36:35 +02009584 if (!rdev->ops->set_cqm_rssi_config)
9585 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009586
Johannes Berg074ac8d2010-09-16 14:58:22 +02009587 if (wdev->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009588 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9589 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009590
Hila Gonene35e4d22012-06-27 17:19:42 +03009591 return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009592}
9593
9594static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
9595{
9596 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
9597 struct nlattr *cqm;
9598 int err;
9599
9600 cqm = info->attrs[NL80211_ATTR_CQM];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009601 if (!cqm)
9602 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009603
9604 err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
9605 nl80211_attr_cqm_policy);
9606 if (err)
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009607 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009608
9609 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
9610 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009611 s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
9612 u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009613
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009614 return nl80211_set_cqm_rssi(info, threshold, hysteresis);
9615 }
9616
9617 if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
9618 attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
9619 attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
9620 u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
9621 u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
9622 u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
9623
9624 return nl80211_set_cqm_txe(info, rate, pkts, intvl);
9625 }
9626
9627 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009628}
9629
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01009630static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
9631{
9632 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9633 struct net_device *dev = info->user_ptr[1];
9634 struct ocb_setup setup = {};
9635 int err;
9636
9637 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9638 if (err)
9639 return err;
9640
9641 return cfg80211_join_ocb(rdev, dev, &setup);
9642}
9643
9644static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
9645{
9646 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9647 struct net_device *dev = info->user_ptr[1];
9648
9649 return cfg80211_leave_ocb(rdev, dev);
9650}
9651
Johannes Berg29cbe682010-12-03 09:20:44 +01009652static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
9653{
9654 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9655 struct net_device *dev = info->user_ptr[1];
9656 struct mesh_config cfg;
Javier Cardonac80d5452010-12-16 17:37:49 -08009657 struct mesh_setup setup;
Johannes Berg29cbe682010-12-03 09:20:44 +01009658 int err;
9659
9660 /* start with default */
9661 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
Javier Cardonac80d5452010-12-16 17:37:49 -08009662 memcpy(&setup, &default_mesh_setup, sizeof(setup));
Johannes Berg29cbe682010-12-03 09:20:44 +01009663
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009664 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01009665 /* and parse parameters if given */
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009666 err = nl80211_parse_mesh_config(info, &cfg, NULL);
Johannes Berg29cbe682010-12-03 09:20:44 +01009667 if (err)
9668 return err;
9669 }
9670
9671 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
9672 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
9673 return -EINVAL;
9674
Javier Cardonac80d5452010-12-16 17:37:49 -08009675 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
9676 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
9677
Chun-Yeow Yeoh4bb62342011-11-24 17:15:20 -08009678 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
9679 !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
9680 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
9681 return -EINVAL;
9682
Marco Porsch9bdbf042013-01-07 16:04:51 +01009683 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
9684 setup.beacon_interval =
9685 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309686
Purushottam Kushwahac6800ff2016-10-12 18:26:51 +05309687 err = cfg80211_validate_beacon_int(rdev,
9688 NL80211_IFTYPE_MESH_POINT,
9689 setup.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309690 if (err)
9691 return err;
Marco Porsch9bdbf042013-01-07 16:04:51 +01009692 }
9693
9694 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
9695 setup.dtim_period =
9696 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
9697 if (setup.dtim_period < 1 || setup.dtim_period > 100)
9698 return -EINVAL;
9699 }
9700
Javier Cardonac80d5452010-12-16 17:37:49 -08009701 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
9702 /* parse additional setup parameters if given */
9703 err = nl80211_parse_mesh_setup(info, &setup);
9704 if (err)
9705 return err;
9706 }
9707
Thomas Pedersend37bb182013-03-04 13:06:13 -08009708 if (setup.user_mpm)
9709 cfg.auto_open_plinks = false;
9710
Johannes Bergcc1d2802012-05-16 23:50:20 +02009711 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01009712 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9713 if (err)
9714 return err;
Johannes Bergcc1d2802012-05-16 23:50:20 +02009715 } else {
9716 /* cfg80211_join_mesh() will sort it out */
Johannes Berg683b6d32012-11-08 21:25:48 +01009717 setup.chandef.chan = NULL;
Johannes Bergcc1d2802012-05-16 23:50:20 +02009718 }
9719
Ashok Nagarajanffb3cf32013-06-03 10:33:36 -07009720 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
9721 u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9722 int n_rates =
9723 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9724 struct ieee80211_supported_band *sband;
9725
9726 if (!setup.chandef.chan)
9727 return -EINVAL;
9728
9729 sband = rdev->wiphy.bands[setup.chandef.chan->band];
9730
9731 err = ieee80211_get_ratemask(sband, rates, n_rates,
9732 &setup.basic_rates);
9733 if (err)
9734 return err;
9735 }
9736
Johannes Berg8564e382016-09-19 09:44:44 +02009737 if (info->attrs[NL80211_ATTR_TX_RATES]) {
9738 err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
9739 if (err)
9740 return err;
9741
Johannes Berg091eac32017-09-18 22:46:36 +02009742 if (!setup.chandef.chan)
9743 return -EINVAL;
9744
Johannes Berg8564e382016-09-19 09:44:44 +02009745 err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
9746 &setup.beacon_rate);
9747 if (err)
9748 return err;
9749 }
9750
Javier Cardonac80d5452010-12-16 17:37:49 -08009751 return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01009752}
9753
9754static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
9755{
9756 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9757 struct net_device *dev = info->user_ptr[1];
9758
9759 return cfg80211_leave_mesh(rdev, dev);
9760}
9761
Johannes Bergdfb89c52012-06-27 09:23:48 +02009762#ifdef CONFIG_PM
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009763static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
9764 struct cfg80211_registered_device *rdev)
9765{
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009766 struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009767 struct nlattr *nl_pats, *nl_pat;
9768 int i, pat_len;
9769
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009770 if (!wowlan->n_patterns)
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009771 return 0;
9772
9773 nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
9774 if (!nl_pats)
9775 return -ENOBUFS;
9776
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009777 for (i = 0; i < wowlan->n_patterns; i++) {
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009778 nl_pat = nla_nest_start(msg, i + 1);
9779 if (!nl_pat)
9780 return -ENOBUFS;
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009781 pat_len = wowlan->patterns[i].pattern_len;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07009782 if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009783 wowlan->patterns[i].mask) ||
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07009784 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
9785 wowlan->patterns[i].pattern) ||
9786 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009787 wowlan->patterns[i].pkt_offset))
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009788 return -ENOBUFS;
9789 nla_nest_end(msg, nl_pat);
9790 }
9791 nla_nest_end(msg, nl_pats);
9792
9793 return 0;
9794}
9795
Johannes Berg2a0e0472013-01-23 22:57:40 +01009796static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
9797 struct cfg80211_wowlan_tcp *tcp)
9798{
9799 struct nlattr *nl_tcp;
9800
9801 if (!tcp)
9802 return 0;
9803
9804 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
9805 if (!nl_tcp)
9806 return -ENOBUFS;
9807
Jiri Benc930345e2015-03-29 16:59:25 +02009808 if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
9809 nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
Johannes Berg2a0e0472013-01-23 22:57:40 +01009810 nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
9811 nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
9812 nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
9813 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
9814 tcp->payload_len, tcp->payload) ||
9815 nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
9816 tcp->data_interval) ||
9817 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
9818 tcp->wake_len, tcp->wake_data) ||
9819 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
9820 DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
9821 return -ENOBUFS;
9822
9823 if (tcp->payload_seq.len &&
9824 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
9825 sizeof(tcp->payload_seq), &tcp->payload_seq))
9826 return -ENOBUFS;
9827
9828 if (tcp->payload_tok.len &&
9829 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
9830 sizeof(tcp->payload_tok) + tcp->tokens_size,
9831 &tcp->payload_tok))
9832 return -ENOBUFS;
9833
Johannes Berge248ad32013-05-16 10:24:28 +02009834 nla_nest_end(msg, nl_tcp);
9835
Johannes Berg2a0e0472013-01-23 22:57:40 +01009836 return 0;
9837}
9838
Luciano Coelho75453cc2015-01-09 14:06:37 +02009839static int nl80211_send_wowlan_nd(struct sk_buff *msg,
9840 struct cfg80211_sched_scan_request *req)
9841{
Avraham Stern3b06d272015-10-12 09:51:34 +03009842 struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
Luciano Coelho75453cc2015-01-09 14:06:37 +02009843 int i;
9844
9845 if (!req)
9846 return 0;
9847
9848 nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
9849 if (!nd)
9850 return -ENOBUFS;
9851
Avraham Stern3b06d272015-10-12 09:51:34 +03009852 if (req->n_scan_plans == 1 &&
9853 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
9854 req->scan_plans[0].interval * 1000))
Luciano Coelho75453cc2015-01-09 14:06:37 +02009855 return -ENOBUFS;
9856
Luciano Coelho21fea562015-03-17 16:36:01 +02009857 if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
9858 return -ENOBUFS;
9859
vamsi krishnaf4f1a542017-01-13 01:12:20 +02009860 if (req->relative_rssi_set) {
9861 struct nl80211_bss_select_rssi_adjust rssi_adjust;
9862
9863 if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
9864 req->relative_rssi))
9865 return -ENOBUFS;
9866
9867 rssi_adjust.band = req->rssi_adjust.band;
9868 rssi_adjust.delta = req->rssi_adjust.delta;
9869 if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
9870 sizeof(rssi_adjust), &rssi_adjust))
9871 return -ENOBUFS;
9872 }
9873
Luciano Coelho75453cc2015-01-09 14:06:37 +02009874 freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
9875 if (!freqs)
9876 return -ENOBUFS;
9877
Johannes Berg53b18982016-09-14 09:59:21 +02009878 for (i = 0; i < req->n_channels; i++) {
9879 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
9880 return -ENOBUFS;
9881 }
Luciano Coelho75453cc2015-01-09 14:06:37 +02009882
9883 nla_nest_end(msg, freqs);
9884
9885 if (req->n_match_sets) {
9886 matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009887 if (!matches)
9888 return -ENOBUFS;
9889
Luciano Coelho75453cc2015-01-09 14:06:37 +02009890 for (i = 0; i < req->n_match_sets; i++) {
9891 match = nla_nest_start(msg, i);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009892 if (!match)
9893 return -ENOBUFS;
9894
Johannes Berg53b18982016-09-14 09:59:21 +02009895 if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
9896 req->match_sets[i].ssid.ssid_len,
9897 req->match_sets[i].ssid.ssid))
9898 return -ENOBUFS;
Luciano Coelho75453cc2015-01-09 14:06:37 +02009899 nla_nest_end(msg, match);
9900 }
9901 nla_nest_end(msg, matches);
9902 }
9903
Avraham Stern3b06d272015-10-12 09:51:34 +03009904 scan_plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
9905 if (!scan_plans)
9906 return -ENOBUFS;
9907
9908 for (i = 0; i < req->n_scan_plans; i++) {
9909 scan_plan = nla_nest_start(msg, i + 1);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009910 if (!scan_plan)
9911 return -ENOBUFS;
9912
Avraham Stern3b06d272015-10-12 09:51:34 +03009913 if (!scan_plan ||
9914 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
9915 req->scan_plans[i].interval) ||
9916 (req->scan_plans[i].iterations &&
9917 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
9918 req->scan_plans[i].iterations)))
9919 return -ENOBUFS;
9920 nla_nest_end(msg, scan_plan);
9921 }
9922 nla_nest_end(msg, scan_plans);
9923
Luciano Coelho75453cc2015-01-09 14:06:37 +02009924 nla_nest_end(msg, nd);
9925
9926 return 0;
9927}
9928
Johannes Bergff1b6e62011-05-04 15:37:28 +02009929static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
9930{
9931 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9932 struct sk_buff *msg;
9933 void *hdr;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009934 u32 size = NLMSG_DEFAULT_SIZE;
Johannes Bergff1b6e62011-05-04 15:37:28 +02009935
Johannes Berg964dc9e2013-06-03 17:25:34 +02009936 if (!rdev->wiphy.wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +02009937 return -EOPNOTSUPP;
9938
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009939 if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
Johannes Berg2a0e0472013-01-23 22:57:40 +01009940 /* adjust size to have room for all the data */
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009941 size += rdev->wiphy.wowlan_config->tcp->tokens_size +
9942 rdev->wiphy.wowlan_config->tcp->payload_len +
9943 rdev->wiphy.wowlan_config->tcp->wake_len +
9944 rdev->wiphy.wowlan_config->tcp->wake_len / 8;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009945 }
9946
9947 msg = nlmsg_new(size, GFP_KERNEL);
Johannes Bergff1b6e62011-05-04 15:37:28 +02009948 if (!msg)
9949 return -ENOMEM;
9950
Eric W. Biederman15e47302012-09-07 20:12:54 +00009951 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Bergff1b6e62011-05-04 15:37:28 +02009952 NL80211_CMD_GET_WOWLAN);
9953 if (!hdr)
9954 goto nla_put_failure;
9955
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009956 if (rdev->wiphy.wowlan_config) {
Johannes Bergff1b6e62011-05-04 15:37:28 +02009957 struct nlattr *nl_wowlan;
9958
9959 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
9960 if (!nl_wowlan)
9961 goto nla_put_failure;
9962
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009963 if ((rdev->wiphy.wowlan_config->any &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009964 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009965 (rdev->wiphy.wowlan_config->disconnect &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009966 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009967 (rdev->wiphy.wowlan_config->magic_pkt &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009968 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009969 (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009970 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009971 (rdev->wiphy.wowlan_config->eap_identity_req &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009972 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009973 (rdev->wiphy.wowlan_config->four_way_handshake &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009974 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009975 (rdev->wiphy.wowlan_config->rfkill_release &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009976 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
9977 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009978
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009979 if (nl80211_send_wowlan_patterns(msg, rdev))
9980 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +01009981
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009982 if (nl80211_send_wowlan_tcp(msg,
9983 rdev->wiphy.wowlan_config->tcp))
Johannes Berg2a0e0472013-01-23 22:57:40 +01009984 goto nla_put_failure;
9985
Luciano Coelho75453cc2015-01-09 14:06:37 +02009986 if (nl80211_send_wowlan_nd(
9987 msg,
9988 rdev->wiphy.wowlan_config->nd_config))
9989 goto nla_put_failure;
9990
Johannes Bergff1b6e62011-05-04 15:37:28 +02009991 nla_nest_end(msg, nl_wowlan);
9992 }
9993
9994 genlmsg_end(msg, hdr);
9995 return genlmsg_reply(msg, info);
9996
9997nla_put_failure:
9998 nlmsg_free(msg);
9999 return -ENOBUFS;
10000}
10001
Johannes Berg2a0e0472013-01-23 22:57:40 +010010002static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
10003 struct nlattr *attr,
10004 struct cfg80211_wowlan *trig)
10005{
10006 struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
10007 struct cfg80211_wowlan_tcp *cfg;
10008 struct nl80211_wowlan_tcp_data_token *tok = NULL;
10009 struct nl80211_wowlan_tcp_data_seq *seq = NULL;
10010 u32 size;
10011 u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
10012 int err, port;
10013
Johannes Berg964dc9e2013-06-03 17:25:34 +020010014 if (!rdev->wiphy.wowlan->tcp)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010015 return -EINVAL;
10016
10017 err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP,
10018 nla_data(attr), nla_len(attr),
10019 nl80211_wowlan_tcp_policy);
10020 if (err)
10021 return err;
10022
10023 if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
10024 !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
10025 !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
10026 !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
10027 !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
10028 !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
10029 !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
10030 !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
10031 return -EINVAL;
10032
10033 data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010034 if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010035 return -EINVAL;
10036
10037 if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
Johannes Berg964dc9e2013-06-03 17:25:34 +020010038 rdev->wiphy.wowlan->tcp->data_interval_max ||
Johannes Berg723d5682013-02-26 13:56:40 +010010039 nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010040 return -EINVAL;
10041
10042 wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010043 if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010044 return -EINVAL;
10045
10046 wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
10047 if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
10048 return -EINVAL;
10049
10050 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
10051 u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
10052
10053 tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
10054 tokens_size = tokln - sizeof(*tok);
10055
10056 if (!tok->len || tokens_size % tok->len)
10057 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010058 if (!rdev->wiphy.wowlan->tcp->tok)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010059 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010060 if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010061 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010062 if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010063 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010064 if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010065 return -EINVAL;
10066 if (tok->offset + tok->len > data_size)
10067 return -EINVAL;
10068 }
10069
10070 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
10071 seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010072 if (!rdev->wiphy.wowlan->tcp->seq)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010073 return -EINVAL;
10074 if (seq->len == 0 || seq->len > 4)
10075 return -EINVAL;
10076 if (seq->len + seq->offset > data_size)
10077 return -EINVAL;
10078 }
10079
10080 size = sizeof(*cfg);
10081 size += data_size;
10082 size += wake_size + wake_mask_size;
10083 size += tokens_size;
10084
10085 cfg = kzalloc(size, GFP_KERNEL);
10086 if (!cfg)
10087 return -ENOMEM;
Jiri Benc67b61f62015-03-29 16:59:26 +020010088 cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
10089 cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010090 memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
10091 ETH_ALEN);
10092 if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
10093 port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
10094 else
10095 port = 0;
10096#ifdef CONFIG_INET
10097 /* allocate a socket and port for it and use it */
10098 err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
10099 IPPROTO_TCP, &cfg->sock, 1);
10100 if (err) {
10101 kfree(cfg);
10102 return err;
10103 }
10104 if (inet_csk_get_port(cfg->sock->sk, port)) {
10105 sock_release(cfg->sock);
10106 kfree(cfg);
10107 return -EADDRINUSE;
10108 }
10109 cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
10110#else
10111 if (!port) {
10112 kfree(cfg);
10113 return -EINVAL;
10114 }
10115 cfg->src_port = port;
10116#endif
10117
10118 cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
10119 cfg->payload_len = data_size;
10120 cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
10121 memcpy((void *)cfg->payload,
10122 nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
10123 data_size);
10124 if (seq)
10125 cfg->payload_seq = *seq;
10126 cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
10127 cfg->wake_len = wake_size;
10128 cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
10129 memcpy((void *)cfg->wake_data,
10130 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
10131 wake_size);
10132 cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
10133 data_size + wake_size;
10134 memcpy((void *)cfg->wake_mask,
10135 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
10136 wake_mask_size);
10137 if (tok) {
10138 cfg->tokens_size = tokens_size;
10139 memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
10140 }
10141
10142 trig->tcp = cfg;
10143
10144 return 0;
10145}
10146
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010147static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
10148 const struct wiphy_wowlan_support *wowlan,
10149 struct nlattr *attr,
10150 struct cfg80211_wowlan *trig)
10151{
10152 struct nlattr **tb;
10153 int err;
10154
10155 tb = kzalloc(NUM_NL80211_ATTR * sizeof(*tb), GFP_KERNEL);
10156 if (!tb)
10157 return -ENOMEM;
10158
10159 if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
10160 err = -EOPNOTSUPP;
10161 goto out;
10162 }
10163
10164 err = nla_parse(tb, NL80211_ATTR_MAX,
10165 nla_data(attr), nla_len(attr),
10166 nl80211_policy);
10167 if (err)
10168 goto out;
10169
Johannes Bergad2b26a2014-06-12 21:39:05 +020010170 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010171 err = PTR_ERR_OR_ZERO(trig->nd_config);
10172 if (err)
10173 trig->nd_config = NULL;
10174
10175out:
10176 kfree(tb);
10177 return err;
10178}
10179
Johannes Bergff1b6e62011-05-04 15:37:28 +020010180static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
10181{
10182 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10183 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010184 struct cfg80211_wowlan new_triggers = {};
Johannes Bergae33bd82012-07-12 16:25:02 +020010185 struct cfg80211_wowlan *ntrig;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010186 const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010187 int err, i;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010188 bool prev_enabled = rdev->wiphy.wowlan_config;
Johannes Berg98fc4382015-03-01 09:10:13 +020010189 bool regular = false;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010190
Johannes Berg964dc9e2013-06-03 17:25:34 +020010191 if (!wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010192 return -EOPNOTSUPP;
10193
Johannes Bergae33bd82012-07-12 16:25:02 +020010194 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
10195 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010196 rdev->wiphy.wowlan_config = NULL;
Johannes Bergae33bd82012-07-12 16:25:02 +020010197 goto set_wakeup;
10198 }
Johannes Bergff1b6e62011-05-04 15:37:28 +020010199
10200 err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
10201 nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
10202 nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
10203 nl80211_wowlan_policy);
10204 if (err)
10205 return err;
10206
10207 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
10208 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
10209 return -EINVAL;
10210 new_triggers.any = true;
10211 }
10212
10213 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
10214 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
10215 return -EINVAL;
10216 new_triggers.disconnect = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010217 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010218 }
10219
10220 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
10221 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
10222 return -EINVAL;
10223 new_triggers.magic_pkt = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010224 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010225 }
10226
Johannes Berg77dbbb12011-07-13 10:48:55 +020010227 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
10228 return -EINVAL;
10229
10230 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
10231 if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
10232 return -EINVAL;
10233 new_triggers.gtk_rekey_failure = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010234 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010235 }
10236
10237 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
10238 if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
10239 return -EINVAL;
10240 new_triggers.eap_identity_req = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010241 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010242 }
10243
10244 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
10245 if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
10246 return -EINVAL;
10247 new_triggers.four_way_handshake = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010248 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010249 }
10250
10251 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
10252 if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
10253 return -EINVAL;
10254 new_triggers.rfkill_release = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010255 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010256 }
10257
Johannes Bergff1b6e62011-05-04 15:37:28 +020010258 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
10259 struct nlattr *pat;
10260 int n_patterns = 0;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010261 int rem, pat_len, mask_len, pkt_offset;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010262 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010263
Johannes Berg98fc4382015-03-01 09:10:13 +020010264 regular = true;
10265
Johannes Bergff1b6e62011-05-04 15:37:28 +020010266 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10267 rem)
10268 n_patterns++;
10269 if (n_patterns > wowlan->n_patterns)
10270 return -EINVAL;
10271
10272 new_triggers.patterns = kcalloc(n_patterns,
10273 sizeof(new_triggers.patterns[0]),
10274 GFP_KERNEL);
10275 if (!new_triggers.patterns)
10276 return -ENOMEM;
10277
10278 new_triggers.n_patterns = n_patterns;
10279 i = 0;
10280
10281 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10282 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010283 u8 *mask_pat;
10284
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010285 nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
Peng Xu4ec90fd2017-10-10 13:56:53 -070010286 nla_len(pat), nl80211_packet_pattern_policy);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010287 err = -EINVAL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010288 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10289 !pat_tb[NL80211_PKTPAT_PATTERN])
Johannes Bergff1b6e62011-05-04 15:37:28 +020010290 goto error;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010291 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010292 mask_len = DIV_ROUND_UP(pat_len, 8);
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010293 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010294 goto error;
10295 if (pat_len > wowlan->pattern_max_len ||
10296 pat_len < wowlan->pattern_min_len)
10297 goto error;
10298
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010299 if (!pat_tb[NL80211_PKTPAT_OFFSET])
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010300 pkt_offset = 0;
10301 else
10302 pkt_offset = nla_get_u32(
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010303 pat_tb[NL80211_PKTPAT_OFFSET]);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010304 if (pkt_offset > wowlan->max_pkt_offset)
10305 goto error;
10306 new_triggers.patterns[i].pkt_offset = pkt_offset;
10307
Johannes Berg922bd802014-05-19 17:59:50 +020010308 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10309 if (!mask_pat) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010310 err = -ENOMEM;
10311 goto error;
10312 }
Johannes Berg922bd802014-05-19 17:59:50 +020010313 new_triggers.patterns[i].mask = mask_pat;
10314 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010315 mask_len);
Johannes Berg922bd802014-05-19 17:59:50 +020010316 mask_pat += mask_len;
10317 new_triggers.patterns[i].pattern = mask_pat;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010318 new_triggers.patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010319 memcpy(mask_pat,
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010320 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010321 pat_len);
10322 i++;
10323 }
10324 }
10325
Johannes Berg2a0e0472013-01-23 22:57:40 +010010326 if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010327 regular = true;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010328 err = nl80211_parse_wowlan_tcp(
10329 rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
10330 &new_triggers);
10331 if (err)
10332 goto error;
10333 }
10334
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010335 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010336 regular = true;
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010337 err = nl80211_parse_wowlan_nd(
10338 rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
10339 &new_triggers);
10340 if (err)
10341 goto error;
10342 }
10343
Johannes Berg98fc4382015-03-01 09:10:13 +020010344 /* The 'any' trigger means the device continues operating more or less
10345 * as in its normal operation mode and wakes up the host on most of the
10346 * normal interrupts (like packet RX, ...)
10347 * It therefore makes little sense to combine with the more constrained
10348 * wakeup trigger modes.
10349 */
10350 if (new_triggers.any && regular) {
10351 err = -EINVAL;
10352 goto error;
10353 }
10354
Johannes Bergae33bd82012-07-12 16:25:02 +020010355 ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
10356 if (!ntrig) {
10357 err = -ENOMEM;
10358 goto error;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010359 }
Johannes Bergae33bd82012-07-12 16:25:02 +020010360 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010361 rdev->wiphy.wowlan_config = ntrig;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010362
Johannes Bergae33bd82012-07-12 16:25:02 +020010363 set_wakeup:
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010364 if (rdev->ops->set_wakeup &&
10365 prev_enabled != !!rdev->wiphy.wowlan_config)
10366 rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
Johannes Berg6d525632012-04-04 15:05:25 +020010367
Johannes Bergff1b6e62011-05-04 15:37:28 +020010368 return 0;
10369 error:
10370 for (i = 0; i < new_triggers.n_patterns; i++)
10371 kfree(new_triggers.patterns[i].mask);
10372 kfree(new_triggers.patterns);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010373 if (new_triggers.tcp && new_triggers.tcp->sock)
10374 sock_release(new_triggers.tcp->sock);
10375 kfree(new_triggers.tcp);
Ola Olssone5dbe072015-12-12 23:17:17 +010010376 kfree(new_triggers.nd_config);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010377 return err;
10378}
Johannes Bergdfb89c52012-06-27 09:23:48 +020010379#endif
Johannes Bergff1b6e62011-05-04 15:37:28 +020010380
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010381static int nl80211_send_coalesce_rules(struct sk_buff *msg,
10382 struct cfg80211_registered_device *rdev)
10383{
10384 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
10385 int i, j, pat_len;
10386 struct cfg80211_coalesce_rules *rule;
10387
10388 if (!rdev->coalesce->n_rules)
10389 return 0;
10390
10391 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
10392 if (!nl_rules)
10393 return -ENOBUFS;
10394
10395 for (i = 0; i < rdev->coalesce->n_rules; i++) {
10396 nl_rule = nla_nest_start(msg, i + 1);
10397 if (!nl_rule)
10398 return -ENOBUFS;
10399
10400 rule = &rdev->coalesce->rules[i];
10401 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
10402 rule->delay))
10403 return -ENOBUFS;
10404
10405 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
10406 rule->condition))
10407 return -ENOBUFS;
10408
10409 nl_pats = nla_nest_start(msg,
10410 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
10411 if (!nl_pats)
10412 return -ENOBUFS;
10413
10414 for (j = 0; j < rule->n_patterns; j++) {
10415 nl_pat = nla_nest_start(msg, j + 1);
10416 if (!nl_pat)
10417 return -ENOBUFS;
10418 pat_len = rule->patterns[j].pattern_len;
10419 if (nla_put(msg, NL80211_PKTPAT_MASK,
10420 DIV_ROUND_UP(pat_len, 8),
10421 rule->patterns[j].mask) ||
10422 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
10423 rule->patterns[j].pattern) ||
10424 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
10425 rule->patterns[j].pkt_offset))
10426 return -ENOBUFS;
10427 nla_nest_end(msg, nl_pat);
10428 }
10429 nla_nest_end(msg, nl_pats);
10430 nla_nest_end(msg, nl_rule);
10431 }
10432 nla_nest_end(msg, nl_rules);
10433
10434 return 0;
10435}
10436
10437static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
10438{
10439 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10440 struct sk_buff *msg;
10441 void *hdr;
10442
10443 if (!rdev->wiphy.coalesce)
10444 return -EOPNOTSUPP;
10445
10446 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10447 if (!msg)
10448 return -ENOMEM;
10449
10450 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10451 NL80211_CMD_GET_COALESCE);
10452 if (!hdr)
10453 goto nla_put_failure;
10454
10455 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
10456 goto nla_put_failure;
10457
10458 genlmsg_end(msg, hdr);
10459 return genlmsg_reply(msg, info);
10460
10461nla_put_failure:
10462 nlmsg_free(msg);
10463 return -ENOBUFS;
10464}
10465
10466void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
10467{
10468 struct cfg80211_coalesce *coalesce = rdev->coalesce;
10469 int i, j;
10470 struct cfg80211_coalesce_rules *rule;
10471
10472 if (!coalesce)
10473 return;
10474
10475 for (i = 0; i < coalesce->n_rules; i++) {
10476 rule = &coalesce->rules[i];
10477 for (j = 0; j < rule->n_patterns; j++)
10478 kfree(rule->patterns[j].mask);
10479 kfree(rule->patterns);
10480 }
10481 kfree(coalesce->rules);
10482 kfree(coalesce);
10483 rdev->coalesce = NULL;
10484}
10485
10486static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
10487 struct nlattr *rule,
10488 struct cfg80211_coalesce_rules *new_rule)
10489{
10490 int err, i;
10491 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10492 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
10493 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
10494 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
10495
10496 err = nla_parse(tb, NL80211_ATTR_COALESCE_RULE_MAX, nla_data(rule),
10497 nla_len(rule), nl80211_coalesce_policy);
10498 if (err)
10499 return err;
10500
10501 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
10502 new_rule->delay =
10503 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
10504 if (new_rule->delay > coalesce->max_delay)
10505 return -EINVAL;
10506
10507 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
10508 new_rule->condition =
10509 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
10510 if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
10511 new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
10512 return -EINVAL;
10513
10514 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
10515 return -EINVAL;
10516
10517 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10518 rem)
10519 n_patterns++;
10520 if (n_patterns > coalesce->n_patterns)
10521 return -EINVAL;
10522
10523 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
10524 GFP_KERNEL);
10525 if (!new_rule->patterns)
10526 return -ENOMEM;
10527
10528 new_rule->n_patterns = n_patterns;
10529 i = 0;
10530
10531 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10532 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010533 u8 *mask_pat;
10534
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010535 nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
Peng Xu4ec90fd2017-10-10 13:56:53 -070010536 nla_len(pat), nl80211_packet_pattern_policy);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010537 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10538 !pat_tb[NL80211_PKTPAT_PATTERN])
10539 return -EINVAL;
10540 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
10541 mask_len = DIV_ROUND_UP(pat_len, 8);
10542 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
10543 return -EINVAL;
10544 if (pat_len > coalesce->pattern_max_len ||
10545 pat_len < coalesce->pattern_min_len)
10546 return -EINVAL;
10547
10548 if (!pat_tb[NL80211_PKTPAT_OFFSET])
10549 pkt_offset = 0;
10550 else
10551 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
10552 if (pkt_offset > coalesce->max_pkt_offset)
10553 return -EINVAL;
10554 new_rule->patterns[i].pkt_offset = pkt_offset;
10555
Johannes Berg922bd802014-05-19 17:59:50 +020010556 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10557 if (!mask_pat)
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010558 return -ENOMEM;
Johannes Berg922bd802014-05-19 17:59:50 +020010559
10560 new_rule->patterns[i].mask = mask_pat;
10561 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
10562 mask_len);
10563
10564 mask_pat += mask_len;
10565 new_rule->patterns[i].pattern = mask_pat;
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010566 new_rule->patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010567 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
10568 pat_len);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010569 i++;
10570 }
10571
10572 return 0;
10573}
10574
10575static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
10576{
10577 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10578 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10579 struct cfg80211_coalesce new_coalesce = {};
10580 struct cfg80211_coalesce *n_coalesce;
10581 int err, rem_rule, n_rules = 0, i, j;
10582 struct nlattr *rule;
10583 struct cfg80211_coalesce_rules *tmp_rule;
10584
10585 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
10586 return -EOPNOTSUPP;
10587
10588 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
10589 cfg80211_rdev_free_coalesce(rdev);
Ilan Peera1056b12015-10-22 22:27:46 +030010590 rdev_set_coalesce(rdev, NULL);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010591 return 0;
10592 }
10593
10594 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10595 rem_rule)
10596 n_rules++;
10597 if (n_rules > coalesce->n_rules)
10598 return -EINVAL;
10599
10600 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
10601 GFP_KERNEL);
10602 if (!new_coalesce.rules)
10603 return -ENOMEM;
10604
10605 new_coalesce.n_rules = n_rules;
10606 i = 0;
10607
10608 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10609 rem_rule) {
10610 err = nl80211_parse_coalesce_rule(rdev, rule,
10611 &new_coalesce.rules[i]);
10612 if (err)
10613 goto error;
10614
10615 i++;
10616 }
10617
Ilan Peera1056b12015-10-22 22:27:46 +030010618 err = rdev_set_coalesce(rdev, &new_coalesce);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010619 if (err)
10620 goto error;
10621
10622 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
10623 if (!n_coalesce) {
10624 err = -ENOMEM;
10625 goto error;
10626 }
10627 cfg80211_rdev_free_coalesce(rdev);
10628 rdev->coalesce = n_coalesce;
10629
10630 return 0;
10631error:
10632 for (i = 0; i < new_coalesce.n_rules; i++) {
10633 tmp_rule = &new_coalesce.rules[i];
10634 for (j = 0; j < tmp_rule->n_patterns; j++)
10635 kfree(tmp_rule->patterns[j].mask);
10636 kfree(tmp_rule->patterns);
10637 }
10638 kfree(new_coalesce.rules);
10639
10640 return err;
10641}
10642
Johannes Berge5497d72011-07-05 16:35:40 +020010643static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
10644{
10645 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10646 struct net_device *dev = info->user_ptr[1];
10647 struct wireless_dev *wdev = dev->ieee80211_ptr;
10648 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
10649 struct cfg80211_gtk_rekey_data rekey_data;
10650 int err;
10651
10652 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
10653 return -EINVAL;
10654
10655 err = nla_parse(tb, MAX_NL80211_REKEY_DATA,
10656 nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]),
10657 nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]),
10658 nl80211_rekey_policy);
10659 if (err)
10660 return err;
10661
Vidyullatha Kanchanapally84aa3ba2017-05-25 20:20:41 +053010662 if (!tb[NL80211_REKEY_DATA_KEK] || !tb[NL80211_REKEY_DATA_REPLAY_CTR] ||
10663 (!wiphy_ext_feature_isset(&rdev->wiphy,
10664 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
10665 !wiphy_ext_feature_isset(&rdev->wiphy,
10666 NL80211_EXT_FEATURE_FILS_STA) &&
10667 !tb[NL80211_REKEY_DATA_KCK]))
10668 return -EINVAL;
10669
Johannes Berge5497d72011-07-05 16:35:40 +020010670 if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
10671 return -ERANGE;
Vidyullatha Kanchanapally84aa3ba2017-05-25 20:20:41 +053010672 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) < NL80211_KEK_LEN)
Johannes Berge5497d72011-07-05 16:35:40 +020010673 return -ERANGE;
Vidyullatha Kanchanapally84aa3ba2017-05-25 20:20:41 +053010674 if (tb[NL80211_REKEY_DATA_KCK] &&
10675 nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
Johannes Berge5497d72011-07-05 16:35:40 +020010676 return -ERANGE;
10677
Vidyullatha Kanchanapally84aa3ba2017-05-25 20:20:41 +053010678 memset(&rekey_data, 0, sizeof(rekey_data));
Johannes Berg78f686c2014-09-10 22:28:06 +030010679 rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
Vidyullatha Kanchanapally84aa3ba2017-05-25 20:20:41 +053010680 rekey_data.kek_len = nla_len(tb[NL80211_REKEY_DATA_KEK]);
10681 if (tb[NL80211_REKEY_DATA_KCK])
10682 rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
Johannes Berg78f686c2014-09-10 22:28:06 +030010683 rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
Johannes Berge5497d72011-07-05 16:35:40 +020010684
10685 wdev_lock(wdev);
10686 if (!wdev->current_bss) {
10687 err = -ENOTCONN;
10688 goto out;
10689 }
10690
10691 if (!rdev->ops->set_rekey_data) {
10692 err = -EOPNOTSUPP;
10693 goto out;
10694 }
10695
Hila Gonene35e4d22012-06-27 17:19:42 +030010696 err = rdev_set_rekey_data(rdev, dev, &rekey_data);
Johannes Berge5497d72011-07-05 16:35:40 +020010697 out:
10698 wdev_unlock(wdev);
10699 return err;
10700}
10701
Johannes Berg28946da2011-11-04 11:18:12 +010010702static int nl80211_register_unexpected_frame(struct sk_buff *skb,
10703 struct genl_info *info)
10704{
10705 struct net_device *dev = info->user_ptr[1];
10706 struct wireless_dev *wdev = dev->ieee80211_ptr;
10707
10708 if (wdev->iftype != NL80211_IFTYPE_AP &&
10709 wdev->iftype != NL80211_IFTYPE_P2P_GO)
10710 return -EINVAL;
10711
Eric W. Biederman15e47302012-09-07 20:12:54 +000010712 if (wdev->ap_unexpected_nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010010713 return -EBUSY;
10714
Eric W. Biederman15e47302012-09-07 20:12:54 +000010715 wdev->ap_unexpected_nlportid = info->snd_portid;
Johannes Berg28946da2011-11-04 11:18:12 +010010716 return 0;
10717}
10718
Johannes Berg7f6cf312011-11-04 11:18:15 +010010719static int nl80211_probe_client(struct sk_buff *skb,
10720 struct genl_info *info)
10721{
10722 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10723 struct net_device *dev = info->user_ptr[1];
10724 struct wireless_dev *wdev = dev->ieee80211_ptr;
10725 struct sk_buff *msg;
10726 void *hdr;
10727 const u8 *addr;
10728 u64 cookie;
10729 int err;
10730
10731 if (wdev->iftype != NL80211_IFTYPE_AP &&
10732 wdev->iftype != NL80211_IFTYPE_P2P_GO)
10733 return -EOPNOTSUPP;
10734
10735 if (!info->attrs[NL80211_ATTR_MAC])
10736 return -EINVAL;
10737
10738 if (!rdev->ops->probe_client)
10739 return -EOPNOTSUPP;
10740
10741 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10742 if (!msg)
10743 return -ENOMEM;
10744
Eric W. Biederman15e47302012-09-07 20:12:54 +000010745 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg7f6cf312011-11-04 11:18:15 +010010746 NL80211_CMD_PROBE_CLIENT);
Dan Carpentercb35fba2013-08-14 14:50:01 +030010747 if (!hdr) {
10748 err = -ENOBUFS;
Johannes Berg7f6cf312011-11-04 11:18:15 +010010749 goto free_msg;
10750 }
10751
10752 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
10753
Hila Gonene35e4d22012-06-27 17:19:42 +030010754 err = rdev_probe_client(rdev, dev, addr, &cookie);
Johannes Berg7f6cf312011-11-04 11:18:15 +010010755 if (err)
10756 goto free_msg;
10757
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020010758 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
10759 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040010760 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010010761
10762 genlmsg_end(msg, hdr);
10763
10764 return genlmsg_reply(msg, info);
10765
10766 nla_put_failure:
10767 err = -ENOBUFS;
10768 free_msg:
10769 nlmsg_free(msg);
10770 return err;
10771}
10772
Johannes Berg5e7602302011-11-04 11:18:17 +010010773static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
10774{
10775 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Ben Greear37c73b52012-10-26 14:49:25 -070010776 struct cfg80211_beacon_registration *reg, *nreg;
10777 int rv;
Johannes Berg5e7602302011-11-04 11:18:17 +010010778
10779 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
10780 return -EOPNOTSUPP;
10781
Ben Greear37c73b52012-10-26 14:49:25 -070010782 nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
10783 if (!nreg)
10784 return -ENOMEM;
Johannes Berg5e7602302011-11-04 11:18:17 +010010785
Ben Greear37c73b52012-10-26 14:49:25 -070010786 /* First, check if already registered. */
10787 spin_lock_bh(&rdev->beacon_registrations_lock);
10788 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
10789 if (reg->nlportid == info->snd_portid) {
10790 rv = -EALREADY;
10791 goto out_err;
10792 }
10793 }
10794 /* Add it to the list */
10795 nreg->nlportid = info->snd_portid;
10796 list_add(&nreg->list, &rdev->beacon_registrations);
10797
10798 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e7602302011-11-04 11:18:17 +010010799
10800 return 0;
Ben Greear37c73b52012-10-26 14:49:25 -070010801out_err:
10802 spin_unlock_bh(&rdev->beacon_registrations_lock);
10803 kfree(nreg);
10804 return rv;
Johannes Berg5e7602302011-11-04 11:18:17 +010010805}
10806
Johannes Berg98104fde2012-06-16 00:19:54 +020010807static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
10808{
10809 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10810 struct wireless_dev *wdev = info->user_ptr[1];
10811 int err;
10812
10813 if (!rdev->ops->start_p2p_device)
10814 return -EOPNOTSUPP;
10815
10816 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
10817 return -EOPNOTSUPP;
10818
10819 if (wdev->p2p_started)
10820 return 0;
10821
Luciano Coelhob6a55012014-02-27 11:07:21 +020010822 if (rfkill_blocked(rdev->rfkill))
10823 return -ERFKILL;
Johannes Berg98104fde2012-06-16 00:19:54 +020010824
Johannes Bergeeb126e2012-10-23 15:16:50 +020010825 err = rdev_start_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020010826 if (err)
10827 return err;
10828
10829 wdev->p2p_started = true;
Johannes Berg98104fde2012-06-16 00:19:54 +020010830 rdev->opencount++;
Johannes Berg98104fde2012-06-16 00:19:54 +020010831
10832 return 0;
10833}
10834
10835static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
10836{
10837 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10838 struct wireless_dev *wdev = info->user_ptr[1];
10839
10840 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
10841 return -EOPNOTSUPP;
10842
10843 if (!rdev->ops->stop_p2p_device)
10844 return -EOPNOTSUPP;
10845
Johannes Bergf9f47522013-03-19 15:04:07 +010010846 cfg80211_stop_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020010847
10848 return 0;
10849}
10850
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010851static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
10852{
10853 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10854 struct wireless_dev *wdev = info->user_ptr[1];
10855 struct cfg80211_nan_conf conf = {};
10856 int err;
10857
10858 if (wdev->iftype != NL80211_IFTYPE_NAN)
10859 return -EOPNOTSUPP;
10860
10861 if (wdev->nan_started)
10862 return -EEXIST;
10863
10864 if (rfkill_blocked(rdev->rfkill))
10865 return -ERFKILL;
10866
10867 if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
10868 return -EINVAL;
10869
10870 if (!info->attrs[NL80211_ATTR_NAN_DUAL])
10871 return -EINVAL;
10872
10873 conf.master_pref =
10874 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
10875 if (!conf.master_pref)
10876 return -EINVAL;
10877
10878 conf.dual = nla_get_u8(info->attrs[NL80211_ATTR_NAN_DUAL]);
10879
10880 err = rdev_start_nan(rdev, wdev, &conf);
10881 if (err)
10882 return err;
10883
10884 wdev->nan_started = true;
10885 rdev->opencount++;
10886
10887 return 0;
10888}
10889
10890static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
10891{
10892 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10893 struct wireless_dev *wdev = info->user_ptr[1];
10894
10895 if (wdev->iftype != NL80211_IFTYPE_NAN)
10896 return -EOPNOTSUPP;
10897
10898 cfg80211_stop_nan(rdev, wdev);
10899
10900 return 0;
10901}
10902
Ayala Bekera442b762016-09-20 17:31:15 +030010903static int validate_nan_filter(struct nlattr *filter_attr)
10904{
10905 struct nlattr *attr;
10906 int len = 0, n_entries = 0, rem;
10907
10908 nla_for_each_nested(attr, filter_attr, rem) {
10909 len += nla_len(attr);
10910 n_entries++;
10911 }
10912
10913 if (len >= U8_MAX)
10914 return -EINVAL;
10915
10916 return n_entries;
10917}
10918
10919static int handle_nan_filter(struct nlattr *attr_filter,
10920 struct cfg80211_nan_func *func,
10921 bool tx)
10922{
10923 struct nlattr *attr;
10924 int n_entries, rem, i;
10925 struct cfg80211_nan_func_filter *filter;
10926
10927 n_entries = validate_nan_filter(attr_filter);
10928 if (n_entries < 0)
10929 return n_entries;
10930
10931 BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
10932
10933 filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
10934 if (!filter)
10935 return -ENOMEM;
10936
10937 i = 0;
10938 nla_for_each_nested(attr, attr_filter, rem) {
10939 filter[i].filter = kmemdup(nla_data(attr), nla_len(attr),
10940 GFP_KERNEL);
10941 filter[i].len = nla_len(attr);
10942 i++;
10943 }
10944 if (tx) {
10945 func->num_tx_filters = n_entries;
10946 func->tx_filters = filter;
10947 } else {
10948 func->num_rx_filters = n_entries;
10949 func->rx_filters = filter;
10950 }
10951
10952 return 0;
10953}
10954
10955static int nl80211_nan_add_func(struct sk_buff *skb,
10956 struct genl_info *info)
10957{
10958 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10959 struct wireless_dev *wdev = info->user_ptr[1];
10960 struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
10961 struct cfg80211_nan_func *func;
10962 struct sk_buff *msg = NULL;
10963 void *hdr = NULL;
10964 int err = 0;
10965
10966 if (wdev->iftype != NL80211_IFTYPE_NAN)
10967 return -EOPNOTSUPP;
10968
10969 if (!wdev->nan_started)
10970 return -ENOTCONN;
10971
10972 if (!info->attrs[NL80211_ATTR_NAN_FUNC])
10973 return -EINVAL;
10974
10975 if (wdev->owner_nlportid &&
10976 wdev->owner_nlportid != info->snd_portid)
10977 return -ENOTCONN;
10978
10979 err = nla_parse(tb, NL80211_NAN_FUNC_ATTR_MAX,
10980 nla_data(info->attrs[NL80211_ATTR_NAN_FUNC]),
10981 nla_len(info->attrs[NL80211_ATTR_NAN_FUNC]),
10982 nl80211_nan_func_policy);
10983 if (err)
10984 return err;
10985
10986 func = kzalloc(sizeof(*func), GFP_KERNEL);
10987 if (!func)
10988 return -ENOMEM;
10989
10990 func->cookie = wdev->wiphy->cookie_counter++;
10991
10992 if (!tb[NL80211_NAN_FUNC_TYPE] ||
10993 nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) {
10994 err = -EINVAL;
10995 goto out;
10996 }
10997
10998
10999 func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
11000
11001 if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
11002 err = -EINVAL;
11003 goto out;
11004 }
11005
11006 memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
11007 sizeof(func->service_id));
11008
11009 func->close_range =
11010 nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
11011
11012 if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
11013 func->serv_spec_info_len =
11014 nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
11015 func->serv_spec_info =
11016 kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
11017 func->serv_spec_info_len,
11018 GFP_KERNEL);
11019 if (!func->serv_spec_info) {
11020 err = -ENOMEM;
11021 goto out;
11022 }
11023 }
11024
11025 if (tb[NL80211_NAN_FUNC_TTL])
11026 func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
11027
11028 switch (func->type) {
11029 case NL80211_NAN_FUNC_PUBLISH:
11030 if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
11031 err = -EINVAL;
11032 goto out;
11033 }
11034
11035 func->publish_type =
11036 nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
11037 func->publish_bcast =
11038 nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
11039
11040 if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
11041 func->publish_bcast) {
11042 err = -EINVAL;
11043 goto out;
11044 }
11045 break;
11046 case NL80211_NAN_FUNC_SUBSCRIBE:
11047 func->subscribe_active =
11048 nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
11049 break;
11050 case NL80211_NAN_FUNC_FOLLOW_UP:
11051 if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
11052 !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]) {
11053 err = -EINVAL;
11054 goto out;
11055 }
11056
11057 func->followup_id =
11058 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
11059 func->followup_reqid =
11060 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
11061 memcpy(func->followup_dest.addr,
11062 nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
11063 sizeof(func->followup_dest.addr));
11064 if (func->ttl) {
11065 err = -EINVAL;
11066 goto out;
11067 }
11068 break;
11069 default:
11070 err = -EINVAL;
11071 goto out;
11072 }
11073
11074 if (tb[NL80211_NAN_FUNC_SRF]) {
11075 struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
11076
11077 err = nla_parse(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
11078 nla_data(tb[NL80211_NAN_FUNC_SRF]),
11079 nla_len(tb[NL80211_NAN_FUNC_SRF]), NULL);
11080 if (err)
11081 goto out;
11082
11083 func->srf_include =
11084 nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
11085
11086 if (srf_tb[NL80211_NAN_SRF_BF]) {
11087 if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
11088 !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
11089 err = -EINVAL;
11090 goto out;
11091 }
11092
11093 func->srf_bf_len =
11094 nla_len(srf_tb[NL80211_NAN_SRF_BF]);
11095 func->srf_bf =
11096 kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
11097 func->srf_bf_len, GFP_KERNEL);
11098 if (!func->srf_bf) {
11099 err = -ENOMEM;
11100 goto out;
11101 }
11102
11103 func->srf_bf_idx =
11104 nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
11105 } else {
11106 struct nlattr *attr, *mac_attr =
11107 srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
11108 int n_entries, rem, i = 0;
11109
11110 if (!mac_attr) {
11111 err = -EINVAL;
11112 goto out;
11113 }
11114
11115 n_entries = validate_acl_mac_addrs(mac_attr);
11116 if (n_entries <= 0) {
11117 err = -EINVAL;
11118 goto out;
11119 }
11120
11121 func->srf_num_macs = n_entries;
11122 func->srf_macs =
11123 kzalloc(sizeof(*func->srf_macs) * n_entries,
11124 GFP_KERNEL);
11125 if (!func->srf_macs) {
11126 err = -ENOMEM;
11127 goto out;
11128 }
11129
11130 nla_for_each_nested(attr, mac_attr, rem)
11131 memcpy(func->srf_macs[i++].addr, nla_data(attr),
11132 sizeof(*func->srf_macs));
11133 }
11134 }
11135
11136 if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
11137 err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
11138 func, true);
11139 if (err)
11140 goto out;
11141 }
11142
11143 if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
11144 err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
11145 func, false);
11146 if (err)
11147 goto out;
11148 }
11149
11150 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11151 if (!msg) {
11152 err = -ENOMEM;
11153 goto out;
11154 }
11155
11156 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11157 NL80211_CMD_ADD_NAN_FUNCTION);
11158 /* This can't really happen - we just allocated 4KB */
11159 if (WARN_ON(!hdr)) {
11160 err = -ENOMEM;
11161 goto out;
11162 }
11163
11164 err = rdev_add_nan_func(rdev, wdev, func);
11165out:
11166 if (err < 0) {
11167 cfg80211_free_nan_func(func);
11168 nlmsg_free(msg);
11169 return err;
11170 }
11171
11172 /* propagate the instance id and cookie to userspace */
11173 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
11174 NL80211_ATTR_PAD))
11175 goto nla_put_failure;
11176
11177 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11178 if (!func_attr)
11179 goto nla_put_failure;
11180
11181 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
11182 func->instance_id))
11183 goto nla_put_failure;
11184
11185 nla_nest_end(msg, func_attr);
11186
11187 genlmsg_end(msg, hdr);
11188 return genlmsg_reply(msg, info);
11189
11190nla_put_failure:
11191 nlmsg_free(msg);
11192 return -ENOBUFS;
11193}
11194
11195static int nl80211_nan_del_func(struct sk_buff *skb,
11196 struct genl_info *info)
11197{
11198 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11199 struct wireless_dev *wdev = info->user_ptr[1];
11200 u64 cookie;
11201
11202 if (wdev->iftype != NL80211_IFTYPE_NAN)
11203 return -EOPNOTSUPP;
11204
11205 if (!wdev->nan_started)
11206 return -ENOTCONN;
11207
11208 if (!info->attrs[NL80211_ATTR_COOKIE])
11209 return -EINVAL;
11210
11211 if (wdev->owner_nlportid &&
11212 wdev->owner_nlportid != info->snd_portid)
11213 return -ENOTCONN;
11214
11215 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
11216
11217 rdev_del_nan_func(rdev, wdev, cookie);
11218
11219 return 0;
11220}
11221
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011222static int nl80211_nan_change_config(struct sk_buff *skb,
11223 struct genl_info *info)
11224{
11225 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11226 struct wireless_dev *wdev = info->user_ptr[1];
11227 struct cfg80211_nan_conf conf = {};
11228 u32 changed = 0;
11229
11230 if (wdev->iftype != NL80211_IFTYPE_NAN)
11231 return -EOPNOTSUPP;
11232
11233 if (!wdev->nan_started)
11234 return -ENOTCONN;
11235
11236 if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
11237 conf.master_pref =
11238 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11239 if (conf.master_pref <= 1 || conf.master_pref == 255)
11240 return -EINVAL;
11241
11242 changed |= CFG80211_NAN_CONF_CHANGED_PREF;
11243 }
11244
11245 if (info->attrs[NL80211_ATTR_NAN_DUAL]) {
11246 conf.dual = nla_get_u8(info->attrs[NL80211_ATTR_NAN_DUAL]);
11247 changed |= CFG80211_NAN_CONF_CHANGED_DUAL;
11248 }
11249
11250 if (!changed)
11251 return -EINVAL;
11252
11253 return rdev_nan_change_conf(rdev, wdev, &conf, changed);
11254}
11255
Ayala Beker50bcd312016-09-20 17:31:17 +030011256void cfg80211_nan_match(struct wireless_dev *wdev,
11257 struct cfg80211_nan_match_params *match, gfp_t gfp)
11258{
11259 struct wiphy *wiphy = wdev->wiphy;
11260 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11261 struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
11262 struct sk_buff *msg;
11263 void *hdr;
11264
11265 if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
11266 return;
11267
11268 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11269 if (!msg)
11270 return;
11271
11272 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
11273 if (!hdr) {
11274 nlmsg_free(msg);
11275 return;
11276 }
11277
11278 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11279 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11280 wdev->netdev->ifindex)) ||
11281 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11282 NL80211_ATTR_PAD))
11283 goto nla_put_failure;
11284
11285 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
11286 NL80211_ATTR_PAD) ||
11287 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
11288 goto nla_put_failure;
11289
11290 match_attr = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH);
11291 if (!match_attr)
11292 goto nla_put_failure;
11293
11294 local_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_LOCAL);
11295 if (!local_func_attr)
11296 goto nla_put_failure;
11297
11298 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
11299 goto nla_put_failure;
11300
11301 nla_nest_end(msg, local_func_attr);
11302
11303 peer_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_PEER);
11304 if (!peer_func_attr)
11305 goto nla_put_failure;
11306
11307 if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
11308 nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
11309 goto nla_put_failure;
11310
11311 if (match->info && match->info_len &&
11312 nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
11313 match->info))
11314 goto nla_put_failure;
11315
11316 nla_nest_end(msg, peer_func_attr);
11317 nla_nest_end(msg, match_attr);
11318 genlmsg_end(msg, hdr);
11319
11320 if (!wdev->owner_nlportid)
11321 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11322 msg, 0, NL80211_MCGRP_NAN, gfp);
11323 else
11324 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11325 wdev->owner_nlportid);
11326
11327 return;
11328
11329nla_put_failure:
11330 nlmsg_free(msg);
11331}
11332EXPORT_SYMBOL(cfg80211_nan_match);
11333
Ayala Beker368e5a72016-09-20 17:31:18 +030011334void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
11335 u8 inst_id,
11336 enum nl80211_nan_func_term_reason reason,
11337 u64 cookie, gfp_t gfp)
11338{
11339 struct wiphy *wiphy = wdev->wiphy;
11340 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11341 struct sk_buff *msg;
11342 struct nlattr *func_attr;
11343 void *hdr;
11344
11345 if (WARN_ON(!inst_id))
11346 return;
11347
11348 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11349 if (!msg)
11350 return;
11351
11352 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
11353 if (!hdr) {
11354 nlmsg_free(msg);
11355 return;
11356 }
11357
11358 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11359 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11360 wdev->netdev->ifindex)) ||
11361 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11362 NL80211_ATTR_PAD))
11363 goto nla_put_failure;
11364
11365 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11366 NL80211_ATTR_PAD))
11367 goto nla_put_failure;
11368
11369 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11370 if (!func_attr)
11371 goto nla_put_failure;
11372
11373 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
11374 nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
11375 goto nla_put_failure;
11376
11377 nla_nest_end(msg, func_attr);
11378 genlmsg_end(msg, hdr);
11379
11380 if (!wdev->owner_nlportid)
11381 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11382 msg, 0, NL80211_MCGRP_NAN, gfp);
11383 else
11384 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11385 wdev->owner_nlportid);
11386
11387 return;
11388
11389nla_put_failure:
11390 nlmsg_free(msg);
11391}
11392EXPORT_SYMBOL(cfg80211_nan_func_terminated);
11393
Johannes Berg3713b4e2013-02-14 16:19:38 +010011394static int nl80211_get_protocol_features(struct sk_buff *skb,
11395 struct genl_info *info)
11396{
11397 void *hdr;
11398 struct sk_buff *msg;
11399
11400 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11401 if (!msg)
11402 return -ENOMEM;
11403
11404 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11405 NL80211_CMD_GET_PROTOCOL_FEATURES);
11406 if (!hdr)
11407 goto nla_put_failure;
11408
11409 if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
11410 NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
11411 goto nla_put_failure;
11412
11413 genlmsg_end(msg, hdr);
11414 return genlmsg_reply(msg, info);
11415
11416 nla_put_failure:
11417 kfree_skb(msg);
11418 return -ENOBUFS;
11419}
11420
Jouni Malinen355199e2013-02-27 17:14:27 +020011421static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
11422{
11423 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11424 struct cfg80211_update_ft_ies_params ft_params;
11425 struct net_device *dev = info->user_ptr[1];
11426
11427 if (!rdev->ops->update_ft_ies)
11428 return -EOPNOTSUPP;
11429
11430 if (!info->attrs[NL80211_ATTR_MDID] ||
11431 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
11432 return -EINVAL;
11433
11434 memset(&ft_params, 0, sizeof(ft_params));
11435 ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
11436 ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
11437 ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
11438
11439 return rdev_update_ft_ies(rdev, dev, &ft_params);
11440}
11441
Arend van Spriel5de17982013-04-18 15:49:00 +020011442static int nl80211_crit_protocol_start(struct sk_buff *skb,
11443 struct genl_info *info)
11444{
11445 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11446 struct wireless_dev *wdev = info->user_ptr[1];
11447 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
11448 u16 duration;
11449 int ret;
11450
11451 if (!rdev->ops->crit_proto_start)
11452 return -EOPNOTSUPP;
11453
11454 if (WARN_ON(!rdev->ops->crit_proto_stop))
11455 return -EINVAL;
11456
11457 if (rdev->crit_proto_nlportid)
11458 return -EBUSY;
11459
11460 /* determine protocol if provided */
11461 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
11462 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
11463
11464 if (proto >= NUM_NL80211_CRIT_PROTO)
11465 return -EINVAL;
11466
11467 /* timeout must be provided */
11468 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
11469 return -EINVAL;
11470
11471 duration =
11472 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
11473
11474 if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
11475 return -ERANGE;
11476
11477 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
11478 if (!ret)
11479 rdev->crit_proto_nlportid = info->snd_portid;
11480
11481 return ret;
11482}
11483
11484static int nl80211_crit_protocol_stop(struct sk_buff *skb,
11485 struct genl_info *info)
11486{
11487 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11488 struct wireless_dev *wdev = info->user_ptr[1];
11489
11490 if (!rdev->ops->crit_proto_stop)
11491 return -EOPNOTSUPP;
11492
11493 if (rdev->crit_proto_nlportid) {
11494 rdev->crit_proto_nlportid = 0;
11495 rdev_crit_proto_stop(rdev, wdev);
11496 }
11497 return 0;
11498}
11499
Johannes Bergad7e7182013-11-13 13:37:47 +010011500static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
11501{
11502 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11503 struct wireless_dev *wdev =
11504 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
11505 int i, err;
11506 u32 vid, subcmd;
11507
11508 if (!rdev->wiphy.vendor_commands)
11509 return -EOPNOTSUPP;
11510
11511 if (IS_ERR(wdev)) {
11512 err = PTR_ERR(wdev);
11513 if (err != -EINVAL)
11514 return err;
11515 wdev = NULL;
11516 } else if (wdev->wiphy != &rdev->wiphy) {
11517 return -EINVAL;
11518 }
11519
11520 if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
11521 !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
11522 return -EINVAL;
11523
11524 vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
11525 subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
11526 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
11527 const struct wiphy_vendor_command *vcmd;
11528 void *data = NULL;
11529 int len = 0;
11530
11531 vcmd = &rdev->wiphy.vendor_commands[i];
11532
11533 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11534 continue;
11535
11536 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11537 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
11538 if (!wdev)
11539 return -EINVAL;
11540 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
11541 !wdev->netdev)
11542 return -EINVAL;
11543
11544 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
11545 if (wdev->netdev &&
11546 !netif_running(wdev->netdev))
11547 return -ENETDOWN;
11548 if (!wdev->netdev && !wdev->p2p_started)
11549 return -ENETDOWN;
11550 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030011551
11552 if (!vcmd->doit)
11553 return -EOPNOTSUPP;
Johannes Bergad7e7182013-11-13 13:37:47 +010011554 } else {
11555 wdev = NULL;
11556 }
11557
11558 if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
11559 data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11560 len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11561 }
11562
11563 rdev->cur_cmd_info = info;
11564 err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
11565 data, len);
11566 rdev->cur_cmd_info = NULL;
11567 return err;
11568 }
11569
11570 return -EOPNOTSUPP;
11571}
11572
Johannes Berg7bdbe402015-08-15 22:39:49 +030011573static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
11574 struct netlink_callback *cb,
11575 struct cfg80211_registered_device **rdev,
11576 struct wireless_dev **wdev)
11577{
11578 u32 vid, subcmd;
11579 unsigned int i;
11580 int vcmd_idx = -1;
11581 int err;
11582 void *data = NULL;
11583 unsigned int data_len = 0;
11584
Johannes Berg7bdbe402015-08-15 22:39:49 +030011585 if (cb->args[0]) {
11586 /* subtract the 1 again here */
11587 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
11588 struct wireless_dev *tmp;
11589
Johannes Berg56769e72017-03-15 14:26:04 +010011590 if (!wiphy)
11591 return -ENODEV;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011592 *rdev = wiphy_to_rdev(wiphy);
11593 *wdev = NULL;
11594
11595 if (cb->args[1]) {
Johannes Berg53873f12016-05-03 16:52:04 +030011596 list_for_each_entry(tmp, &wiphy->wdev_list, list) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011597 if (tmp->identifier == cb->args[1] - 1) {
11598 *wdev = tmp;
11599 break;
11600 }
11601 }
11602 }
11603
11604 /* keep rtnl locked in successful case */
11605 return 0;
11606 }
11607
11608 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
11609 nl80211_fam.attrbuf, nl80211_fam.maxattr,
11610 nl80211_policy);
11611 if (err)
Johannes Berg56769e72017-03-15 14:26:04 +010011612 return err;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011613
11614 if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] ||
Johannes Berg56769e72017-03-15 14:26:04 +010011615 !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
11616 return -EINVAL;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011617
11618 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
11619 nl80211_fam.attrbuf);
11620 if (IS_ERR(*wdev))
11621 *wdev = NULL;
11622
11623 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
11624 nl80211_fam.attrbuf);
Johannes Berg56769e72017-03-15 14:26:04 +010011625 if (IS_ERR(*rdev))
11626 return PTR_ERR(*rdev);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011627
11628 vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]);
11629 subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
11630
11631 for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
11632 const struct wiphy_vendor_command *vcmd;
11633
11634 vcmd = &(*rdev)->wiphy.vendor_commands[i];
11635
11636 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11637 continue;
11638
Johannes Berg56769e72017-03-15 14:26:04 +010011639 if (!vcmd->dumpit)
11640 return -EOPNOTSUPP;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011641
11642 vcmd_idx = i;
11643 break;
11644 }
11645
Johannes Berg56769e72017-03-15 14:26:04 +010011646 if (vcmd_idx < 0)
11647 return -EOPNOTSUPP;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011648
11649 if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) {
11650 data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
11651 data_len = nla_len(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
11652 }
11653
11654 /* 0 is the first index - add 1 to parse only once */
11655 cb->args[0] = (*rdev)->wiphy_idx + 1;
11656 /* add 1 to know if it was NULL */
11657 cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
11658 cb->args[2] = vcmd_idx;
11659 cb->args[3] = (unsigned long)data;
11660 cb->args[4] = data_len;
11661
11662 /* keep rtnl locked in successful case */
11663 return 0;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011664}
11665
11666static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
11667 struct netlink_callback *cb)
11668{
11669 struct cfg80211_registered_device *rdev;
11670 struct wireless_dev *wdev;
11671 unsigned int vcmd_idx;
11672 const struct wiphy_vendor_command *vcmd;
11673 void *data;
11674 int data_len;
11675 int err;
11676 struct nlattr *vendor_data;
11677
Johannes Berg56769e72017-03-15 14:26:04 +010011678 rtnl_lock();
Johannes Berg7bdbe402015-08-15 22:39:49 +030011679 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
11680 if (err)
Johannes Berg56769e72017-03-15 14:26:04 +010011681 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011682
11683 vcmd_idx = cb->args[2];
11684 data = (void *)cb->args[3];
11685 data_len = cb->args[4];
11686 vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
11687
11688 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11689 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
Johannes Berg56769e72017-03-15 14:26:04 +010011690 if (!wdev) {
11691 err = -EINVAL;
11692 goto out;
11693 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030011694 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
Johannes Berg56769e72017-03-15 14:26:04 +010011695 !wdev->netdev) {
11696 err = -EINVAL;
11697 goto out;
11698 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030011699
11700 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
11701 if (wdev->netdev &&
Johannes Berg56769e72017-03-15 14:26:04 +010011702 !netif_running(wdev->netdev)) {
11703 err = -ENETDOWN;
11704 goto out;
11705 }
11706 if (!wdev->netdev && !wdev->p2p_started) {
11707 err = -ENETDOWN;
11708 goto out;
11709 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030011710 }
11711 }
11712
11713 while (1) {
11714 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
11715 cb->nlh->nlmsg_seq, NLM_F_MULTI,
11716 NL80211_CMD_VENDOR);
11717 if (!hdr)
11718 break;
11719
11720 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020011721 (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
11722 wdev_id(wdev),
11723 NL80211_ATTR_PAD))) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011724 genlmsg_cancel(skb, hdr);
11725 break;
11726 }
11727
11728 vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
11729 if (!vendor_data) {
11730 genlmsg_cancel(skb, hdr);
11731 break;
11732 }
11733
11734 err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
11735 (unsigned long *)&cb->args[5]);
11736 nla_nest_end(skb, vendor_data);
11737
11738 if (err == -ENOBUFS || err == -ENOENT) {
11739 genlmsg_cancel(skb, hdr);
11740 break;
11741 } else if (err) {
11742 genlmsg_cancel(skb, hdr);
11743 goto out;
11744 }
11745
11746 genlmsg_end(skb, hdr);
11747 }
11748
11749 err = skb->len;
11750 out:
11751 rtnl_unlock();
11752 return err;
11753}
11754
Johannes Bergad7e7182013-11-13 13:37:47 +010011755struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
11756 enum nl80211_commands cmd,
11757 enum nl80211_attrs attr,
11758 int approxlen)
11759{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080011760 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Bergad7e7182013-11-13 13:37:47 +010011761
11762 if (WARN_ON(!rdev->cur_cmd_info))
11763 return NULL;
11764
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020011765 return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
Johannes Bergad7e7182013-11-13 13:37:47 +010011766 rdev->cur_cmd_info->snd_portid,
11767 rdev->cur_cmd_info->snd_seq,
Johannes Berg567ffc32013-12-18 14:43:31 +010011768 cmd, attr, NULL, GFP_KERNEL);
Johannes Bergad7e7182013-11-13 13:37:47 +010011769}
11770EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
11771
11772int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
11773{
11774 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
11775 void *hdr = ((void **)skb->cb)[1];
11776 struct nlattr *data = ((void **)skb->cb)[2];
11777
Johannes Bergbd8c78e2014-07-30 14:55:26 +020011778 /* clear CB data for netlink core to own from now on */
11779 memset(skb->cb, 0, sizeof(skb->cb));
11780
Johannes Bergad7e7182013-11-13 13:37:47 +010011781 if (WARN_ON(!rdev->cur_cmd_info)) {
11782 kfree_skb(skb);
11783 return -EINVAL;
11784 }
11785
11786 nla_nest_end(skb, data);
11787 genlmsg_end(skb, hdr);
11788 return genlmsg_reply(skb, rdev->cur_cmd_info);
11789}
11790EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
11791
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080011792static int nl80211_set_qos_map(struct sk_buff *skb,
11793 struct genl_info *info)
11794{
11795 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11796 struct cfg80211_qos_map *qos_map = NULL;
11797 struct net_device *dev = info->user_ptr[1];
11798 u8 *pos, len, num_des, des_len, des;
11799 int ret;
11800
11801 if (!rdev->ops->set_qos_map)
11802 return -EOPNOTSUPP;
11803
11804 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
11805 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
11806 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
11807
11808 if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
11809 len > IEEE80211_QOS_MAP_LEN_MAX)
11810 return -EINVAL;
11811
11812 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
11813 if (!qos_map)
11814 return -ENOMEM;
11815
11816 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
11817 if (num_des) {
11818 des_len = num_des *
11819 sizeof(struct cfg80211_dscp_exception);
11820 memcpy(qos_map->dscp_exception, pos, des_len);
11821 qos_map->num_des = num_des;
11822 for (des = 0; des < num_des; des++) {
11823 if (qos_map->dscp_exception[des].up > 7) {
11824 kfree(qos_map);
11825 return -EINVAL;
11826 }
11827 }
11828 pos += des_len;
11829 }
11830 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
11831 }
11832
11833 wdev_lock(dev->ieee80211_ptr);
11834 ret = nl80211_key_allowed(dev->ieee80211_ptr);
11835 if (!ret)
11836 ret = rdev_set_qos_map(rdev, dev, qos_map);
11837 wdev_unlock(dev->ieee80211_ptr);
11838
11839 kfree(qos_map);
11840 return ret;
11841}
11842
Johannes Berg960d01a2014-09-09 22:55:35 +030011843static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
11844{
11845 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11846 struct net_device *dev = info->user_ptr[1];
11847 struct wireless_dev *wdev = dev->ieee80211_ptr;
11848 const u8 *peer;
11849 u8 tsid, up;
11850 u16 admitted_time = 0;
11851 int err;
11852
Johannes Berg723e73a2014-10-22 09:25:06 +020011853 if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
Johannes Berg960d01a2014-09-09 22:55:35 +030011854 return -EOPNOTSUPP;
11855
11856 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
11857 !info->attrs[NL80211_ATTR_USER_PRIO])
11858 return -EINVAL;
11859
11860 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
11861 if (tsid >= IEEE80211_NUM_TIDS)
11862 return -EINVAL;
11863
11864 up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
11865 if (up >= IEEE80211_NUM_UPS)
11866 return -EINVAL;
11867
11868 /* WMM uses TIDs 0-7 even for TSPEC */
Johannes Berg723e73a2014-10-22 09:25:06 +020011869 if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
Johannes Berg960d01a2014-09-09 22:55:35 +030011870 /* TODO: handle 802.11 TSPEC/admission control
Johannes Berg723e73a2014-10-22 09:25:06 +020011871 * need more attributes for that (e.g. BA session requirement);
11872 * change the WMM adminssion test above to allow both then
Johannes Berg960d01a2014-09-09 22:55:35 +030011873 */
11874 return -EINVAL;
11875 }
11876
11877 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
11878
11879 if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
11880 admitted_time =
11881 nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
11882 if (!admitted_time)
11883 return -EINVAL;
11884 }
11885
11886 wdev_lock(wdev);
11887 switch (wdev->iftype) {
11888 case NL80211_IFTYPE_STATION:
11889 case NL80211_IFTYPE_P2P_CLIENT:
11890 if (wdev->current_bss)
11891 break;
11892 err = -ENOTCONN;
11893 goto out;
11894 default:
11895 err = -EOPNOTSUPP;
11896 goto out;
11897 }
11898
11899 err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
11900
11901 out:
11902 wdev_unlock(wdev);
11903 return err;
11904}
11905
11906static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
11907{
11908 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11909 struct net_device *dev = info->user_ptr[1];
11910 struct wireless_dev *wdev = dev->ieee80211_ptr;
11911 const u8 *peer;
11912 u8 tsid;
11913 int err;
11914
11915 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
11916 return -EINVAL;
11917
11918 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
11919 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
11920
11921 wdev_lock(wdev);
11922 err = rdev_del_tx_ts(rdev, dev, tsid, peer);
11923 wdev_unlock(wdev);
11924
11925 return err;
11926}
11927
Arik Nemtsov1057d352014-11-19 12:54:26 +020011928static int nl80211_tdls_channel_switch(struct sk_buff *skb,
11929 struct genl_info *info)
11930{
11931 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11932 struct net_device *dev = info->user_ptr[1];
11933 struct wireless_dev *wdev = dev->ieee80211_ptr;
11934 struct cfg80211_chan_def chandef = {};
11935 const u8 *addr;
11936 u8 oper_class;
11937 int err;
11938
11939 if (!rdev->ops->tdls_channel_switch ||
11940 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
11941 return -EOPNOTSUPP;
11942
11943 switch (dev->ieee80211_ptr->iftype) {
11944 case NL80211_IFTYPE_STATION:
11945 case NL80211_IFTYPE_P2P_CLIENT:
11946 break;
11947 default:
11948 return -EOPNOTSUPP;
11949 }
11950
11951 if (!info->attrs[NL80211_ATTR_MAC] ||
11952 !info->attrs[NL80211_ATTR_OPER_CLASS])
11953 return -EINVAL;
11954
11955 err = nl80211_parse_chandef(rdev, info, &chandef);
11956 if (err)
11957 return err;
11958
11959 /*
11960 * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
11961 * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
11962 * specification is not defined for them.
11963 */
Johannes Berg57fbcce2016-04-12 15:56:15 +020011964 if (chandef.chan->band == NL80211_BAND_2GHZ &&
Arik Nemtsov1057d352014-11-19 12:54:26 +020011965 chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
11966 chandef.width != NL80211_CHAN_WIDTH_20)
11967 return -EINVAL;
11968
11969 /* we will be active on the TDLS link */
Arik Nemtsov923b3522015-07-08 15:41:44 +030011970 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
11971 wdev->iftype))
Arik Nemtsov1057d352014-11-19 12:54:26 +020011972 return -EINVAL;
11973
11974 /* don't allow switching to DFS channels */
11975 if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
11976 return -EINVAL;
11977
11978 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
11979 oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
11980
11981 wdev_lock(wdev);
11982 err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
11983 wdev_unlock(wdev);
11984
11985 return err;
11986}
11987
11988static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
11989 struct genl_info *info)
11990{
11991 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11992 struct net_device *dev = info->user_ptr[1];
11993 struct wireless_dev *wdev = dev->ieee80211_ptr;
11994 const u8 *addr;
11995
11996 if (!rdev->ops->tdls_channel_switch ||
11997 !rdev->ops->tdls_cancel_channel_switch ||
11998 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
11999 return -EOPNOTSUPP;
12000
12001 switch (dev->ieee80211_ptr->iftype) {
12002 case NL80211_IFTYPE_STATION:
12003 case NL80211_IFTYPE_P2P_CLIENT:
12004 break;
12005 default:
12006 return -EOPNOTSUPP;
12007 }
12008
12009 if (!info->attrs[NL80211_ATTR_MAC])
12010 return -EINVAL;
12011
12012 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12013
12014 wdev_lock(wdev);
12015 rdev_tdls_cancel_channel_switch(rdev, dev, addr);
12016 wdev_unlock(wdev);
12017
12018 return 0;
12019}
12020
Michael Braund757efc2016-10-10 19:12:22 +020012021static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
12022 struct genl_info *info)
12023{
12024 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12025 struct net_device *dev = info->user_ptr[1];
12026 struct wireless_dev *wdev = dev->ieee80211_ptr;
12027 const struct nlattr *nla;
12028 bool enabled;
12029
12030 if (netif_running(dev))
12031 return -EBUSY;
12032
12033 if (!rdev->ops->set_multicast_to_unicast)
12034 return -EOPNOTSUPP;
12035
12036 if (wdev->iftype != NL80211_IFTYPE_AP &&
12037 wdev->iftype != NL80211_IFTYPE_P2P_GO)
12038 return -EOPNOTSUPP;
12039
12040 nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
12041 enabled = nla_get_flag(nla);
12042
12043 return rdev_set_multicast_to_unicast(rdev, dev, enabled);
12044}
12045
Johannes Berg4c476992010-10-04 21:36:35 +020012046#define NL80211_FLAG_NEED_WIPHY 0x01
12047#define NL80211_FLAG_NEED_NETDEV 0x02
12048#define NL80211_FLAG_NEED_RTNL 0x04
Johannes Berg41265712010-10-04 21:14:05 +020012049#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
12050#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
12051 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg1bf614e2012-06-15 15:23:36 +020012052#define NL80211_FLAG_NEED_WDEV 0x10
Johannes Berg98104fde2012-06-16 00:19:54 +020012053/* If a netdev is associated, it must be UP, P2P must be started */
Johannes Berg1bf614e2012-06-15 15:23:36 +020012054#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
12055 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg5393b912014-09-10 15:00:16 +030012056#define NL80211_FLAG_CLEAR_SKB 0x20
Johannes Berg4c476992010-10-04 21:36:35 +020012057
Johannes Bergf84f7712013-11-14 17:14:45 +010012058static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012059 struct genl_info *info)
12060{
12061 struct cfg80211_registered_device *rdev;
Johannes Berg89a54e42012-06-15 14:33:17 +020012062 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012063 struct net_device *dev;
Johannes Berg4c476992010-10-04 21:36:35 +020012064 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
12065
12066 if (rtnl)
12067 rtnl_lock();
12068
12069 if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
Johannes Berg4f7eff12012-06-15 14:14:22 +020012070 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
Johannes Berg4c476992010-10-04 21:36:35 +020012071 if (IS_ERR(rdev)) {
12072 if (rtnl)
12073 rtnl_unlock();
12074 return PTR_ERR(rdev);
12075 }
12076 info->user_ptr[0] = rdev;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012077 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
12078 ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020012079 ASSERT_RTNL();
12080
Johannes Berg89a54e42012-06-15 14:33:17 +020012081 wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
12082 info->attrs);
12083 if (IS_ERR(wdev)) {
Johannes Berg4c476992010-10-04 21:36:35 +020012084 if (rtnl)
12085 rtnl_unlock();
Johannes Berg89a54e42012-06-15 14:33:17 +020012086 return PTR_ERR(wdev);
Johannes Berg4c476992010-10-04 21:36:35 +020012087 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012088
Johannes Berg89a54e42012-06-15 14:33:17 +020012089 dev = wdev->netdev;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080012090 rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg89a54e42012-06-15 14:33:17 +020012091
Johannes Berg1bf614e2012-06-15 15:23:36 +020012092 if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
12093 if (!dev) {
Johannes Berg1bf614e2012-06-15 15:23:36 +020012094 if (rtnl)
12095 rtnl_unlock();
12096 return -EINVAL;
12097 }
12098
12099 info->user_ptr[1] = dev;
12100 } else {
12101 info->user_ptr[1] = wdev;
Johannes Berg41265712010-10-04 21:14:05 +020012102 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012103
Johannes Berg1bf614e2012-06-15 15:23:36 +020012104 if (dev) {
12105 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
12106 !netif_running(dev)) {
Johannes Berg1bf614e2012-06-15 15:23:36 +020012107 if (rtnl)
12108 rtnl_unlock();
12109 return -ENETDOWN;
12110 }
12111
12112 dev_hold(dev);
Johannes Berg98104fde2012-06-16 00:19:54 +020012113 } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012114 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
12115 !wdev->p2p_started) {
12116 if (rtnl)
12117 rtnl_unlock();
12118 return -ENETDOWN;
12119 }
12120 if (wdev->iftype == NL80211_IFTYPE_NAN &&
12121 !wdev->nan_started) {
Johannes Berg98104fde2012-06-16 00:19:54 +020012122 if (rtnl)
12123 rtnl_unlock();
12124 return -ENETDOWN;
12125 }
Johannes Berg1bf614e2012-06-15 15:23:36 +020012126 }
12127
Johannes Berg4c476992010-10-04 21:36:35 +020012128 info->user_ptr[0] = rdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012129 }
12130
12131 return 0;
12132}
12133
Johannes Bergf84f7712013-11-14 17:14:45 +010012134static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012135 struct genl_info *info)
12136{
Johannes Berg1bf614e2012-06-15 15:23:36 +020012137 if (info->user_ptr[1]) {
12138 if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
12139 struct wireless_dev *wdev = info->user_ptr[1];
12140
12141 if (wdev->netdev)
12142 dev_put(wdev->netdev);
12143 } else {
12144 dev_put(info->user_ptr[1]);
12145 }
12146 }
Johannes Berg5393b912014-09-10 15:00:16 +030012147
Johannes Berg4c476992010-10-04 21:36:35 +020012148 if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
12149 rtnl_unlock();
Johannes Berg5393b912014-09-10 15:00:16 +030012150
12151 /* If needed, clear the netlink message payload from the SKB
12152 * as it might contain key data that shouldn't stick around on
12153 * the heap after the SKB is freed. The netlink message header
12154 * is still needed for further processing, so leave it intact.
12155 */
12156 if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
12157 struct nlmsghdr *nlh = nlmsg_hdr(skb);
12158
12159 memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
12160 }
Johannes Berg4c476992010-10-04 21:36:35 +020012161}
12162
Johannes Berg4534de82013-11-14 17:14:46 +010012163static const struct genl_ops nl80211_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040012164 {
12165 .cmd = NL80211_CMD_GET_WIPHY,
12166 .doit = nl80211_get_wiphy,
12167 .dumpit = nl80211_dump_wiphy,
Johannes Berg86e8cf92013-06-19 10:57:22 +020012168 .done = nl80211_dump_wiphy_done,
Johannes Berg55682962007-09-20 13:09:35 -040012169 .policy = nl80211_policy,
12170 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012171 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12172 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012173 },
12174 {
12175 .cmd = NL80211_CMD_SET_WIPHY,
12176 .doit = nl80211_set_wiphy,
12177 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012178 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012179 .internal_flags = NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012180 },
12181 {
12182 .cmd = NL80211_CMD_GET_INTERFACE,
12183 .doit = nl80211_get_interface,
12184 .dumpit = nl80211_dump_interface,
12185 .policy = nl80211_policy,
12186 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012187 .internal_flags = NL80211_FLAG_NEED_WDEV |
12188 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012189 },
12190 {
12191 .cmd = NL80211_CMD_SET_INTERFACE,
12192 .doit = nl80211_set_interface,
12193 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012194 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012195 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12196 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012197 },
12198 {
12199 .cmd = NL80211_CMD_NEW_INTERFACE,
12200 .doit = nl80211_new_interface,
12201 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012202 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012203 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12204 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012205 },
12206 {
12207 .cmd = NL80211_CMD_DEL_INTERFACE,
12208 .doit = nl80211_del_interface,
12209 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012210 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg84efbb82012-06-16 00:00:26 +020012211 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012212 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012213 },
Johannes Berg41ade002007-12-19 02:03:29 +010012214 {
12215 .cmd = NL80211_CMD_GET_KEY,
12216 .doit = nl80211_get_key,
12217 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012218 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012219 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012220 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012221 },
12222 {
12223 .cmd = NL80211_CMD_SET_KEY,
12224 .doit = nl80211_set_key,
12225 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012226 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012227 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012228 NL80211_FLAG_NEED_RTNL |
12229 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012230 },
12231 {
12232 .cmd = NL80211_CMD_NEW_KEY,
12233 .doit = nl80211_new_key,
12234 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012235 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012236 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012237 NL80211_FLAG_NEED_RTNL |
12238 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012239 },
12240 {
12241 .cmd = NL80211_CMD_DEL_KEY,
12242 .doit = nl80211_del_key,
12243 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012244 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012245 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012246 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012247 },
Johannes Berged1b6cc2007-12-19 02:03:32 +010012248 {
12249 .cmd = NL80211_CMD_SET_BEACON,
12250 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012251 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012252 .doit = nl80211_set_beacon,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012253 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012254 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012255 },
12256 {
Johannes Berg88600202012-02-13 15:17:18 +010012257 .cmd = NL80211_CMD_START_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012258 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012259 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012260 .doit = nl80211_start_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012261 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012262 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012263 },
12264 {
Johannes Berg88600202012-02-13 15:17:18 +010012265 .cmd = NL80211_CMD_STOP_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012266 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012267 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012268 .doit = nl80211_stop_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012269 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012270 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012271 },
Johannes Berg5727ef12007-12-19 02:03:34 +010012272 {
12273 .cmd = NL80211_CMD_GET_STATION,
12274 .doit = nl80211_get_station,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012275 .dumpit = nl80211_dump_station,
Johannes Berg5727ef12007-12-19 02:03:34 +010012276 .policy = nl80211_policy,
Johannes Berg4c476992010-10-04 21:36:35 +020012277 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12278 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012279 },
12280 {
12281 .cmd = NL80211_CMD_SET_STATION,
12282 .doit = nl80211_set_station,
12283 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012284 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012285 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012286 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012287 },
12288 {
12289 .cmd = NL80211_CMD_NEW_STATION,
12290 .doit = nl80211_new_station,
12291 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012292 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012293 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012294 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012295 },
12296 {
12297 .cmd = NL80211_CMD_DEL_STATION,
12298 .doit = nl80211_del_station,
12299 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012300 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012301 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012302 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012303 },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012304 {
12305 .cmd = NL80211_CMD_GET_MPATH,
12306 .doit = nl80211_get_mpath,
12307 .dumpit = nl80211_dump_mpath,
12308 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012309 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012310 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012311 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012312 },
12313 {
Henning Rogge66be7d22014-09-12 08:58:49 +020012314 .cmd = NL80211_CMD_GET_MPP,
12315 .doit = nl80211_get_mpp,
12316 .dumpit = nl80211_dump_mpp,
12317 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012318 .flags = GENL_UNS_ADMIN_PERM,
Henning Rogge66be7d22014-09-12 08:58:49 +020012319 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12320 NL80211_FLAG_NEED_RTNL,
12321 },
12322 {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012323 .cmd = NL80211_CMD_SET_MPATH,
12324 .doit = nl80211_set_mpath,
12325 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012326 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012327 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012328 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012329 },
12330 {
12331 .cmd = NL80211_CMD_NEW_MPATH,
12332 .doit = nl80211_new_mpath,
12333 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012334 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012335 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012336 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012337 },
12338 {
12339 .cmd = NL80211_CMD_DEL_MPATH,
12340 .doit = nl80211_del_mpath,
12341 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012342 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012343 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012344 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012345 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012346 {
12347 .cmd = NL80211_CMD_SET_BSS,
12348 .doit = nl80211_set_bss,
12349 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012350 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012351 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012352 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012353 },
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012354 {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012355 .cmd = NL80211_CMD_GET_REG,
Arik Nemtsovad30ca22014-12-15 19:25:59 +020012356 .doit = nl80211_get_reg_do,
12357 .dumpit = nl80211_get_reg_dump,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012358 .policy = nl80211_policy,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012359 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012360 /* can be retrieved by unprivileged users */
12361 },
Johannes Bergb6863032015-10-15 09:25:18 +020012362#ifdef CONFIG_CFG80211_CRDA_SUPPORT
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012363 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012364 .cmd = NL80211_CMD_SET_REG,
12365 .doit = nl80211_set_reg,
12366 .policy = nl80211_policy,
12367 .flags = GENL_ADMIN_PERM,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012368 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012369 },
Johannes Bergb6863032015-10-15 09:25:18 +020012370#endif
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012371 {
12372 .cmd = NL80211_CMD_REQ_SET_REG,
12373 .doit = nl80211_req_set_reg,
12374 .policy = nl80211_policy,
12375 .flags = GENL_ADMIN_PERM,
12376 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012377 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012378 .cmd = NL80211_CMD_GET_MESH_CONFIG,
12379 .doit = nl80211_get_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012380 .policy = nl80211_policy,
12381 /* can be retrieved by unprivileged users */
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012382 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012383 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012384 },
12385 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012386 .cmd = NL80211_CMD_SET_MESH_CONFIG,
12387 .doit = nl80211_update_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012388 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012389 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012390 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012391 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012392 },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +020012393 {
Johannes Berg2a519312009-02-10 21:25:55 +010012394 .cmd = NL80211_CMD_TRIGGER_SCAN,
12395 .doit = nl80211_trigger_scan,
12396 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012397 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergfd014282012-06-18 19:17:03 +020012398 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012399 NL80211_FLAG_NEED_RTNL,
Johannes Berg2a519312009-02-10 21:25:55 +010012400 },
12401 {
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012402 .cmd = NL80211_CMD_ABORT_SCAN,
12403 .doit = nl80211_abort_scan,
12404 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012405 .flags = GENL_UNS_ADMIN_PERM,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012406 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12407 NL80211_FLAG_NEED_RTNL,
12408 },
12409 {
Johannes Berg2a519312009-02-10 21:25:55 +010012410 .cmd = NL80211_CMD_GET_SCAN,
12411 .policy = nl80211_policy,
12412 .dumpit = nl80211_dump_scan,
12413 },
Jouni Malinen636a5d32009-03-19 13:39:22 +020012414 {
Luciano Coelho807f8a82011-05-11 17:09:35 +030012415 .cmd = NL80211_CMD_START_SCHED_SCAN,
12416 .doit = nl80211_start_sched_scan,
12417 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012418 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012419 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12420 NL80211_FLAG_NEED_RTNL,
12421 },
12422 {
12423 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
12424 .doit = nl80211_stop_sched_scan,
12425 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012426 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012427 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12428 NL80211_FLAG_NEED_RTNL,
12429 },
12430 {
Jouni Malinen636a5d32009-03-19 13:39:22 +020012431 .cmd = NL80211_CMD_AUTHENTICATE,
12432 .doit = nl80211_authenticate,
12433 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012434 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012435 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012436 NL80211_FLAG_NEED_RTNL |
12437 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012438 },
12439 {
12440 .cmd = NL80211_CMD_ASSOCIATE,
12441 .doit = nl80211_associate,
12442 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012443 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012444 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012445 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012446 },
12447 {
12448 .cmd = NL80211_CMD_DEAUTHENTICATE,
12449 .doit = nl80211_deauthenticate,
12450 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012451 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012452 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012453 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012454 },
12455 {
12456 .cmd = NL80211_CMD_DISASSOCIATE,
12457 .doit = nl80211_disassociate,
12458 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012459 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012460 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012461 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012462 },
Johannes Berg04a773a2009-04-19 21:24:32 +020012463 {
12464 .cmd = NL80211_CMD_JOIN_IBSS,
12465 .doit = nl80211_join_ibss,
12466 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012467 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012468 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012469 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012470 },
12471 {
12472 .cmd = NL80211_CMD_LEAVE_IBSS,
12473 .doit = nl80211_leave_ibss,
12474 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012475 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012476 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012477 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012478 },
Johannes Bergaff89a92009-07-01 21:26:51 +020012479#ifdef CONFIG_NL80211_TESTMODE
12480 {
12481 .cmd = NL80211_CMD_TESTMODE,
12482 .doit = nl80211_testmode_do,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070012483 .dumpit = nl80211_testmode_dump,
Johannes Bergaff89a92009-07-01 21:26:51 +020012484 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012485 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012486 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12487 NL80211_FLAG_NEED_RTNL,
Johannes Bergaff89a92009-07-01 21:26:51 +020012488 },
12489#endif
Samuel Ortizb23aa672009-07-01 21:26:54 +020012490 {
12491 .cmd = NL80211_CMD_CONNECT,
12492 .doit = nl80211_connect,
12493 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012494 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012495 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012496 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012497 },
12498 {
vamsi krishna30da4e82016-10-27 16:51:11 +030012499 .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
12500 .doit = nl80211_update_connect_params,
12501 .policy = nl80211_policy,
12502 .flags = GENL_ADMIN_PERM,
12503 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12504 NL80211_FLAG_NEED_RTNL,
12505 },
12506 {
Samuel Ortizb23aa672009-07-01 21:26:54 +020012507 .cmd = NL80211_CMD_DISCONNECT,
12508 .doit = nl80211_disconnect,
12509 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012510 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012511 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012512 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012513 },
Johannes Berg463d0182009-07-14 00:33:35 +020012514 {
12515 .cmd = NL80211_CMD_SET_WIPHY_NETNS,
12516 .doit = nl80211_wiphy_netns,
12517 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012518 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012519 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12520 NL80211_FLAG_NEED_RTNL,
Johannes Berg463d0182009-07-14 00:33:35 +020012521 },
Holger Schurig61fa7132009-11-11 12:25:40 +010012522 {
12523 .cmd = NL80211_CMD_GET_SURVEY,
12524 .policy = nl80211_policy,
12525 .dumpit = nl80211_dump_survey,
12526 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012527 {
12528 .cmd = NL80211_CMD_SET_PMKSA,
12529 .doit = nl80211_setdel_pmksa,
12530 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012531 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012532 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012533 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012534 },
12535 {
12536 .cmd = NL80211_CMD_DEL_PMKSA,
12537 .doit = nl80211_setdel_pmksa,
12538 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012539 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012540 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012541 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012542 },
12543 {
12544 .cmd = NL80211_CMD_FLUSH_PMKSA,
12545 .doit = nl80211_flush_pmksa,
12546 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012547 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012548 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012549 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012550 },
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012551 {
12552 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
12553 .doit = nl80211_remain_on_channel,
12554 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012555 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012556 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012557 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012558 },
12559 {
12560 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
12561 .doit = nl80211_cancel_remain_on_channel,
12562 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012563 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012564 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012565 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012566 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012567 {
12568 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
12569 .doit = nl80211_set_tx_bitrate_mask,
12570 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012571 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012572 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12573 NL80211_FLAG_NEED_RTNL,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012574 },
Jouni Malinen026331c2010-02-15 12:53:10 +020012575 {
Johannes Berg2e161f72010-08-12 15:38:38 +020012576 .cmd = NL80211_CMD_REGISTER_FRAME,
12577 .doit = nl80211_register_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012578 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012579 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012580 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012581 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012582 },
12583 {
Johannes Berg2e161f72010-08-12 15:38:38 +020012584 .cmd = NL80211_CMD_FRAME,
12585 .doit = nl80211_tx_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012586 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012587 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012588 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012589 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012590 },
Kalle Valoffb9eb32010-02-17 17:58:10 +020012591 {
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012592 .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
12593 .doit = nl80211_tx_mgmt_cancel_wait,
12594 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012595 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012596 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012597 NL80211_FLAG_NEED_RTNL,
12598 },
12599 {
Kalle Valoffb9eb32010-02-17 17:58:10 +020012600 .cmd = NL80211_CMD_SET_POWER_SAVE,
12601 .doit = nl80211_set_power_save,
12602 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012603 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012604 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12605 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012606 },
12607 {
12608 .cmd = NL80211_CMD_GET_POWER_SAVE,
12609 .doit = nl80211_get_power_save,
12610 .policy = nl80211_policy,
12611 /* can be retrieved by unprivileged users */
Johannes Berg4c476992010-10-04 21:36:35 +020012612 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12613 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012614 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012615 {
12616 .cmd = NL80211_CMD_SET_CQM,
12617 .doit = nl80211_set_cqm,
12618 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012619 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012620 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12621 NL80211_FLAG_NEED_RTNL,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012622 },
Johannes Bergf444de02010-05-05 15:25:02 +020012623 {
12624 .cmd = NL80211_CMD_SET_CHANNEL,
12625 .doit = nl80211_set_channel,
12626 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012627 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012628 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12629 NL80211_FLAG_NEED_RTNL,
Johannes Bergf444de02010-05-05 15:25:02 +020012630 },
Bill Jordane8347eb2010-10-01 13:54:28 -040012631 {
12632 .cmd = NL80211_CMD_SET_WDS_PEER,
12633 .doit = nl80211_set_wds_peer,
12634 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012635 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg43b19952010-10-07 13:10:30 +020012636 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12637 NL80211_FLAG_NEED_RTNL,
Bill Jordane8347eb2010-10-01 13:54:28 -040012638 },
Johannes Berg29cbe682010-12-03 09:20:44 +010012639 {
12640 .cmd = NL80211_CMD_JOIN_MESH,
12641 .doit = nl80211_join_mesh,
12642 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012643 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012644 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12645 NL80211_FLAG_NEED_RTNL,
12646 },
12647 {
12648 .cmd = NL80211_CMD_LEAVE_MESH,
12649 .doit = nl80211_leave_mesh,
12650 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012651 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012652 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12653 NL80211_FLAG_NEED_RTNL,
12654 },
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012655 {
12656 .cmd = NL80211_CMD_JOIN_OCB,
12657 .doit = nl80211_join_ocb,
12658 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012659 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012660 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12661 NL80211_FLAG_NEED_RTNL,
12662 },
12663 {
12664 .cmd = NL80211_CMD_LEAVE_OCB,
12665 .doit = nl80211_leave_ocb,
12666 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012667 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012668 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12669 NL80211_FLAG_NEED_RTNL,
12670 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020012671#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +020012672 {
12673 .cmd = NL80211_CMD_GET_WOWLAN,
12674 .doit = nl80211_get_wowlan,
12675 .policy = nl80211_policy,
12676 /* can be retrieved by unprivileged users */
12677 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12678 NL80211_FLAG_NEED_RTNL,
12679 },
12680 {
12681 .cmd = NL80211_CMD_SET_WOWLAN,
12682 .doit = nl80211_set_wowlan,
12683 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012684 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergff1b6e62011-05-04 15:37:28 +020012685 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12686 NL80211_FLAG_NEED_RTNL,
12687 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020012688#endif
Johannes Berge5497d72011-07-05 16:35:40 +020012689 {
12690 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
12691 .doit = nl80211_set_rekey_data,
12692 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012693 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berge5497d72011-07-05 16:35:40 +020012694 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012695 NL80211_FLAG_NEED_RTNL |
12696 NL80211_FLAG_CLEAR_SKB,
Johannes Berge5497d72011-07-05 16:35:40 +020012697 },
Arik Nemtsov109086c2011-09-28 14:12:50 +030012698 {
12699 .cmd = NL80211_CMD_TDLS_MGMT,
12700 .doit = nl80211_tdls_mgmt,
12701 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012702 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030012703 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12704 NL80211_FLAG_NEED_RTNL,
12705 },
12706 {
12707 .cmd = NL80211_CMD_TDLS_OPER,
12708 .doit = nl80211_tdls_oper,
12709 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012710 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030012711 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12712 NL80211_FLAG_NEED_RTNL,
12713 },
Johannes Berg28946da2011-11-04 11:18:12 +010012714 {
12715 .cmd = NL80211_CMD_UNEXPECTED_FRAME,
12716 .doit = nl80211_register_unexpected_frame,
12717 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012718 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg28946da2011-11-04 11:18:12 +010012719 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12720 NL80211_FLAG_NEED_RTNL,
12721 },
Johannes Berg7f6cf312011-11-04 11:18:15 +010012722 {
12723 .cmd = NL80211_CMD_PROBE_CLIENT,
12724 .doit = nl80211_probe_client,
12725 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012726 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012727 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg7f6cf312011-11-04 11:18:15 +010012728 NL80211_FLAG_NEED_RTNL,
12729 },
Johannes Berg5e7602302011-11-04 11:18:17 +010012730 {
12731 .cmd = NL80211_CMD_REGISTER_BEACONS,
12732 .doit = nl80211_register_beacons,
12733 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012734 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg5e7602302011-11-04 11:18:17 +010012735 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12736 NL80211_FLAG_NEED_RTNL,
12737 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010012738 {
12739 .cmd = NL80211_CMD_SET_NOACK_MAP,
12740 .doit = nl80211_set_noack_map,
12741 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012742 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010012743 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12744 NL80211_FLAG_NEED_RTNL,
12745 },
Johannes Berg98104fde2012-06-16 00:19:54 +020012746 {
12747 .cmd = NL80211_CMD_START_P2P_DEVICE,
12748 .doit = nl80211_start_p2p_device,
12749 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012750 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020012751 .internal_flags = NL80211_FLAG_NEED_WDEV |
12752 NL80211_FLAG_NEED_RTNL,
12753 },
12754 {
12755 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
12756 .doit = nl80211_stop_p2p_device,
12757 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012758 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020012759 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12760 NL80211_FLAG_NEED_RTNL,
12761 },
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012762 {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012763 .cmd = NL80211_CMD_START_NAN,
12764 .doit = nl80211_start_nan,
12765 .policy = nl80211_policy,
12766 .flags = GENL_ADMIN_PERM,
12767 .internal_flags = NL80211_FLAG_NEED_WDEV |
12768 NL80211_FLAG_NEED_RTNL,
12769 },
12770 {
12771 .cmd = NL80211_CMD_STOP_NAN,
12772 .doit = nl80211_stop_nan,
12773 .policy = nl80211_policy,
12774 .flags = GENL_ADMIN_PERM,
12775 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12776 NL80211_FLAG_NEED_RTNL,
12777 },
12778 {
Ayala Bekera442b762016-09-20 17:31:15 +030012779 .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
12780 .doit = nl80211_nan_add_func,
12781 .policy = nl80211_policy,
12782 .flags = GENL_ADMIN_PERM,
12783 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12784 NL80211_FLAG_NEED_RTNL,
12785 },
12786 {
12787 .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
12788 .doit = nl80211_nan_del_func,
12789 .policy = nl80211_policy,
12790 .flags = GENL_ADMIN_PERM,
12791 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12792 NL80211_FLAG_NEED_RTNL,
12793 },
12794 {
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030012795 .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
12796 .doit = nl80211_nan_change_config,
12797 .policy = nl80211_policy,
12798 .flags = GENL_ADMIN_PERM,
12799 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12800 NL80211_FLAG_NEED_RTNL,
12801 },
12802 {
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012803 .cmd = NL80211_CMD_SET_MCAST_RATE,
12804 .doit = nl80211_set_mcast_rate,
12805 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012806 .flags = GENL_UNS_ADMIN_PERM,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012807 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12808 NL80211_FLAG_NEED_RTNL,
12809 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053012810 {
12811 .cmd = NL80211_CMD_SET_MAC_ACL,
12812 .doit = nl80211_set_mac_acl,
12813 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012814 .flags = GENL_UNS_ADMIN_PERM,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053012815 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12816 NL80211_FLAG_NEED_RTNL,
12817 },
Simon Wunderlich04f39042013-02-08 18:16:19 +010012818 {
12819 .cmd = NL80211_CMD_RADAR_DETECT,
12820 .doit = nl80211_start_radar_detection,
12821 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012822 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich04f39042013-02-08 18:16:19 +010012823 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12824 NL80211_FLAG_NEED_RTNL,
12825 },
Johannes Berg3713b4e2013-02-14 16:19:38 +010012826 {
12827 .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
12828 .doit = nl80211_get_protocol_features,
12829 .policy = nl80211_policy,
12830 },
Jouni Malinen355199e2013-02-27 17:14:27 +020012831 {
12832 .cmd = NL80211_CMD_UPDATE_FT_IES,
12833 .doit = nl80211_update_ft_ies,
12834 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012835 .flags = GENL_UNS_ADMIN_PERM,
Jouni Malinen355199e2013-02-27 17:14:27 +020012836 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12837 NL80211_FLAG_NEED_RTNL,
12838 },
Arend van Spriel5de17982013-04-18 15:49:00 +020012839 {
12840 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
12841 .doit = nl80211_crit_protocol_start,
12842 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012843 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020012844 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12845 NL80211_FLAG_NEED_RTNL,
12846 },
12847 {
12848 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
12849 .doit = nl80211_crit_protocol_stop,
12850 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012851 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020012852 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12853 NL80211_FLAG_NEED_RTNL,
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070012854 },
12855 {
12856 .cmd = NL80211_CMD_GET_COALESCE,
12857 .doit = nl80211_get_coalesce,
12858 .policy = nl80211_policy,
12859 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12860 NL80211_FLAG_NEED_RTNL,
12861 },
12862 {
12863 .cmd = NL80211_CMD_SET_COALESCE,
12864 .doit = nl80211_set_coalesce,
12865 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012866 .flags = GENL_UNS_ADMIN_PERM,
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070012867 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12868 NL80211_FLAG_NEED_RTNL,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020012869 },
12870 {
12871 .cmd = NL80211_CMD_CHANNEL_SWITCH,
12872 .doit = nl80211_channel_switch,
12873 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012874 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020012875 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12876 NL80211_FLAG_NEED_RTNL,
12877 },
Johannes Bergad7e7182013-11-13 13:37:47 +010012878 {
12879 .cmd = NL80211_CMD_VENDOR,
12880 .doit = nl80211_vendor_cmd,
Johannes Berg7bdbe402015-08-15 22:39:49 +030012881 .dumpit = nl80211_vendor_cmd_dump,
Johannes Bergad7e7182013-11-13 13:37:47 +010012882 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012883 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergad7e7182013-11-13 13:37:47 +010012884 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12885 NL80211_FLAG_NEED_RTNL,
12886 },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080012887 {
12888 .cmd = NL80211_CMD_SET_QOS_MAP,
12889 .doit = nl80211_set_qos_map,
12890 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012891 .flags = GENL_UNS_ADMIN_PERM,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080012892 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12893 NL80211_FLAG_NEED_RTNL,
12894 },
Johannes Berg960d01a2014-09-09 22:55:35 +030012895 {
12896 .cmd = NL80211_CMD_ADD_TX_TS,
12897 .doit = nl80211_add_tx_ts,
12898 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012899 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030012900 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12901 NL80211_FLAG_NEED_RTNL,
12902 },
12903 {
12904 .cmd = NL80211_CMD_DEL_TX_TS,
12905 .doit = nl80211_del_tx_ts,
12906 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012907 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030012908 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12909 NL80211_FLAG_NEED_RTNL,
12910 },
Arik Nemtsov1057d352014-11-19 12:54:26 +020012911 {
12912 .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
12913 .doit = nl80211_tdls_channel_switch,
12914 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012915 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020012916 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12917 NL80211_FLAG_NEED_RTNL,
12918 },
12919 {
12920 .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
12921 .doit = nl80211_tdls_cancel_channel_switch,
12922 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012923 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020012924 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12925 NL80211_FLAG_NEED_RTNL,
12926 },
Michael Braund757efc2016-10-10 19:12:22 +020012927 {
12928 .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
12929 .doit = nl80211_set_multicast_to_unicast,
12930 .policy = nl80211_policy,
12931 .flags = GENL_UNS_ADMIN_PERM,
12932 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12933 NL80211_FLAG_NEED_RTNL,
12934 },
Johannes Berg55682962007-09-20 13:09:35 -040012935};
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012936
Johannes Berg55682962007-09-20 13:09:35 -040012937/* notification functions */
12938
Johannes Berg3bb20552014-05-26 13:52:25 +020012939void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
12940 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -040012941{
12942 struct sk_buff *msg;
Johannes Berg86e8cf92013-06-19 10:57:22 +020012943 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -040012944
Johannes Berg3bb20552014-05-26 13:52:25 +020012945 WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
12946 cmd != NL80211_CMD_DEL_WIPHY);
12947
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070012948 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040012949 if (!msg)
12950 return;
12951
Johannes Berg3bb20552014-05-26 13:52:25 +020012952 if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
Johannes Berg55682962007-09-20 13:09:35 -040012953 nlmsg_free(msg);
12954 return;
12955 }
12956
Johannes Berg68eb5502013-11-19 15:19:38 +010012957 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010012958 NL80211_MCGRP_CONFIG, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040012959}
12960
Denis Kenzior896ff062016-08-03 16:58:33 -050012961void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
12962 struct wireless_dev *wdev,
12963 enum nl80211_commands cmd)
12964{
12965 struct sk_buff *msg;
12966
12967 WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
12968 cmd != NL80211_CMD_DEL_INTERFACE);
12969
12970 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12971 if (!msg)
12972 return;
12973
12974 if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
12975 cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
12976 nlmsg_free(msg);
12977 return;
12978 }
12979
12980 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
12981 NL80211_MCGRP_CONFIG, GFP_KERNEL);
12982}
12983
Johannes Berg362a4152009-05-24 16:43:15 +020012984static int nl80211_add_scan_req(struct sk_buff *msg,
12985 struct cfg80211_registered_device *rdev)
12986{
12987 struct cfg80211_scan_request *req = rdev->scan_req;
12988 struct nlattr *nest;
12989 int i;
12990
12991 if (WARN_ON(!req))
12992 return 0;
12993
12994 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
12995 if (!nest)
12996 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040012997 for (i = 0; i < req->n_ssids; i++) {
12998 if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
12999 goto nla_put_failure;
13000 }
Johannes Berg362a4152009-05-24 16:43:15 +020013001 nla_nest_end(msg, nest);
13002
13003 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
13004 if (!nest)
13005 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040013006 for (i = 0; i < req->n_channels; i++) {
13007 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
13008 goto nla_put_failure;
13009 }
Johannes Berg362a4152009-05-24 16:43:15 +020013010 nla_nest_end(msg, nest);
13011
David S. Miller9360ffd2012-03-29 04:41:26 -040013012 if (req->ie &&
13013 nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
13014 goto nla_put_failure;
Johannes Berg362a4152009-05-24 16:43:15 +020013015
Johannes Bergae917c92013-10-25 11:05:22 +020013016 if (req->flags &&
13017 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
13018 goto nla_put_failure;
Sam Lefflered4737712012-10-11 21:03:31 -070013019
Avraham Stern1d762502016-07-05 17:10:13 +030013020 if (req->info.scan_start_tsf &&
13021 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
13022 req->info.scan_start_tsf, NL80211_BSS_PAD) ||
13023 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
13024 req->info.tsf_bssid)))
13025 goto nla_put_failure;
13026
Johannes Berg362a4152009-05-24 16:43:15 +020013027 return 0;
13028 nla_put_failure:
13029 return -ENOBUFS;
13030}
13031
Johannes Berga538e2d2009-06-16 19:56:42 +020013032static int nl80211_send_scan_msg(struct sk_buff *msg,
13033 struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013034 struct wireless_dev *wdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013035 u32 portid, u32 seq, int flags,
Johannes Berga538e2d2009-06-16 19:56:42 +020013036 u32 cmd)
Johannes Berg2a519312009-02-10 21:25:55 +010013037{
13038 void *hdr;
13039
Eric W. Biederman15e47302012-09-07 20:12:54 +000013040 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg2a519312009-02-10 21:25:55 +010013041 if (!hdr)
13042 return -1;
13043
David S. Miller9360ffd2012-03-29 04:41:26 -040013044 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Bergfd014282012-06-18 19:17:03 +020013045 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13046 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013047 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13048 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013049 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +010013050
Johannes Berg362a4152009-05-24 16:43:15 +020013051 /* ignore errors and send incomplete event anyway */
13052 nl80211_add_scan_req(msg, rdev);
Johannes Berg2a519312009-02-10 21:25:55 +010013053
Johannes Berg053c0952015-01-16 22:09:00 +010013054 genlmsg_end(msg, hdr);
13055 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +010013056
13057 nla_put_failure:
13058 genlmsg_cancel(msg, hdr);
13059 return -EMSGSIZE;
13060}
13061
Luciano Coelho807f8a82011-05-11 17:09:35 +030013062static int
13063nl80211_send_sched_scan_msg(struct sk_buff *msg,
13064 struct cfg80211_registered_device *rdev,
13065 struct net_device *netdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013066 u32 portid, u32 seq, int flags, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030013067{
13068 void *hdr;
13069
Eric W. Biederman15e47302012-09-07 20:12:54 +000013070 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013071 if (!hdr)
13072 return -1;
13073
David S. Miller9360ffd2012-03-29 04:41:26 -040013074 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13075 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
13076 goto nla_put_failure;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013077
Johannes Berg053c0952015-01-16 22:09:00 +010013078 genlmsg_end(msg, hdr);
13079 return 0;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013080
13081 nla_put_failure:
13082 genlmsg_cancel(msg, hdr);
13083 return -EMSGSIZE;
13084}
13085
Johannes Berga538e2d2009-06-16 19:56:42 +020013086void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013087 struct wireless_dev *wdev)
Johannes Berga538e2d2009-06-16 19:56:42 +020013088{
13089 struct sk_buff *msg;
13090
Thomas Graf58050fc2012-06-28 03:57:45 +000013091 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013092 if (!msg)
13093 return;
13094
Johannes Bergfd014282012-06-18 19:17:03 +020013095 if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Berga538e2d2009-06-16 19:56:42 +020013096 NL80211_CMD_TRIGGER_SCAN) < 0) {
13097 nlmsg_free(msg);
13098 return;
13099 }
13100
Johannes Berg68eb5502013-11-19 15:19:38 +010013101 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013102 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013103}
13104
Johannes Bergf9d15d12014-01-22 11:14:19 +020013105struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
13106 struct wireless_dev *wdev, bool aborted)
Johannes Berg2a519312009-02-10 21:25:55 +010013107{
13108 struct sk_buff *msg;
13109
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013110 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013111 if (!msg)
Johannes Bergf9d15d12014-01-22 11:14:19 +020013112 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013113
Johannes Bergfd014282012-06-18 19:17:03 +020013114 if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Bergf9d15d12014-01-22 11:14:19 +020013115 aborted ? NL80211_CMD_SCAN_ABORTED :
13116 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +010013117 nlmsg_free(msg);
Johannes Bergf9d15d12014-01-22 11:14:19 +020013118 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013119 }
13120
Johannes Bergf9d15d12014-01-22 11:14:19 +020013121 return msg;
Johannes Berg2a519312009-02-10 21:25:55 +010013122}
13123
Johannes Bergf9d15d12014-01-22 11:14:19 +020013124void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
13125 struct sk_buff *msg)
Johannes Berg2a519312009-02-10 21:25:55 +010013126{
Johannes Berg2a519312009-02-10 21:25:55 +010013127 if (!msg)
13128 return;
13129
Johannes Berg68eb5502013-11-19 15:19:38 +010013130 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013131 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013132}
13133
Luciano Coelho807f8a82011-05-11 17:09:35 +030013134void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
13135 struct net_device *netdev)
13136{
13137 struct sk_buff *msg;
13138
13139 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13140 if (!msg)
13141 return;
13142
13143 if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
13144 NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
13145 nlmsg_free(msg);
13146 return;
13147 }
13148
Johannes Berg68eb5502013-11-19 15:19:38 +010013149 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013150 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013151}
13152
13153void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
13154 struct net_device *netdev, u32 cmd)
13155{
13156 struct sk_buff *msg;
13157
Thomas Graf58050fc2012-06-28 03:57:45 +000013158 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013159 if (!msg)
13160 return;
13161
13162 if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
13163 nlmsg_free(msg);
13164 return;
13165 }
13166
Johannes Berg68eb5502013-11-19 15:19:38 +010013167 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013168 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013169}
13170
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013171static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
13172 struct regulatory_request *request)
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013173{
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013174 /* Userspace can always count this one always being set */
David S. Miller9360ffd2012-03-29 04:41:26 -040013175 if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
13176 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013177
David S. Miller9360ffd2012-03-29 04:41:26 -040013178 if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
13179 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13180 NL80211_REGDOM_TYPE_WORLD))
13181 goto nla_put_failure;
13182 } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
13183 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13184 NL80211_REGDOM_TYPE_CUSTOM_WORLD))
13185 goto nla_put_failure;
13186 } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
13187 request->intersect) {
13188 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13189 NL80211_REGDOM_TYPE_INTERSECTION))
13190 goto nla_put_failure;
13191 } else {
13192 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13193 NL80211_REGDOM_TYPE_COUNTRY) ||
13194 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
13195 request->alpha2))
13196 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013197 }
13198
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013199 if (request->wiphy_idx != WIPHY_IDX_INVALID) {
13200 struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
13201
13202 if (wiphy &&
13203 nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
13204 goto nla_put_failure;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +020013205
13206 if (wiphy &&
13207 wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
13208 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
13209 goto nla_put_failure;
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013210 }
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013211
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013212 return true;
13213
13214nla_put_failure:
13215 return false;
13216}
13217
13218/*
13219 * This can happen on global regulatory changes or device specific settings
13220 * based on custom regulatory domains.
13221 */
13222void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
13223 struct regulatory_request *request)
13224{
13225 struct sk_buff *msg;
13226 void *hdr;
13227
13228 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13229 if (!msg)
13230 return;
13231
13232 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
13233 if (!hdr) {
13234 nlmsg_free(msg);
13235 return;
13236 }
13237
13238 if (nl80211_reg_change_event_fill(msg, request) == false)
13239 goto nla_put_failure;
13240
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013241 genlmsg_end(msg, hdr);
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013242
Johannes Bergbc43b282009-07-25 10:54:13 +020013243 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013244 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013245 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Bergbc43b282009-07-25 10:54:13 +020013246 rcu_read_unlock();
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013247
13248 return;
13249
13250nla_put_failure:
13251 genlmsg_cancel(msg, hdr);
13252 nlmsg_free(msg);
13253}
13254
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013255static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
13256 struct net_device *netdev,
13257 const u8 *buf, size_t len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013258 enum nl80211_commands cmd, gfp_t gfp,
13259 int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013260{
13261 struct sk_buff *msg;
13262 void *hdr;
13263
Johannes Berg14459722017-01-09 11:10:42 +010013264 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013265 if (!msg)
13266 return;
13267
13268 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13269 if (!hdr) {
13270 nlmsg_free(msg);
13271 return;
13272 }
13273
David S. Miller9360ffd2012-03-29 04:41:26 -040013274 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13275 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13276 nla_put(msg, NL80211_ATTR_FRAME, len, buf))
13277 goto nla_put_failure;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013278
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013279 if (uapsd_queues >= 0) {
13280 struct nlattr *nla_wmm =
13281 nla_nest_start(msg, NL80211_ATTR_STA_WME);
13282 if (!nla_wmm)
13283 goto nla_put_failure;
13284
13285 if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
13286 uapsd_queues))
13287 goto nla_put_failure;
13288
13289 nla_nest_end(msg, nla_wmm);
13290 }
13291
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013292 genlmsg_end(msg, hdr);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013293
Johannes Berg68eb5502013-11-19 15:19:38 +010013294 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013295 NL80211_MCGRP_MLME, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013296 return;
13297
13298 nla_put_failure:
13299 genlmsg_cancel(msg, hdr);
13300 nlmsg_free(msg);
13301}
13302
13303void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013304 struct net_device *netdev, const u8 *buf,
13305 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013306{
13307 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013308 NL80211_CMD_AUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013309}
13310
13311void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
13312 struct net_device *netdev, const u8 *buf,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013313 size_t len, gfp_t gfp, int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013314{
Johannes Berge6d6e342009-07-01 21:26:47 +020013315 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013316 NL80211_CMD_ASSOCIATE, gfp, uapsd_queues);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013317}
13318
Jouni Malinen53b46b82009-03-27 20:53:56 +020013319void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013320 struct net_device *netdev, const u8 *buf,
13321 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013322{
13323 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013324 NL80211_CMD_DEAUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013325}
13326
Jouni Malinen53b46b82009-03-27 20:53:56 +020013327void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
13328 struct net_device *netdev, const u8 *buf,
Johannes Berge6d6e342009-07-01 21:26:47 +020013329 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013330{
13331 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013332 NL80211_CMD_DISASSOCIATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013333}
13334
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013335void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
13336 size_t len)
Jouni Malinencf4e5942010-12-16 00:52:40 +020013337{
Johannes Berg947add32013-02-22 22:05:20 +010013338 struct wireless_dev *wdev = dev->ieee80211_ptr;
13339 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013340 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013341 const struct ieee80211_mgmt *mgmt = (void *)buf;
13342 u32 cmd;
Jouni Malinencf4e5942010-12-16 00:52:40 +020013343
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013344 if (WARN_ON(len < 2))
13345 return;
13346
13347 if (ieee80211_is_deauth(mgmt->frame_control))
13348 cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
13349 else
13350 cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
13351
13352 trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013353 nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013354}
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013355EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013356
Luis R. Rodriguez1b06bb42009-05-02 00:34:48 -040013357static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
13358 struct net_device *netdev, int cmd,
Johannes Berge6d6e342009-07-01 21:26:47 +020013359 const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013360{
13361 struct sk_buff *msg;
13362 void *hdr;
13363
Johannes Berge6d6e342009-07-01 21:26:47 +020013364 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013365 if (!msg)
13366 return;
13367
13368 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13369 if (!hdr) {
13370 nlmsg_free(msg);
13371 return;
13372 }
13373
David S. Miller9360ffd2012-03-29 04:41:26 -040013374 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13375 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13376 nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
13377 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
13378 goto nla_put_failure;
Jouni Malinen1965c852009-04-22 21:38:25 +030013379
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013380 genlmsg_end(msg, hdr);
Jouni Malinen1965c852009-04-22 21:38:25 +030013381
Johannes Berg68eb5502013-11-19 15:19:38 +010013382 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013383 NL80211_MCGRP_MLME, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013384 return;
13385
13386 nla_put_failure:
13387 genlmsg_cancel(msg, hdr);
13388 nlmsg_free(msg);
13389}
13390
13391void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013392 struct net_device *netdev, const u8 *addr,
13393 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013394{
13395 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
Johannes Berge6d6e342009-07-01 21:26:47 +020013396 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013397}
13398
13399void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013400 struct net_device *netdev, const u8 *addr,
13401 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013402{
Johannes Berge6d6e342009-07-01 21:26:47 +020013403 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
13404 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013405}
13406
Samuel Ortizb23aa672009-07-01 21:26:54 +020013407void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
Vidyullatha Kanchanapally3f1905b2017-03-31 00:22:33 +030013408 struct net_device *netdev,
13409 struct cfg80211_connect_resp_params *cr,
Purushottam Kushwahadf935062017-01-13 01:12:21 +020013410 gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013411{
13412 struct sk_buff *msg;
13413 void *hdr;
13414
Vidyullatha Kanchanapally36eabf62017-03-31 00:22:34 +030013415 msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
13416 cr->fils_kek_len + cr->pmk_len +
13417 (cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013418 if (!msg)
13419 return;
13420
13421 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
13422 if (!hdr) {
13423 nlmsg_free(msg);
13424 return;
13425 }
13426
David S. Miller9360ffd2012-03-29 04:41:26 -040013427 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13428 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Vidyullatha Kanchanapally3f1905b2017-03-31 00:22:33 +030013429 (cr->bssid &&
13430 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
Jouni Malinenbf1ecd22016-05-31 00:16:50 +030013431 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
Vidyullatha Kanchanapally3f1905b2017-03-31 00:22:33 +030013432 cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
13433 cr->status) ||
13434 (cr->status < 0 &&
Purushottam Kushwahadf935062017-01-13 01:12:21 +020013435 (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
Vidyullatha Kanchanapally3f1905b2017-03-31 00:22:33 +030013436 nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
13437 cr->timeout_reason))) ||
13438 (cr->req_ie &&
13439 nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
13440 (cr->resp_ie &&
13441 nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
Vidyullatha Kanchanapally36eabf62017-03-31 00:22:34 +030013442 cr->resp_ie)) ||
13443 (cr->update_erp_next_seq_num &&
13444 nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
13445 cr->fils_erp_next_seq_num)) ||
13446 (cr->status == WLAN_STATUS_SUCCESS &&
13447 ((cr->fils_kek &&
13448 nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
13449 cr->fils_kek)) ||
13450 (cr->pmk &&
13451 nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
13452 (cr->pmkid &&
13453 nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
David S. Miller9360ffd2012-03-29 04:41:26 -040013454 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013455
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013456 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +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);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013460 return;
13461
13462 nla_put_failure:
13463 genlmsg_cancel(msg, hdr);
13464 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013465}
13466
13467void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
Avraham Stern9e841a62017-04-26 10:58:49 +030013468 struct net_device *netdev,
13469 struct cfg80211_roam_info *info, gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013470{
13471 struct sk_buff *msg;
13472 void *hdr;
Avraham Stern9e841a62017-04-26 10:58:49 +030013473 const u8 *bssid = info->bss ? info->bss->bssid : info->bssid;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013474
Avraham Stern9e841a62017-04-26 10:58:49 +030013475 msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013476 if (!msg)
13477 return;
13478
13479 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
13480 if (!hdr) {
13481 nlmsg_free(msg);
13482 return;
13483 }
13484
David S. Miller9360ffd2012-03-29 04:41:26 -040013485 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13486 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13487 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
Avraham Stern9e841a62017-04-26 10:58:49 +030013488 (info->req_ie &&
13489 nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len,
13490 info->req_ie)) ||
13491 (info->resp_ie &&
13492 nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
Avraham Stern562be6e2017-06-09 13:08:45 +010013493 info->resp_ie)) ||
13494 (info->authorized &&
13495 nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)))
David S. Miller9360ffd2012-03-29 04:41:26 -040013496 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013497
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013498 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013499
Johannes Berg68eb5502013-11-19 15:19:38 +010013500 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013501 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013502 return;
13503
13504 nla_put_failure:
13505 genlmsg_cancel(msg, hdr);
13506 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013507}
13508
13509void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
13510 struct net_device *netdev, u16 reason,
Johannes Berg667503dd2009-07-07 03:56:11 +020013511 const u8 *ie, size_t ie_len, bool from_ap)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013512{
13513 struct sk_buff *msg;
13514 void *hdr;
13515
Johannes Berg14459722017-01-09 11:10:42 +010013516 msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013517 if (!msg)
13518 return;
13519
13520 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
13521 if (!hdr) {
13522 nlmsg_free(msg);
13523 return;
13524 }
13525
David S. Miller9360ffd2012-03-29 04:41:26 -040013526 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13527 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13528 (from_ap && reason &&
13529 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
13530 (from_ap &&
13531 nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
13532 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
13533 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013534
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013535 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013536
Johannes Berg68eb5502013-11-19 15:19:38 +010013537 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013538 NL80211_MCGRP_MLME, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013539 return;
13540
13541 nla_put_failure:
13542 genlmsg_cancel(msg, hdr);
13543 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013544}
13545
Johannes Berg04a773a2009-04-19 21:24:32 +020013546void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
13547 struct net_device *netdev, const u8 *bssid,
13548 gfp_t gfp)
13549{
13550 struct sk_buff *msg;
13551 void *hdr;
13552
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013553 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013554 if (!msg)
13555 return;
13556
13557 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
13558 if (!hdr) {
13559 nlmsg_free(msg);
13560 return;
13561 }
13562
David S. Miller9360ffd2012-03-29 04:41:26 -040013563 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13564 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13565 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
13566 goto nla_put_failure;
Johannes Berg04a773a2009-04-19 21:24:32 +020013567
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013568 genlmsg_end(msg, hdr);
Johannes Berg04a773a2009-04-19 21:24:32 +020013569
Johannes Berg68eb5502013-11-19 15:19:38 +010013570 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013571 NL80211_MCGRP_MLME, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013572 return;
13573
13574 nla_put_failure:
13575 genlmsg_cancel(msg, hdr);
13576 nlmsg_free(msg);
13577}
13578
Johannes Berg947add32013-02-22 22:05:20 +010013579void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
13580 const u8* ie, u8 ie_len, gfp_t gfp)
Javier Cardonac93b5e72011-04-07 15:08:34 -070013581{
Johannes Berg947add32013-02-22 22:05:20 +010013582 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013583 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013584 struct sk_buff *msg;
13585 void *hdr;
13586
Johannes Berg947add32013-02-22 22:05:20 +010013587 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
13588 return;
13589
13590 trace_cfg80211_notify_new_peer_candidate(dev, addr);
13591
Johannes Berg14459722017-01-09 11:10:42 +010013592 msg = nlmsg_new(100 + ie_len, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013593 if (!msg)
13594 return;
13595
13596 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
13597 if (!hdr) {
13598 nlmsg_free(msg);
13599 return;
13600 }
13601
David S. Miller9360ffd2012-03-29 04:41:26 -040013602 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010013603 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13604 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013605 (ie_len && ie &&
13606 nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
13607 goto nla_put_failure;
Javier Cardonac93b5e72011-04-07 15:08:34 -070013608
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013609 genlmsg_end(msg, hdr);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013610
Johannes Berg68eb5502013-11-19 15:19:38 +010013611 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013612 NL80211_MCGRP_MLME, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013613 return;
13614
13615 nla_put_failure:
13616 genlmsg_cancel(msg, hdr);
13617 nlmsg_free(msg);
13618}
Johannes Berg947add32013-02-22 22:05:20 +010013619EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013620
Jouni Malinena3b8b052009-03-27 21:59:49 +020013621void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
13622 struct net_device *netdev, const u8 *addr,
13623 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +020013624 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +020013625{
13626 struct sk_buff *msg;
13627 void *hdr;
13628
Johannes Berge6d6e342009-07-01 21:26:47 +020013629 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013630 if (!msg)
13631 return;
13632
13633 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
13634 if (!hdr) {
13635 nlmsg_free(msg);
13636 return;
13637 }
13638
David S. Miller9360ffd2012-03-29 04:41:26 -040013639 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13640 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13641 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
13642 nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
13643 (key_id != -1 &&
13644 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
13645 (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
13646 goto nla_put_failure;
Jouni Malinena3b8b052009-03-27 21:59:49 +020013647
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013648 genlmsg_end(msg, hdr);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013649
Johannes Berg68eb5502013-11-19 15:19:38 +010013650 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013651 NL80211_MCGRP_MLME, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013652 return;
13653
13654 nla_put_failure:
13655 genlmsg_cancel(msg, hdr);
13656 nlmsg_free(msg);
13657}
13658
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013659void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
13660 struct ieee80211_channel *channel_before,
13661 struct ieee80211_channel *channel_after)
13662{
13663 struct sk_buff *msg;
13664 void *hdr;
13665 struct nlattr *nl_freq;
13666
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013667 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013668 if (!msg)
13669 return;
13670
13671 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
13672 if (!hdr) {
13673 nlmsg_free(msg);
13674 return;
13675 }
13676
13677 /*
13678 * Since we are applying the beacon hint to a wiphy we know its
13679 * wiphy_idx is valid
13680 */
David S. Miller9360ffd2012-03-29 04:41:26 -040013681 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
13682 goto nla_put_failure;
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013683
13684 /* Before */
13685 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
13686 if (!nl_freq)
13687 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010013688 if (nl80211_msg_put_channel(msg, channel_before, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013689 goto nla_put_failure;
13690 nla_nest_end(msg, nl_freq);
13691
13692 /* After */
13693 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
13694 if (!nl_freq)
13695 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010013696 if (nl80211_msg_put_channel(msg, channel_after, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013697 goto nla_put_failure;
13698 nla_nest_end(msg, nl_freq);
13699
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013700 genlmsg_end(msg, hdr);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013701
Johannes Berg463d0182009-07-14 00:33:35 +020013702 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013703 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013704 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Berg463d0182009-07-14 00:33:35 +020013705 rcu_read_unlock();
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013706
13707 return;
13708
13709nla_put_failure:
13710 genlmsg_cancel(msg, hdr);
13711 nlmsg_free(msg);
13712}
13713
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013714static void nl80211_send_remain_on_chan_event(
13715 int cmd, struct cfg80211_registered_device *rdev,
Johannes Berg71bbc992012-06-15 15:30:18 +020013716 struct wireless_dev *wdev, u64 cookie,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013717 struct ieee80211_channel *chan,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013718 unsigned int duration, gfp_t gfp)
13719{
13720 struct sk_buff *msg;
13721 void *hdr;
13722
13723 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13724 if (!msg)
13725 return;
13726
13727 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13728 if (!hdr) {
13729 nlmsg_free(msg);
13730 return;
13731 }
13732
David S. Miller9360ffd2012-03-29 04:41:26 -040013733 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013734 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13735 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013736 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13737 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013738 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
Johannes Berg42d97a52012-11-08 18:31:02 +010013739 nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
13740 NL80211_CHAN_NO_HT) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013741 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13742 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013743 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013744
David S. Miller9360ffd2012-03-29 04:41:26 -040013745 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
13746 nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
13747 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013748
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013749 genlmsg_end(msg, hdr);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013750
Johannes Berg68eb5502013-11-19 15:19:38 +010013751 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013752 NL80211_MCGRP_MLME, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013753 return;
13754
13755 nla_put_failure:
13756 genlmsg_cancel(msg, hdr);
13757 nlmsg_free(msg);
13758}
13759
Johannes Berg947add32013-02-22 22:05:20 +010013760void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
13761 struct ieee80211_channel *chan,
13762 unsigned int duration, gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013763{
Johannes Berg947add32013-02-22 22:05:20 +010013764 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013765 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010013766
13767 trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013768 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Berg71bbc992012-06-15 15:30:18 +020013769 rdev, wdev, cookie, chan,
Johannes Berg42d97a52012-11-08 18:31:02 +010013770 duration, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013771}
Johannes Berg947add32013-02-22 22:05:20 +010013772EXPORT_SYMBOL(cfg80211_ready_on_channel);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013773
Johannes Berg947add32013-02-22 22:05:20 +010013774void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
13775 struct ieee80211_channel *chan,
13776 gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013777{
Johannes Berg947add32013-02-22 22:05:20 +010013778 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013779 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010013780
13781 trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013782 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Berg42d97a52012-11-08 18:31:02 +010013783 rdev, wdev, cookie, chan, 0, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013784}
Johannes Berg947add32013-02-22 22:05:20 +010013785EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013786
Johannes Berg947add32013-02-22 22:05:20 +010013787void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
13788 struct station_info *sinfo, gfp_t gfp)
Johannes Berg98b62182009-12-23 13:15:44 +010013789{
Johannes Berg947add32013-02-22 22:05:20 +010013790 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013791 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg98b62182009-12-23 13:15:44 +010013792 struct sk_buff *msg;
13793
Johannes Berg947add32013-02-22 22:05:20 +010013794 trace_cfg80211_new_sta(dev, mac_addr, sinfo);
13795
Thomas Graf58050fc2012-06-28 03:57:45 +000013796 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010013797 if (!msg)
13798 return;
13799
Johannes Bergcf5ead82014-11-14 17:14:00 +010013800 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
John W. Linville66266b32012-03-15 13:25:41 -040013801 rdev, dev, mac_addr, sinfo) < 0) {
Johannes Berg98b62182009-12-23 13:15:44 +010013802 nlmsg_free(msg);
13803 return;
13804 }
13805
Johannes Berg68eb5502013-11-19 15:19:38 +010013806 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013807 NL80211_MCGRP_MLME, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010013808}
Johannes Berg947add32013-02-22 22:05:20 +010013809EXPORT_SYMBOL(cfg80211_new_sta);
Johannes Berg98b62182009-12-23 13:15:44 +010013810
Johannes Bergcf5ead82014-11-14 17:14:00 +010013811void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
13812 struct station_info *sinfo, gfp_t gfp)
Jouni Malinenec15e682011-03-23 15:29:52 +020013813{
Johannes Berg947add32013-02-22 22:05:20 +010013814 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013815 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinenec15e682011-03-23 15:29:52 +020013816 struct sk_buff *msg;
Johannes Bergcf5ead82014-11-14 17:14:00 +010013817 struct station_info empty_sinfo = {};
13818
13819 if (!sinfo)
13820 sinfo = &empty_sinfo;
Jouni Malinenec15e682011-03-23 15:29:52 +020013821
Johannes Berg947add32013-02-22 22:05:20 +010013822 trace_cfg80211_del_sta(dev, mac_addr);
13823
Thomas Graf58050fc2012-06-28 03:57:45 +000013824 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020013825 if (!msg)
13826 return;
13827
Johannes Bergcf5ead82014-11-14 17:14:00 +010013828 if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
Johannes Berg57007122015-01-16 21:05:02 +010013829 rdev, dev, mac_addr, sinfo) < 0) {
Jouni Malinenec15e682011-03-23 15:29:52 +020013830 nlmsg_free(msg);
13831 return;
13832 }
13833
Johannes Berg68eb5502013-11-19 15:19:38 +010013834 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013835 NL80211_MCGRP_MLME, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020013836}
Johannes Bergcf5ead82014-11-14 17:14:00 +010013837EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
Jouni Malinenec15e682011-03-23 15:29:52 +020013838
Johannes Berg947add32013-02-22 22:05:20 +010013839void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
13840 enum nl80211_connect_failed_reason reason,
13841 gfp_t gfp)
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013842{
Johannes Berg947add32013-02-22 22:05:20 +010013843 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013844 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013845 struct sk_buff *msg;
13846 void *hdr;
13847
13848 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
13849 if (!msg)
13850 return;
13851
13852 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
13853 if (!hdr) {
13854 nlmsg_free(msg);
13855 return;
13856 }
13857
13858 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13859 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
13860 nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
13861 goto nla_put_failure;
13862
13863 genlmsg_end(msg, hdr);
13864
Johannes Berg68eb5502013-11-19 15:19:38 +010013865 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013866 NL80211_MCGRP_MLME, gfp);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013867 return;
13868
13869 nla_put_failure:
13870 genlmsg_cancel(msg, hdr);
13871 nlmsg_free(msg);
13872}
Johannes Berg947add32013-02-22 22:05:20 +010013873EXPORT_SYMBOL(cfg80211_conn_failed);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013874
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013875static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
13876 const u8 *addr, gfp_t gfp)
Johannes Berg28946da2011-11-04 11:18:12 +010013877{
13878 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013879 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg28946da2011-11-04 11:18:12 +010013880 struct sk_buff *msg;
13881 void *hdr;
Eric W. Biederman15e47302012-09-07 20:12:54 +000013882 u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010013883
Eric W. Biederman15e47302012-09-07 20:12:54 +000013884 if (!nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010013885 return false;
13886
13887 msg = nlmsg_new(100, gfp);
13888 if (!msg)
13889 return true;
13890
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013891 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Johannes Berg28946da2011-11-04 11:18:12 +010013892 if (!hdr) {
13893 nlmsg_free(msg);
13894 return true;
13895 }
13896
David S. Miller9360ffd2012-03-29 04:41:26 -040013897 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13898 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13899 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
13900 goto nla_put_failure;
Johannes Berg28946da2011-11-04 11:18:12 +010013901
Johannes Berg9c90a9f2013-06-04 12:46:03 +020013902 genlmsg_end(msg, hdr);
Eric W. Biederman15e47302012-09-07 20:12:54 +000013903 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010013904 return true;
13905
13906 nla_put_failure:
13907 genlmsg_cancel(msg, hdr);
13908 nlmsg_free(msg);
13909 return true;
13910}
13911
Johannes Berg947add32013-02-22 22:05:20 +010013912bool cfg80211_rx_spurious_frame(struct net_device *dev,
13913 const u8 *addr, gfp_t gfp)
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013914{
Johannes Berg947add32013-02-22 22:05:20 +010013915 struct wireless_dev *wdev = dev->ieee80211_ptr;
13916 bool ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013917
Johannes Berg947add32013-02-22 22:05:20 +010013918 trace_cfg80211_rx_spurious_frame(dev, addr);
13919
13920 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
13921 wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
13922 trace_cfg80211_return_bool(false);
13923 return false;
13924 }
13925 ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
13926 addr, gfp);
13927 trace_cfg80211_return_bool(ret);
13928 return ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013929}
Johannes Berg947add32013-02-22 22:05:20 +010013930EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
13931
13932bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
13933 const u8 *addr, gfp_t gfp)
13934{
13935 struct wireless_dev *wdev = dev->ieee80211_ptr;
13936 bool ret;
13937
13938 trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
13939
13940 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
13941 wdev->iftype != NL80211_IFTYPE_P2P_GO &&
13942 wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
13943 trace_cfg80211_return_bool(false);
13944 return false;
13945 }
13946 ret = __nl80211_unexpected_frame(dev,
13947 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
13948 addr, gfp);
13949 trace_cfg80211_return_bool(ret);
13950 return ret;
13951}
13952EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013953
Johannes Berg2e161f72010-08-12 15:38:38 +020013954int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013955 struct wireless_dev *wdev, u32 nlportid,
Johannes Berg804483e2012-03-05 22:18:41 +010013956 int freq, int sig_dbm,
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030013957 const u8 *buf, size_t len, u32 flags, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020013958{
Johannes Berg71bbc992012-06-15 15:30:18 +020013959 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020013960 struct sk_buff *msg;
13961 void *hdr;
Jouni Malinen026331c2010-02-15 12:53:10 +020013962
Johannes Berg14459722017-01-09 11:10:42 +010013963 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020013964 if (!msg)
13965 return -ENOMEM;
13966
Johannes Berg2e161f72010-08-12 15:38:38 +020013967 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
Jouni Malinen026331c2010-02-15 12:53:10 +020013968 if (!hdr) {
13969 nlmsg_free(msg);
13970 return -ENOMEM;
13971 }
13972
David S. Miller9360ffd2012-03-29 04:41:26 -040013973 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013974 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13975 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013976 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13977 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013978 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
13979 (sig_dbm &&
13980 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030013981 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
13982 (flags &&
13983 nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
David S. Miller9360ffd2012-03-29 04:41:26 -040013984 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020013985
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013986 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020013987
Eric W. Biederman15e47302012-09-07 20:12:54 +000013988 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Jouni Malinen026331c2010-02-15 12:53:10 +020013989
13990 nla_put_failure:
13991 genlmsg_cancel(msg, hdr);
13992 nlmsg_free(msg);
13993 return -ENOBUFS;
13994}
13995
Johannes Berg947add32013-02-22 22:05:20 +010013996void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
13997 const u8 *buf, size_t len, bool ack, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020013998{
Johannes Berg947add32013-02-22 22:05:20 +010013999 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014000 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg71bbc992012-06-15 15:30:18 +020014001 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020014002 struct sk_buff *msg;
14003 void *hdr;
14004
Johannes Berg947add32013-02-22 22:05:20 +010014005 trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
14006
Johannes Berg14459722017-01-09 11:10:42 +010014007 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014008 if (!msg)
14009 return;
14010
Johannes Berg2e161f72010-08-12 15:38:38 +020014011 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
Jouni Malinen026331c2010-02-15 12:53:10 +020014012 if (!hdr) {
14013 nlmsg_free(msg);
14014 return;
14015 }
14016
David S. Miller9360ffd2012-03-29 04:41:26 -040014017 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014018 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14019 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014020 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14021 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014022 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014023 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14024 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014025 (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
14026 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020014027
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014028 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020014029
Johannes Berg68eb5502013-11-19 15:19:38 +010014030 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014031 NL80211_MCGRP_MLME, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014032 return;
14033
14034 nla_put_failure:
14035 genlmsg_cancel(msg, hdr);
14036 nlmsg_free(msg);
14037}
Johannes Berg947add32013-02-22 22:05:20 +010014038EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
Jouni Malinen026331c2010-02-15 12:53:10 +020014039
Johannes Berg5b97f492014-11-26 12:37:43 +010014040static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
14041 const char *mac, gfp_t gfp)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014042{
Johannes Berg947add32013-02-22 22:05:20 +010014043 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg5b97f492014-11-26 12:37:43 +010014044 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
14045 struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14046 void **cb;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014047
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014048 if (!msg)
Johannes Berg5b97f492014-11-26 12:37:43 +010014049 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014050
Johannes Berg5b97f492014-11-26 12:37:43 +010014051 cb = (void **)msg->cb;
14052
14053 cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
14054 if (!cb[0]) {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014055 nlmsg_free(msg);
Johannes Berg5b97f492014-11-26 12:37:43 +010014056 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014057 }
14058
David S. Miller9360ffd2012-03-29 04:41:26 -040014059 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010014060 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
David S. Miller9360ffd2012-03-29 04:41:26 -040014061 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014062
Johannes Berg5b97f492014-11-26 12:37:43 +010014063 if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014064 goto nla_put_failure;
14065
Johannes Berg5b97f492014-11-26 12:37:43 +010014066 cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM);
14067 if (!cb[1])
14068 goto nla_put_failure;
14069
14070 cb[2] = rdev;
14071
14072 return msg;
14073 nla_put_failure:
14074 nlmsg_free(msg);
14075 return NULL;
14076}
14077
14078static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
14079{
14080 void **cb = (void **)msg->cb;
14081 struct cfg80211_registered_device *rdev = cb[2];
14082
14083 nla_nest_end(msg, cb[1]);
14084 genlmsg_end(msg, cb[0]);
14085
14086 memset(msg->cb, 0, sizeof(msg->cb));
14087
14088 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14089 NL80211_MCGRP_MLME, gfp);
14090}
14091
14092void cfg80211_cqm_rssi_notify(struct net_device *dev,
14093 enum nl80211_cqm_rssi_threshold_event rssi_event,
14094 gfp_t gfp)
14095{
14096 struct sk_buff *msg;
14097
14098 trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
14099
Johannes Berg98f03342014-11-26 12:42:02 +010014100 if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
14101 rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
14102 return;
14103
Johannes Berg5b97f492014-11-26 12:37:43 +010014104 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14105 if (!msg)
14106 return;
14107
David S. Miller9360ffd2012-03-29 04:41:26 -040014108 if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
14109 rssi_event))
14110 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014111
Johannes Berg5b97f492014-11-26 12:37:43 +010014112 cfg80211_send_cqm(msg, gfp);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014113
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014114 return;
14115
14116 nla_put_failure:
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014117 nlmsg_free(msg);
14118}
Johannes Berg947add32013-02-22 22:05:20 +010014119EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014120
Johannes Berg5b97f492014-11-26 12:37:43 +010014121void cfg80211_cqm_txe_notify(struct net_device *dev,
14122 const u8 *peer, u32 num_packets,
14123 u32 rate, u32 intvl, gfp_t gfp)
14124{
14125 struct sk_buff *msg;
14126
14127 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14128 if (!msg)
14129 return;
14130
14131 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
14132 goto nla_put_failure;
14133
14134 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
14135 goto nla_put_failure;
14136
14137 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
14138 goto nla_put_failure;
14139
14140 cfg80211_send_cqm(msg, gfp);
14141 return;
14142
14143 nla_put_failure:
14144 nlmsg_free(msg);
14145}
14146EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
14147
14148void cfg80211_cqm_pktloss_notify(struct net_device *dev,
14149 const u8 *peer, u32 num_packets, gfp_t gfp)
14150{
14151 struct sk_buff *msg;
14152
14153 trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
14154
14155 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14156 if (!msg)
14157 return;
14158
14159 if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
14160 goto nla_put_failure;
14161
14162 cfg80211_send_cqm(msg, gfp);
14163 return;
14164
14165 nla_put_failure:
14166 nlmsg_free(msg);
14167}
14168EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
14169
Johannes Berg98f03342014-11-26 12:42:02 +010014170void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
14171{
14172 struct sk_buff *msg;
14173
14174 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14175 if (!msg)
14176 return;
14177
14178 if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
14179 goto nla_put_failure;
14180
14181 cfg80211_send_cqm(msg, gfp);
14182 return;
14183
14184 nla_put_failure:
14185 nlmsg_free(msg);
14186}
14187EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
14188
Johannes Berg947add32013-02-22 22:05:20 +010014189static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
14190 struct net_device *netdev, const u8 *bssid,
14191 const u8 *replay_ctr, gfp_t gfp)
Johannes Berge5497d72011-07-05 16:35:40 +020014192{
14193 struct sk_buff *msg;
14194 struct nlattr *rekey_attr;
14195 void *hdr;
14196
Thomas Graf58050fc2012-06-28 03:57:45 +000014197 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014198 if (!msg)
14199 return;
14200
14201 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
14202 if (!hdr) {
14203 nlmsg_free(msg);
14204 return;
14205 }
14206
David S. Miller9360ffd2012-03-29 04:41:26 -040014207 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14208 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14209 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
14210 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014211
14212 rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
14213 if (!rekey_attr)
14214 goto nla_put_failure;
14215
David S. Miller9360ffd2012-03-29 04:41:26 -040014216 if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
14217 NL80211_REPLAY_CTR_LEN, replay_ctr))
14218 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014219
14220 nla_nest_end(msg, rekey_attr);
14221
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014222 genlmsg_end(msg, hdr);
Johannes Berge5497d72011-07-05 16:35:40 +020014223
Johannes Berg68eb5502013-11-19 15:19:38 +010014224 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014225 NL80211_MCGRP_MLME, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014226 return;
14227
14228 nla_put_failure:
14229 genlmsg_cancel(msg, hdr);
14230 nlmsg_free(msg);
14231}
14232
Johannes Berg947add32013-02-22 22:05:20 +010014233void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
14234 const u8 *replay_ctr, gfp_t gfp)
14235{
14236 struct wireless_dev *wdev = dev->ieee80211_ptr;
14237 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014238 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014239
14240 trace_cfg80211_gtk_rekey_notify(dev, bssid);
14241 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
14242}
14243EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
14244
14245static void
14246nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
14247 struct net_device *netdev, int index,
14248 const u8 *bssid, bool preauth, gfp_t gfp)
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014249{
14250 struct sk_buff *msg;
14251 struct nlattr *attr;
14252 void *hdr;
14253
Thomas Graf58050fc2012-06-28 03:57:45 +000014254 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014255 if (!msg)
14256 return;
14257
14258 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
14259 if (!hdr) {
14260 nlmsg_free(msg);
14261 return;
14262 }
14263
David S. Miller9360ffd2012-03-29 04:41:26 -040014264 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14265 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14266 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014267
14268 attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
14269 if (!attr)
14270 goto nla_put_failure;
14271
David S. Miller9360ffd2012-03-29 04:41:26 -040014272 if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
14273 nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
14274 (preauth &&
14275 nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
14276 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014277
14278 nla_nest_end(msg, attr);
14279
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014280 genlmsg_end(msg, hdr);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014281
Johannes Berg68eb5502013-11-19 15:19:38 +010014282 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014283 NL80211_MCGRP_MLME, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014284 return;
14285
14286 nla_put_failure:
14287 genlmsg_cancel(msg, hdr);
14288 nlmsg_free(msg);
14289}
14290
Johannes Berg947add32013-02-22 22:05:20 +010014291void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
14292 const u8 *bssid, bool preauth, gfp_t gfp)
14293{
14294 struct wireless_dev *wdev = dev->ieee80211_ptr;
14295 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014296 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014297
14298 trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
14299 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
14300}
14301EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
14302
14303static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
14304 struct net_device *netdev,
14305 struct cfg80211_chan_def *chandef,
Luciano Coelhof8d75522014-11-07 14:31:35 +020014306 gfp_t gfp,
14307 enum nl80211_commands notif,
14308 u8 count)
Thomas Pedersen53145262012-04-06 13:35:47 -070014309{
14310 struct sk_buff *msg;
14311 void *hdr;
14312
Thomas Graf58050fc2012-06-28 03:57:45 +000014313 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014314 if (!msg)
14315 return;
14316
Luciano Coelhof8d75522014-11-07 14:31:35 +020014317 hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
Thomas Pedersen53145262012-04-06 13:35:47 -070014318 if (!hdr) {
14319 nlmsg_free(msg);
14320 return;
14321 }
14322
Johannes Berg683b6d32012-11-08 21:25:48 +010014323 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14324 goto nla_put_failure;
14325
14326 if (nl80211_send_chandef(msg, chandef))
John W. Linville7eab0f62012-04-12 14:25:14 -040014327 goto nla_put_failure;
Thomas Pedersen53145262012-04-06 13:35:47 -070014328
Luciano Coelhof8d75522014-11-07 14:31:35 +020014329 if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
14330 (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
14331 goto nla_put_failure;
14332
Thomas Pedersen53145262012-04-06 13:35:47 -070014333 genlmsg_end(msg, hdr);
14334
Johannes Berg68eb5502013-11-19 15:19:38 +010014335 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014336 NL80211_MCGRP_MLME, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014337 return;
14338
14339 nla_put_failure:
14340 genlmsg_cancel(msg, hdr);
14341 nlmsg_free(msg);
14342}
14343
Johannes Berg947add32013-02-22 22:05:20 +010014344void cfg80211_ch_switch_notify(struct net_device *dev,
14345 struct cfg80211_chan_def *chandef)
Thomas Pedersen84f10702012-07-12 16:17:33 -070014346{
Johannes Berg947add32013-02-22 22:05:20 +010014347 struct wireless_dev *wdev = dev->ieee80211_ptr;
14348 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014349 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014350
Simon Wunderliche487eae2013-11-21 18:19:51 +010014351 ASSERT_WDEV_LOCK(wdev);
Johannes Berg947add32013-02-22 22:05:20 +010014352
Simon Wunderliche487eae2013-11-21 18:19:51 +010014353 trace_cfg80211_ch_switch_notify(dev, chandef);
Johannes Berg947add32013-02-22 22:05:20 +010014354
Michal Kazior9e0e2962014-01-29 14:22:27 +010014355 wdev->chandef = *chandef;
Janusz Dziedzic96f55f12014-01-24 14:29:21 +010014356 wdev->preset_chandef = *chandef;
Luciano Coelhof8d75522014-11-07 14:31:35 +020014357 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14358 NL80211_CMD_CH_SWITCH_NOTIFY, 0);
Johannes Berg947add32013-02-22 22:05:20 +010014359}
14360EXPORT_SYMBOL(cfg80211_ch_switch_notify);
14361
Luciano Coelhof8d75522014-11-07 14:31:35 +020014362void cfg80211_ch_switch_started_notify(struct net_device *dev,
14363 struct cfg80211_chan_def *chandef,
14364 u8 count)
14365{
14366 struct wireless_dev *wdev = dev->ieee80211_ptr;
14367 struct wiphy *wiphy = wdev->wiphy;
14368 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
14369
14370 trace_cfg80211_ch_switch_started_notify(dev, chandef);
14371
14372 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14373 NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
14374}
14375EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
14376
Thomas Pedersen84f10702012-07-12 16:17:33 -070014377void
Simon Wunderlich04f39042013-02-08 18:16:19 +010014378nl80211_radar_notify(struct cfg80211_registered_device *rdev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +010014379 const struct cfg80211_chan_def *chandef,
Simon Wunderlich04f39042013-02-08 18:16:19 +010014380 enum nl80211_radar_event event,
14381 struct net_device *netdev, gfp_t gfp)
14382{
14383 struct sk_buff *msg;
14384 void *hdr;
14385
14386 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14387 if (!msg)
14388 return;
14389
14390 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
14391 if (!hdr) {
14392 nlmsg_free(msg);
14393 return;
14394 }
14395
14396 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
14397 goto nla_put_failure;
14398
14399 /* NOP and radar events don't need a netdev parameter */
14400 if (netdev) {
14401 struct wireless_dev *wdev = netdev->ieee80211_ptr;
14402
14403 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014404 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14405 NL80211_ATTR_PAD))
Simon Wunderlich04f39042013-02-08 18:16:19 +010014406 goto nla_put_failure;
14407 }
14408
14409 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
14410 goto nla_put_failure;
14411
14412 if (nl80211_send_chandef(msg, chandef))
14413 goto nla_put_failure;
14414
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014415 genlmsg_end(msg, hdr);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014416
Johannes Berg68eb5502013-11-19 15:19:38 +010014417 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014418 NL80211_MCGRP_MLME, gfp);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014419 return;
14420
14421 nla_put_failure:
14422 genlmsg_cancel(msg, hdr);
14423 nlmsg_free(msg);
14424}
14425
Johannes Berg7f6cf312011-11-04 11:18:15 +010014426void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
14427 u64 cookie, bool acked, gfp_t gfp)
14428{
14429 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014430 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014431 struct sk_buff *msg;
14432 void *hdr;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014433
Beni Lev4ee3e062012-08-27 12:49:39 +030014434 trace_cfg80211_probe_status(dev, addr, cookie, acked);
14435
Thomas Graf58050fc2012-06-28 03:57:45 +000014436 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Beni Lev4ee3e062012-08-27 12:49:39 +030014437
Johannes Berg7f6cf312011-11-04 11:18:15 +010014438 if (!msg)
14439 return;
14440
14441 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
14442 if (!hdr) {
14443 nlmsg_free(msg);
14444 return;
14445 }
14446
David S. Miller9360ffd2012-03-29 04:41:26 -040014447 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14448 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14449 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014450 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14451 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014452 (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
14453 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014454
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014455 genlmsg_end(msg, hdr);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014456
Johannes Berg68eb5502013-11-19 15:19:38 +010014457 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014458 NL80211_MCGRP_MLME, gfp);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014459 return;
14460
14461 nla_put_failure:
14462 genlmsg_cancel(msg, hdr);
14463 nlmsg_free(msg);
14464}
14465EXPORT_SYMBOL(cfg80211_probe_status);
14466
Johannes Berg5e7602302011-11-04 11:18:17 +010014467void cfg80211_report_obss_beacon(struct wiphy *wiphy,
14468 const u8 *frame, size_t len,
Ben Greear37c73b52012-10-26 14:49:25 -070014469 int freq, int sig_dbm)
Johannes Berg5e7602302011-11-04 11:18:17 +010014470{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014471 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg5e7602302011-11-04 11:18:17 +010014472 struct sk_buff *msg;
14473 void *hdr;
Ben Greear37c73b52012-10-26 14:49:25 -070014474 struct cfg80211_beacon_registration *reg;
Johannes Berg5e7602302011-11-04 11:18:17 +010014475
Beni Lev4ee3e062012-08-27 12:49:39 +030014476 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
14477
Ben Greear37c73b52012-10-26 14:49:25 -070014478 spin_lock_bh(&rdev->beacon_registrations_lock);
14479 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
14480 msg = nlmsg_new(len + 100, GFP_ATOMIC);
14481 if (!msg) {
14482 spin_unlock_bh(&rdev->beacon_registrations_lock);
14483 return;
14484 }
Johannes Berg5e7602302011-11-04 11:18:17 +010014485
Ben Greear37c73b52012-10-26 14:49:25 -070014486 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
14487 if (!hdr)
14488 goto nla_put_failure;
Johannes Berg5e7602302011-11-04 11:18:17 +010014489
Ben Greear37c73b52012-10-26 14:49:25 -070014490 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14491 (freq &&
14492 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
14493 (sig_dbm &&
14494 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
14495 nla_put(msg, NL80211_ATTR_FRAME, len, frame))
14496 goto nla_put_failure;
14497
14498 genlmsg_end(msg, hdr);
14499
14500 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
Johannes Berg5e7602302011-11-04 11:18:17 +010014501 }
Ben Greear37c73b52012-10-26 14:49:25 -070014502 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e7602302011-11-04 11:18:17 +010014503 return;
14504
14505 nla_put_failure:
Ben Greear37c73b52012-10-26 14:49:25 -070014506 spin_unlock_bh(&rdev->beacon_registrations_lock);
14507 if (hdr)
14508 genlmsg_cancel(msg, hdr);
Johannes Berg5e7602302011-11-04 11:18:17 +010014509 nlmsg_free(msg);
14510}
14511EXPORT_SYMBOL(cfg80211_report_obss_beacon);
14512
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014513#ifdef CONFIG_PM
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014514static int cfg80211_net_detect_results(struct sk_buff *msg,
14515 struct cfg80211_wowlan_wakeup *wakeup)
14516{
14517 struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
14518 struct nlattr *nl_results, *nl_match, *nl_freqs;
14519 int i, j;
14520
14521 nl_results = nla_nest_start(
14522 msg, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
14523 if (!nl_results)
14524 return -EMSGSIZE;
14525
14526 for (i = 0; i < nd->n_matches; i++) {
14527 struct cfg80211_wowlan_nd_match *match = nd->matches[i];
14528
14529 nl_match = nla_nest_start(msg, i);
14530 if (!nl_match)
14531 break;
14532
14533 /* The SSID attribute is optional in nl80211, but for
14534 * simplicity reasons it's always present in the
14535 * cfg80211 structure. If a driver can't pass the
14536 * SSID, that needs to be changed. A zero length SSID
14537 * is still a valid SSID (wildcard), so it cannot be
14538 * used for this purpose.
14539 */
14540 if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
14541 match->ssid.ssid)) {
14542 nla_nest_cancel(msg, nl_match);
14543 goto out;
14544 }
14545
14546 if (match->n_channels) {
14547 nl_freqs = nla_nest_start(
14548 msg, NL80211_ATTR_SCAN_FREQUENCIES);
14549 if (!nl_freqs) {
14550 nla_nest_cancel(msg, nl_match);
14551 goto out;
14552 }
14553
14554 for (j = 0; j < match->n_channels; j++) {
Samuel Tan5528fae82015-02-09 21:29:15 +020014555 if (nla_put_u32(msg, j, match->channels[j])) {
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014556 nla_nest_cancel(msg, nl_freqs);
14557 nla_nest_cancel(msg, nl_match);
14558 goto out;
14559 }
14560 }
14561
14562 nla_nest_end(msg, nl_freqs);
14563 }
14564
14565 nla_nest_end(msg, nl_match);
14566 }
14567
14568out:
14569 nla_nest_end(msg, nl_results);
14570 return 0;
14571}
14572
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014573void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
14574 struct cfg80211_wowlan_wakeup *wakeup,
14575 gfp_t gfp)
14576{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014577 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014578 struct sk_buff *msg;
14579 void *hdr;
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014580 int size = 200;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014581
14582 trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
14583
14584 if (wakeup)
14585 size += wakeup->packet_present_len;
14586
14587 msg = nlmsg_new(size, gfp);
14588 if (!msg)
14589 return;
14590
14591 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
14592 if (!hdr)
14593 goto free_msg;
14594
14595 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014596 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14597 NL80211_ATTR_PAD))
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014598 goto free_msg;
14599
14600 if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14601 wdev->netdev->ifindex))
14602 goto free_msg;
14603
14604 if (wakeup) {
14605 struct nlattr *reasons;
14606
14607 reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Berg7fa322c2013-10-25 11:16:58 +020014608 if (!reasons)
14609 goto free_msg;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014610
14611 if (wakeup->disconnect &&
14612 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
14613 goto free_msg;
14614 if (wakeup->magic_pkt &&
14615 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
14616 goto free_msg;
14617 if (wakeup->gtk_rekey_failure &&
14618 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
14619 goto free_msg;
14620 if (wakeup->eap_identity_req &&
14621 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
14622 goto free_msg;
14623 if (wakeup->four_way_handshake &&
14624 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
14625 goto free_msg;
14626 if (wakeup->rfkill_release &&
14627 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
14628 goto free_msg;
14629
14630 if (wakeup->pattern_idx >= 0 &&
14631 nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
14632 wakeup->pattern_idx))
14633 goto free_msg;
14634
Johannes Bergae917c92013-10-25 11:05:22 +020014635 if (wakeup->tcp_match &&
14636 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
14637 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014638
Johannes Bergae917c92013-10-25 11:05:22 +020014639 if (wakeup->tcp_connlost &&
14640 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
14641 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014642
Johannes Bergae917c92013-10-25 11:05:22 +020014643 if (wakeup->tcp_nomoretokens &&
14644 nla_put_flag(msg,
14645 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
14646 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014647
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014648 if (wakeup->packet) {
14649 u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
14650 u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
14651
14652 if (!wakeup->packet_80211) {
14653 pkt_attr =
14654 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
14655 len_attr =
14656 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
14657 }
14658
14659 if (wakeup->packet_len &&
14660 nla_put_u32(msg, len_attr, wakeup->packet_len))
14661 goto free_msg;
14662
14663 if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
14664 wakeup->packet))
14665 goto free_msg;
14666 }
14667
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014668 if (wakeup->net_detect &&
14669 cfg80211_net_detect_results(msg, wakeup))
14670 goto free_msg;
14671
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014672 nla_nest_end(msg, reasons);
14673 }
14674
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014675 genlmsg_end(msg, hdr);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014676
Johannes Berg68eb5502013-11-19 15:19:38 +010014677 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014678 NL80211_MCGRP_MLME, gfp);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014679 return;
14680
14681 free_msg:
14682 nlmsg_free(msg);
14683}
14684EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
14685#endif
14686
Jouni Malinen3475b092012-11-16 22:49:57 +020014687void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
14688 enum nl80211_tdls_operation oper,
14689 u16 reason_code, gfp_t gfp)
14690{
14691 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014692 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Jouni Malinen3475b092012-11-16 22:49:57 +020014693 struct sk_buff *msg;
14694 void *hdr;
Jouni Malinen3475b092012-11-16 22:49:57 +020014695
14696 trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
14697 reason_code);
14698
14699 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14700 if (!msg)
14701 return;
14702
14703 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
14704 if (!hdr) {
14705 nlmsg_free(msg);
14706 return;
14707 }
14708
14709 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14710 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14711 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
14712 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
14713 (reason_code > 0 &&
14714 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
14715 goto nla_put_failure;
14716
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014717 genlmsg_end(msg, hdr);
Jouni Malinen3475b092012-11-16 22:49:57 +020014718
Johannes Berg68eb5502013-11-19 15:19:38 +010014719 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014720 NL80211_MCGRP_MLME, gfp);
Jouni Malinen3475b092012-11-16 22:49:57 +020014721 return;
14722
14723 nla_put_failure:
14724 genlmsg_cancel(msg, hdr);
14725 nlmsg_free(msg);
14726}
14727EXPORT_SYMBOL(cfg80211_tdls_oper_request);
14728
Jouni Malinen026331c2010-02-15 12:53:10 +020014729static int nl80211_netlink_notify(struct notifier_block * nb,
14730 unsigned long state,
14731 void *_notify)
14732{
14733 struct netlink_notify *notify = _notify;
14734 struct cfg80211_registered_device *rdev;
14735 struct wireless_dev *wdev;
Ben Greear37c73b52012-10-26 14:49:25 -070014736 struct cfg80211_beacon_registration *reg, *tmp;
Jouni Malinen026331c2010-02-15 12:53:10 +020014737
Dmitry Ivanov8f815cd2016-04-06 17:23:18 +030014738 if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
Jouni Malinen026331c2010-02-15 12:53:10 +020014739 return NOTIFY_DONE;
14740
14741 rcu_read_lock();
14742
Johannes Berg5e7602302011-11-04 11:18:17 +010014743 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
Johannes Berg78f22b62014-03-24 17:57:27 +010014744 bool schedule_destroy_work = false;
Jukka Rissanen93a1e862014-12-15 13:25:39 +020014745 struct cfg80211_sched_scan_request *sched_scan_req =
14746 rcu_dereference(rdev->sched_scan_req);
14747
14748 if (sched_scan_req && notify->portid &&
Johannes Berg0a28f532017-01-05 10:57:14 +010014749 sched_scan_req->owner_nlportid == notify->portid) {
14750 sched_scan_req->owner_nlportid = 0;
14751
14752 if (rdev->ops->sched_scan_stop &&
14753 rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
14754 schedule_work(&rdev->sched_scan_stop_wk);
14755 }
Johannes Berg78f22b62014-03-24 17:57:27 +010014756
Johannes Berg53873f12016-05-03 16:52:04 +030014757 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000014758 cfg80211_mlme_unregister_socket(wdev, notify->portid);
Ben Greear37c73b52012-10-26 14:49:25 -070014759
Johannes Berg78f22b62014-03-24 17:57:27 +010014760 if (wdev->owner_nlportid == notify->portid)
14761 schedule_destroy_work = true;
Andrzej Zaborowski5f3f4d32018-02-04 21:57:28 +053014762 else if (wdev->conn_owner_nlportid == notify->portid)
14763 schedule_work(&wdev->disconnect_wk);
Johannes Berg78f22b62014-03-24 17:57:27 +010014764 }
14765
Ben Greear37c73b52012-10-26 14:49:25 -070014766 spin_lock_bh(&rdev->beacon_registrations_lock);
14767 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
14768 list) {
14769 if (reg->nlportid == notify->portid) {
14770 list_del(&reg->list);
14771 kfree(reg);
14772 break;
14773 }
14774 }
14775 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg78f22b62014-03-24 17:57:27 +010014776
14777 if (schedule_destroy_work) {
14778 struct cfg80211_iface_destroy *destroy;
14779
14780 destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC);
14781 if (destroy) {
14782 destroy->nlportid = notify->portid;
14783 spin_lock(&rdev->destroy_list_lock);
14784 list_add(&destroy->list, &rdev->destroy_list);
14785 spin_unlock(&rdev->destroy_list_lock);
14786 schedule_work(&rdev->destroy_work);
14787 }
14788 }
Johannes Berg5e7602302011-11-04 11:18:17 +010014789 }
Jouni Malinen026331c2010-02-15 12:53:10 +020014790
14791 rcu_read_unlock();
14792
Ilan peer05050752015-03-04 00:32:06 -050014793 /*
14794 * It is possible that the user space process that is controlling the
14795 * indoor setting disappeared, so notify the regulatory core.
14796 */
14797 regulatory_netlink_notify(notify->portid);
Zhao, Gang6784c7d2014-04-21 12:53:04 +080014798 return NOTIFY_OK;
Jouni Malinen026331c2010-02-15 12:53:10 +020014799}
14800
14801static struct notifier_block nl80211_netlink_notifier = {
14802 .notifier_call = nl80211_netlink_notify,
14803};
14804
Jouni Malinen355199e2013-02-27 17:14:27 +020014805void cfg80211_ft_event(struct net_device *netdev,
14806 struct cfg80211_ft_event_params *ft_event)
14807{
14808 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014809 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinen355199e2013-02-27 17:14:27 +020014810 struct sk_buff *msg;
14811 void *hdr;
Jouni Malinen355199e2013-02-27 17:14:27 +020014812
14813 trace_cfg80211_ft_event(wiphy, netdev, ft_event);
14814
14815 if (!ft_event->target_ap)
14816 return;
14817
Johannes Berg14459722017-01-09 11:10:42 +010014818 msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
Jouni Malinen355199e2013-02-27 17:14:27 +020014819 if (!msg)
14820 return;
14821
14822 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
Johannes Bergae917c92013-10-25 11:05:22 +020014823 if (!hdr)
14824 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020014825
Johannes Bergae917c92013-10-25 11:05:22 +020014826 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14827 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14828 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
14829 goto out;
14830
14831 if (ft_event->ies &&
14832 nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
14833 goto out;
14834 if (ft_event->ric_ies &&
14835 nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
14836 ft_event->ric_ies))
14837 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020014838
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014839 genlmsg_end(msg, hdr);
Jouni Malinen355199e2013-02-27 17:14:27 +020014840
Johannes Berg68eb5502013-11-19 15:19:38 +010014841 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014842 NL80211_MCGRP_MLME, GFP_KERNEL);
Johannes Bergae917c92013-10-25 11:05:22 +020014843 return;
14844 out:
14845 nlmsg_free(msg);
Jouni Malinen355199e2013-02-27 17:14:27 +020014846}
14847EXPORT_SYMBOL(cfg80211_ft_event);
14848
Arend van Spriel5de17982013-04-18 15:49:00 +020014849void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
14850{
14851 struct cfg80211_registered_device *rdev;
14852 struct sk_buff *msg;
14853 void *hdr;
14854 u32 nlportid;
14855
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014856 rdev = wiphy_to_rdev(wdev->wiphy);
Arend van Spriel5de17982013-04-18 15:49:00 +020014857 if (!rdev->crit_proto_nlportid)
14858 return;
14859
14860 nlportid = rdev->crit_proto_nlportid;
14861 rdev->crit_proto_nlportid = 0;
14862
14863 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14864 if (!msg)
14865 return;
14866
14867 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
14868 if (!hdr)
14869 goto nla_put_failure;
14870
14871 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014872 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14873 NL80211_ATTR_PAD))
Arend van Spriel5de17982013-04-18 15:49:00 +020014874 goto nla_put_failure;
14875
14876 genlmsg_end(msg, hdr);
14877
14878 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
14879 return;
14880
14881 nla_put_failure:
14882 if (hdr)
14883 genlmsg_cancel(msg, hdr);
14884 nlmsg_free(msg);
Arend van Spriel5de17982013-04-18 15:49:00 +020014885}
14886EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
14887
Sameer Thalappilfaa4c4a2013-07-05 14:58:32 -070014888void cfg80211_ap_stopped(struct net_device *netdev, gfp_t gfp)
14889{
14890 struct wireless_dev *wdev = netdev->ieee80211_ptr;
14891 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
14892
14893 nl80211_send_mlme_event(rdev, netdev, NULL, 0,
14894 NL80211_CMD_STOP_AP, gfp, -1);
14895}
14896EXPORT_SYMBOL(cfg80211_ap_stopped);
14897
Johannes Berg348baf02014-01-24 14:06:29 +010014898void nl80211_send_ap_stopped(struct wireless_dev *wdev)
14899{
14900 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014901 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg348baf02014-01-24 14:06:29 +010014902 struct sk_buff *msg;
14903 void *hdr;
14904
14905 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14906 if (!msg)
14907 return;
14908
14909 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
14910 if (!hdr)
14911 goto out;
14912
14913 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14914 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014915 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14916 NL80211_ATTR_PAD))
Johannes Berg348baf02014-01-24 14:06:29 +010014917 goto out;
14918
14919 genlmsg_end(msg, hdr);
14920
14921 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
14922 NL80211_MCGRP_MLME, GFP_KERNEL);
14923 return;
14924 out:
14925 nlmsg_free(msg);
14926}
14927
Johannes Berg55682962007-09-20 13:09:35 -040014928/* initialisation/exit functions */
14929
14930int nl80211_init(void)
14931{
Michał Mirosław0d63cbb2009-05-21 10:34:06 +000014932 int err;
Johannes Berg55682962007-09-20 13:09:35 -040014933
Johannes Berg2a94fe42013-11-19 15:19:39 +010014934 err = genl_register_family_with_ops_groups(&nl80211_fam, nl80211_ops,
14935 nl80211_mcgrps);
Johannes Berg55682962007-09-20 13:09:35 -040014936 if (err)
14937 return err;
14938
Jouni Malinen026331c2010-02-15 12:53:10 +020014939 err = netlink_register_notifier(&nl80211_netlink_notifier);
14940 if (err)
14941 goto err_out;
14942
Johannes Berg55682962007-09-20 13:09:35 -040014943 return 0;
14944 err_out:
14945 genl_unregister_family(&nl80211_fam);
14946 return err;
14947}
14948
14949void nl80211_exit(void)
14950{
Jouni Malinen026331c2010-02-15 12:53:10 +020014951 netlink_unregister_notifier(&nl80211_netlink_notifier);
Johannes Berg55682962007-09-20 13:09:35 -040014952 genl_unregister_family(&nl80211_fam);
14953}