nl80211.c 314.9 KB
Newer Older
1 2 3
/*
 * This is the new netlink-based wireless configuration interface.
 *
4
 * Copyright 2006-2010	Johannes Berg <johannes@sipsolutions.net>
5 6 7 8 9
 */

#include <linux/if.h>
#include <linux/module.h>
#include <linux/err.h>
10
#include <linux/slab.h>
11 12 13 14 15 16
#include <linux/list.h>
#include <linux/if_ether.h>
#include <linux/ieee80211.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
17
#include <linux/etherdevice.h>
18
#include <net/net_namespace.h>
19 20
#include <net/genetlink.h>
#include <net/cfg80211.h>
21
#include <net/sock.h>
22
#include <net/inet_connection_sock.h>
23 24
#include "core.h"
#include "nl80211.h"
25
#include "reg.h"
26
#include "rdev-ops.h"
27

28 29 30 31 32
static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
				   struct genl_info *info,
				   struct cfg80211_crypto_settings *settings,
				   int cipher_limit);

J
Johannes Berg 已提交
33
static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
34
			    struct genl_info *info);
J
Johannes Berg 已提交
35
static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
36 37
			      struct genl_info *info);

38 39
/* the netlink family */
static struct genl_family nl80211_fam = {
40 41 42 43
	.id = GENL_ID_GENERATE,		/* don't bother with a hardcoded ID */
	.name = NL80211_GENL_NAME,	/* have users key off the name instead */
	.hdrsize = 0,			/* no private header */
	.version = 1,			/* no particular meaning now */
44
	.maxattr = NL80211_ATTR_MAX,
45
	.netnsok = true,
46 47
	.pre_doit = nl80211_pre_doit,
	.post_doit = nl80211_post_doit,
48 49
};

50 51 52 53 54 55
/* multicast groups */
enum nl80211_multicast_groups {
	NL80211_MCGRP_CONFIG,
	NL80211_MCGRP_SCAN,
	NL80211_MCGRP_REGULATORY,
	NL80211_MCGRP_MLME,
56
	NL80211_MCGRP_VENDOR,
57 58 59 60 61 62 63 64
	NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
};

static const struct genl_multicast_group nl80211_mcgrps[] = {
	[NL80211_MCGRP_CONFIG] = { .name = "config", },
	[NL80211_MCGRP_SCAN] = { .name = "scan", },
	[NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
	[NL80211_MCGRP_MLME] = { .name = "mlme", },
65
	[NL80211_MCGRP_VENDOR] = { .name = "vendor", },
66 67 68 69 70
#ifdef CONFIG_NL80211_TESTMODE
	[NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
#endif
};

71 72 73
/* returns ERR_PTR values */
static struct wireless_dev *
__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
74
{
75 76 77 78 79 80 81
	struct cfg80211_registered_device *rdev;
	struct wireless_dev *result = NULL;
	bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
	bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
	u64 wdev_id;
	int wiphy_idx = -1;
	int ifidx = -1;
82

83
	ASSERT_RTNL();
84

85 86
	if (!have_ifidx && !have_wdev_id)
		return ERR_PTR(-EINVAL);
87

88 89 90 91 92
	if (have_ifidx)
		ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
	if (have_wdev_id) {
		wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
		wiphy_idx = wdev_id >> 32;
93 94
	}

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
		struct wireless_dev *wdev;

		if (wiphy_net(&rdev->wiphy) != netns)
			continue;

		if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
			continue;

		list_for_each_entry(wdev, &rdev->wdev_list, list) {
			if (have_ifidx && wdev->netdev &&
			    wdev->netdev->ifindex == ifidx) {
				result = wdev;
				break;
			}
			if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
				result = wdev;
				break;
			}
		}

		if (result)
			break;
	}

	if (result)
		return result;
	return ERR_PTR(-ENODEV);
123 124
}

125
static struct cfg80211_registered_device *
126
__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
127
{
128 129
	struct cfg80211_registered_device *rdev = NULL, *tmp;
	struct net_device *netdev;
130

131
	ASSERT_RTNL();
132

133
	if (!attrs[NL80211_ATTR_WIPHY] &&
134 135
	    !attrs[NL80211_ATTR_IFINDEX] &&
	    !attrs[NL80211_ATTR_WDEV])
136 137
		return ERR_PTR(-EINVAL);

138
	if (attrs[NL80211_ATTR_WIPHY])
139
		rdev = cfg80211_rdev_by_wiphy_idx(
140
				nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
141

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
	if (attrs[NL80211_ATTR_WDEV]) {
		u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
		struct wireless_dev *wdev;
		bool found = false;

		tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
		if (tmp) {
			/* make sure wdev exists */
			list_for_each_entry(wdev, &tmp->wdev_list, list) {
				if (wdev->identifier != (u32)wdev_id)
					continue;
				found = true;
				break;
			}

			if (!found)
				tmp = NULL;

			if (rdev && tmp != rdev)
				return ERR_PTR(-EINVAL);
			rdev = tmp;
		}
	}

166 167
	if (attrs[NL80211_ATTR_IFINDEX]) {
		int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
168
		netdev = __dev_get_by_index(netns, ifindex);
169 170
		if (netdev) {
			if (netdev->ieee80211_ptr)
171 172
				tmp = wiphy_to_rdev(
					netdev->ieee80211_ptr->wiphy);
173 174 175 176 177 178 179 180 181 182 183 184
			else
				tmp = NULL;

			/* not wireless device -- return error */
			if (!tmp)
				return ERR_PTR(-EINVAL);

			/* mismatch -- return error */
			if (rdev && tmp != rdev)
				return ERR_PTR(-EINVAL);

			rdev = tmp;
185 186 187
		}
	}

J
Johannes Berg 已提交
188 189
	if (!rdev)
		return ERR_PTR(-ENODEV);
190

J
Johannes Berg 已提交
191 192 193 194
	if (netns != wiphy_net(&rdev->wiphy))
		return ERR_PTR(-ENODEV);

	return rdev;
195 196 197 198 199 200 201 202 203 204
}

/*
 * This function returns a pointer to the driver
 * that the genl_info item that is passed refers to.
 *
 * The result of this can be a PTR_ERR and hence must
 * be checked with IS_ERR() for errors.
 */
static struct cfg80211_registered_device *
J
Johannes Berg 已提交
205
cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
206
{
207
	return __cfg80211_rdev_from_attrs(netns, info->attrs);
208 209
}

210
/* policy for the attributes */
A
Alexey Dobriyan 已提交
211
static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
212 213
	[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
	[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
214
				      .len = 20-1 },
215
	[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
216

217
	[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
S
Sujith 已提交
218
	[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
219 220 221 222
	[NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
	[NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
	[NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },

223 224 225 226
	[NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
	[NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
	[NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
	[NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
227
	[NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
228 229 230 231

	[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
	[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
232

E
Eliad Peller 已提交
233 234
	[NL80211_ATTR_MAC] = { .len = ETH_ALEN },
	[NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN },
235

236
	[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
237 238 239 240 241
	[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
				    .len = WLAN_MAX_KEY_LEN },
	[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
	[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
	[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
242
	[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
243
	[NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
244 245 246 247 248 249 250

	[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
	[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
	[NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
				       .len = IEEE80211_MAX_DATA_LEN },
	[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
				       .len = IEEE80211_MAX_DATA_LEN },
251 252 253 254 255
	[NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
	[NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
	[NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
	[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
					       .len = NL80211_MAX_SUPP_RATES },
256
	[NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
257
	[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
J
Johannes Berg 已提交
258
	[NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
259
	[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
260
				   .len = IEEE80211_MAX_MESH_ID_LEN },
261
	[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
262

263 264 265
	[NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
	[NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },

266 267 268
	[NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
	[NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
	[NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
269 270
	[NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
					   .len = NL80211_MAX_SUPP_RATES },
271
	[NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },
272

273
	[NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
274
	[NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
275

276
	[NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN },
277 278 279 280

	[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
	[NL80211_ATTR_IE] = { .type = NLA_BINARY,
			      .len = IEEE80211_MAX_DATA_LEN },
281 282
	[NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
	[NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
283 284 285 286 287

	[NL80211_ATTR_SSID] = { .type = NLA_BINARY,
				.len = IEEE80211_MAX_SSID_LEN },
	[NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
	[NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
J
Johannes Berg 已提交
288
	[NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
289
	[NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
290
	[NL80211_ATTR_USE_MFP] = { .type = NLA_U32 },
291 292 293
	[NL80211_ATTR_STA_FLAGS2] = {
		.len = sizeof(struct nl80211_sta_flag_update),
	},
294
	[NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
295 296
	[NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
	[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
S
Samuel Ortiz 已提交
297 298 299
	[NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
	[NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
	[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
300
	[NL80211_ATTR_PID] = { .type = NLA_U32 },
301
	[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
S
Samuel Ortiz 已提交
302 303
	[NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
				 .len = WLAN_PMKID_LEN },
304 305
	[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
	[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
306
	[NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
307 308 309
	[NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
				 .len = IEEE80211_MAX_DATA_LEN },
	[NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
K
Kalle Valo 已提交
310
	[NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
311
	[NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
312
	[NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
313
	[NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
314 315
	[NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
	[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
316
	[NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
317 318
	[NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
	[NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
319
	[NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
320
	[NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
321
	[NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
J
Johannes Berg 已提交
322
	[NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
323
	[NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
324
	[NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
325
	[NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
326
	[NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
327
	[NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
328 329 330 331
	[NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
					 .len = IEEE80211_MAX_DATA_LEN },
	[NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
					 .len = IEEE80211_MAX_DATA_LEN },
332
	[NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
333
	[NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
334
	[NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
335 336 337 338 339
	[NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
	[NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
	[NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
	[NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
	[NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
340
	[NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
341
	[NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
342 343
	[NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
				      .len = IEEE80211_MAX_DATA_LEN },
344
	[NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
345 346 347 348
	[NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
	[NL80211_ATTR_HT_CAPABILITY_MASK] = {
		.len = NL80211_HT_CAPABILITY_LEN
	},
349
	[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
350
	[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
351
	[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
352
	[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
353
	[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
354
	[NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
M
Mahesh Palivela 已提交
355
	[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
356
	[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
357 358
	[NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
	[NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
359 360
	[NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
	[NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
361 362
	[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
	[NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
363
	[NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
364 365 366 367
	[NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
	[NL80211_ATTR_VHT_CAPABILITY_MASK] = {
		.len = NL80211_VHT_CAPABILITY_LEN,
	},
368 369 370
	[NL80211_ATTR_MDID] = { .type = NLA_U16 },
	[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
				  .len = IEEE80211_MAX_DATA_LEN },
371
	[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
372 373 374
	[NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
	[NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
	[NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
375 376
	[NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY },
	[NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY },
377 378
	[NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
	[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
379
	[NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
380
	[NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
J
Johannes Berg 已提交
381 382 383
	[NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
	[NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
	[NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
384 385
	[NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
				   .len = IEEE80211_QOS_MAP_LEN_MAX },
386 387
	[NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
	[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
388
	[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
389
	[NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
390
	[NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
391 392
};

393
/* policy for the key attributes */
A
Alexey Dobriyan 已提交
394
static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
J
Johannes Berg 已提交
395
	[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
396 397
	[NL80211_KEY_IDX] = { .type = NLA_U8 },
	[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
398
	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
399 400
	[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
	[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
401
	[NL80211_KEY_TYPE] = { .type = NLA_U32 },
402 403 404 405 406 407 408 409
	[NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
};

/* policy for the key default flags */
static const struct nla_policy
nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
	[NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
	[NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
410 411
};

J
Johannes Berg 已提交
412 413 414 415 416 417 418
/* policy for WoWLAN attributes */
static const struct nla_policy
nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
	[NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
	[NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
	[NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
	[NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
419 420 421 422
	[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
	[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
	[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
	[NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
	[NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
};

static const struct nla_policy
nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
	[NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
	[NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
	[NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN },
	[NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
	[NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
	[NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 },
	[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
		.len = sizeof(struct nl80211_wowlan_tcp_data_seq)
	},
	[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
		.len = sizeof(struct nl80211_wowlan_tcp_data_token)
	},
	[NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
	[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
	[NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
J
Johannes Berg 已提交
443 444
};

445 446 447 448 449 450 451 452
/* policy for coalesce rule attributes */
static const struct nla_policy
nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
	[NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
	[NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
	[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
};

453 454 455 456 457 458 459 460
/* policy for GTK rekey offload attributes */
static const struct nla_policy
nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
	[NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
	[NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
	[NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
};

461 462
static const struct nla_policy
nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
463
	[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
464
						 .len = IEEE80211_MAX_SSID_LEN },
465
	[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
466 467
};

468 469 470 471
static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
				     struct netlink_callback *cb,
				     struct cfg80211_registered_device **rdev,
				     struct wireless_dev **wdev)
472
{
473
	int err;
474

475
	rtnl_lock();
476

477 478 479 480 481 482
	if (!cb->args[0]) {
		err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
				  nl80211_fam.attrbuf, nl80211_fam.maxattr,
				  nl80211_policy);
		if (err)
			goto out_unlock;
483

484 485 486 487 488 489
		*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
						   nl80211_fam.attrbuf);
		if (IS_ERR(*wdev)) {
			err = PTR_ERR(*wdev);
			goto out_unlock;
		}
490
		*rdev = wiphy_to_rdev((*wdev)->wiphy);
491 492
		/* 0 is the first index - add 1 to parse only once */
		cb->args[0] = (*rdev)->wiphy_idx + 1;
493 494
		cb->args[1] = (*wdev)->identifier;
	} else {
495 496
		/* subtract the 1 again here */
		struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
497
		struct wireless_dev *tmp;
498

499 500 501 502
		if (!wiphy) {
			err = -ENODEV;
			goto out_unlock;
		}
503
		*rdev = wiphy_to_rdev(wiphy);
504
		*wdev = NULL;
505

506 507 508 509 510 511
		list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
			if (tmp->identifier == cb->args[1]) {
				*wdev = tmp;
				break;
			}
		}
512

513 514 515 516
		if (!*wdev) {
			err = -ENODEV;
			goto out_unlock;
		}
517 518 519
	}

	return 0;
520
 out_unlock:
521 522 523 524
	rtnl_unlock();
	return err;
}

525
static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
526 527 528 529
{
	rtnl_unlock();
}

530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
/* IE validation */
static bool is_valid_ie_attr(const struct nlattr *attr)
{
	const u8 *pos;
	int len;

	if (!attr)
		return true;

	pos = nla_data(attr);
	len = nla_len(attr);

	while (len) {
		u8 elemlen;

		if (len < 2)
			return false;
		len -= 2;

		elemlen = pos[1];
		if (elemlen > len)
			return false;

		len -= elemlen;
		pos += 2 + elemlen;
	}

	return true;
}

560
/* message building helper */
561
static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
562 563 564
				   int flags, u8 cmd)
{
	/* since there is no private header just add the generic one */
565
	return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
566 567
}

568
static int nl80211_msg_put_channel(struct sk_buff *msg,
569 570
				   struct ieee80211_channel *chan,
				   bool large)
571
{
572 573 574 575 576 577 578
	/* Some channels must be completely excluded from the
	 * list to protect old user-space tools from breaking
	 */
	if (!large && chan->flags &
	    (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
		return 0;

579 580 581
	if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
			chan->center_freq))
		goto nla_put_failure;
582

583 584 585
	if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
	    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
		goto nla_put_failure;
586 587 588 589 590 591
	if (chan->flags & IEEE80211_CHAN_NO_IR) {
		if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
			goto nla_put_failure;
		if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
			goto nla_put_failure;
	}
592 593 594 595 596 597 598 599 600 601 602 603 604 605
	if (chan->flags & IEEE80211_CHAN_RADAR) {
		if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
			goto nla_put_failure;
		if (large) {
			u32 time;

			time = elapsed_jiffies_msecs(chan->dfs_state_entered);

			if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
					chan->dfs_state))
				goto nla_put_failure;
			if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
					time))
				goto nla_put_failure;
606 607 608 609
			if (nla_put_u32(msg,
					NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
					chan->dfs_cac_ms))
				goto nla_put_failure;
610 611
		}
	}
612

613 614 615 616 617 618 619 620 621 622 623 624 625
	if (large) {
		if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
		    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
			goto nla_put_failure;
		if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
		    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
			goto nla_put_failure;
		if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
		    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
			goto nla_put_failure;
		if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
		    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
			goto nla_put_failure;
626 627 628 629 630 631
		if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
		    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
			goto nla_put_failure;
		if ((chan->flags & IEEE80211_CHAN_GO_CONCURRENT) &&
		    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_GO_CONCURRENT))
			goto nla_put_failure;
632 633 634 635 636 637
		if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
		    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
			goto nla_put_failure;
		if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
		    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
			goto nla_put_failure;
638 639
	}

640 641 642
	if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
			DBM_TO_MBM(chan->max_power)))
		goto nla_put_failure;
643 644 645 646 647 648 649

	return 0;

 nla_put_failure:
	return -ENOBUFS;
}

650 651
/* netlink command implementations */

652 653 654
struct key_parse {
	struct key_params p;
	int idx;
655
	int type;
656
	bool def, defmgmt;
657
	bool def_uni, def_multi;
658 659 660 661 662 663 664 665 666 667 668 669 670
};

static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
{
	struct nlattr *tb[NL80211_KEY_MAX + 1];
	int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
				   nl80211_key_policy);
	if (err)
		return err;

	k->def = !!tb[NL80211_KEY_DEFAULT];
	k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];

671 672 673 674 675 676 677
	if (k->def) {
		k->def_uni = true;
		k->def_multi = true;
	}
	if (k->defmgmt)
		k->def_multi = true;

678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
	if (tb[NL80211_KEY_IDX])
		k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);

	if (tb[NL80211_KEY_DATA]) {
		k->p.key = nla_data(tb[NL80211_KEY_DATA]);
		k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
	}

	if (tb[NL80211_KEY_SEQ]) {
		k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
		k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
	}

	if (tb[NL80211_KEY_CIPHER])
		k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);

694 695 696 697 698 699
	if (tb[NL80211_KEY_TYPE]) {
		k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
		if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
			return -EINVAL;
	}

700 701
	if (tb[NL80211_KEY_DEFAULT_TYPES]) {
		struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
702 703 704
		err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
				       tb[NL80211_KEY_DEFAULT_TYPES],
				       nl80211_key_default_policy);
705 706 707 708 709 710 711
		if (err)
			return err;

		k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
		k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
	}

712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
	return 0;
}

static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
{
	if (info->attrs[NL80211_ATTR_KEY_DATA]) {
		k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
		k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
	}

	if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
		k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
		k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
	}

	if (info->attrs[NL80211_ATTR_KEY_IDX])
		k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);

	if (info->attrs[NL80211_ATTR_KEY_CIPHER])
		k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);

	k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
	k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];

736 737 738 739 740 741 742
	if (k->def) {
		k->def_uni = true;
		k->def_multi = true;
	}
	if (k->defmgmt)
		k->def_multi = true;

743 744 745 746 747 748
	if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
		k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
		if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
			return -EINVAL;
	}

749 750 751 752 753 754 755 756 757 758 759 760 761
	if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
		struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
		int err = nla_parse_nested(
				kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
				info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
				nl80211_key_default_policy);
		if (err)
			return err;

		k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
		k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
	}

762 763 764 765 766 767 768 769 770
	return 0;
}

static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
{
	int err;

	memset(k, 0, sizeof(*k));
	k->idx = -1;
771
	k->type = -1;
772 773 774 775 776 777 778 779 780 781 782 783

	if (info->attrs[NL80211_ATTR_KEY])
		err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
	else
		err = nl80211_parse_key_old(info, k);

	if (err)
		return err;

	if (k->def && k->defmgmt)
		return -EINVAL;

784 785 786 787 788
	if (k->defmgmt) {
		if (k->def_uni || !k->def_multi)
			return -EINVAL;
	}

789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
	if (k->idx != -1) {
		if (k->defmgmt) {
			if (k->idx < 4 || k->idx > 5)
				return -EINVAL;
		} else if (k->def) {
			if (k->idx < 0 || k->idx > 3)
				return -EINVAL;
		} else {
			if (k->idx < 0 || k->idx > 5)
				return -EINVAL;
		}
	}

	return 0;
}

J
Johannes Berg 已提交
805 806
static struct cfg80211_cached_keys *
nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
807
		       struct nlattr *keys, bool *no_ht)
J
Johannes Berg 已提交
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
{
	struct key_parse parse;
	struct nlattr *key;
	struct cfg80211_cached_keys *result;
	int rem, err, def = 0;

	result = kzalloc(sizeof(*result), GFP_KERNEL);
	if (!result)
		return ERR_PTR(-ENOMEM);

	result->def = -1;
	result->defmgmt = -1;

	nla_for_each_nested(key, keys, rem) {
		memset(&parse, 0, sizeof(parse));
		parse.idx = -1;

		err = nl80211_parse_key_new(key, &parse);
		if (err)
			goto error;
		err = -EINVAL;
		if (!parse.p.key)
			goto error;
		if (parse.idx < 0 || parse.idx > 4)
			goto error;
		if (parse.def) {
			if (def)
				goto error;
			def = 1;
			result->def = parse.idx;
838 839
			if (!parse.def_uni || !parse.def_multi)
				goto error;
J
Johannes Berg 已提交
840 841 842
		} else if (parse.defmgmt)
			goto error;
		err = cfg80211_validate_key_settings(rdev, &parse.p,
843
						     parse.idx, false, NULL);
J
Johannes Berg 已提交
844 845 846 847 848 849
		if (err)
			goto error;
		result->params[parse.idx].cipher = parse.p.cipher;
		result->params[parse.idx].key_len = parse.p.key_len;
		result->params[parse.idx].key = result->data[parse.idx];
		memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
850 851 852 853 854 855

		if (parse.p.cipher == WLAN_CIPHER_SUITE_WEP40 ||
		    parse.p.cipher == WLAN_CIPHER_SUITE_WEP104) {
			if (no_ht)
				*no_ht = true;
		}
J
Johannes Berg 已提交
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
	}

	return result;
 error:
	kfree(result);
	return ERR_PTR(err);
}

static int nl80211_key_allowed(struct wireless_dev *wdev)
{
	ASSERT_WDEV_LOCK(wdev);

	switch (wdev->iftype) {
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
871
	case NL80211_IFTYPE_P2P_GO:
872
	case NL80211_IFTYPE_MESH_POINT:
J
Johannes Berg 已提交
873 874 875
		break;
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_STATION:
876
	case NL80211_IFTYPE_P2P_CLIENT:
877
		if (!wdev->current_bss)
J
Johannes Berg 已提交
878 879 880 881 882 883 884 885 886
			return -ENOLINK;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

887 888 889 890 891 892 893 894 895 896 897 898 899
static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
							struct nlattr *tb)
{
	struct ieee80211_channel *chan;

	if (tb == NULL)
		return NULL;
	chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
	if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
		return NULL;
	return chan;
}

900 901 902 903 904 905 906 907 908 909
static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
{
	struct nlattr *nl_modes = nla_nest_start(msg, attr);
	int i;

	if (!nl_modes)
		goto nla_put_failure;

	i = 0;
	while (ifmodes) {
910 911
		if ((ifmodes & 1) && nla_put_flag(msg, i))
			goto nla_put_failure;
912 913 914 915 916 917 918 919 920 921 922 923
		ifmodes >>= 1;
		i++;
	}

	nla_nest_end(msg, nl_modes);
	return 0;

nla_put_failure:
	return -ENOBUFS;
}

static int nl80211_put_iface_combinations(struct wiphy *wiphy,
924 925
					  struct sk_buff *msg,
					  bool large)
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
{
	struct nlattr *nl_combis;
	int i, j;

	nl_combis = nla_nest_start(msg,
				NL80211_ATTR_INTERFACE_COMBINATIONS);
	if (!nl_combis)
		goto nla_put_failure;

	for (i = 0; i < wiphy->n_iface_combinations; i++) {
		const struct ieee80211_iface_combination *c;
		struct nlattr *nl_combi, *nl_limits;

		c = &wiphy->iface_combinations[i];

		nl_combi = nla_nest_start(msg, i + 1);
		if (!nl_combi)
			goto nla_put_failure;

		nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS);
		if (!nl_limits)
			goto nla_put_failure;

		for (j = 0; j < c->n_limits; j++) {
			struct nlattr *nl_limit;

			nl_limit = nla_nest_start(msg, j + 1);
			if (!nl_limit)
				goto nla_put_failure;
955 956 957
			if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
					c->limits[j].max))
				goto nla_put_failure;
958 959 960 961 962 963 964 965
			if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
						c->limits[j].types))
				goto nla_put_failure;
			nla_nest_end(msg, nl_limit);
		}

		nla_nest_end(msg, nl_limits);

966 967 968 969 970 971 972 973
		if (c->beacon_int_infra_match &&
		    nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
			goto nla_put_failure;
		if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
				c->num_different_channels) ||
		    nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
				c->max_interfaces))
			goto nla_put_failure;
974
		if (large &&
975 976 977 978
		    (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
				c->radar_detect_widths) ||
		     nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
				c->radar_detect_regions)))
979
			goto nla_put_failure;
980 981 982 983 984 985 986 987 988 989 990

		nla_nest_end(msg, nl_combi);
	}

	nla_nest_end(msg, nl_combis);

	return 0;
nla_put_failure:
	return -ENOBUFS;
}

991
#ifdef CONFIG_PM
992 993 994
static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
					struct sk_buff *msg)
{
995
	const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
	struct nlattr *nl_tcp;

	if (!tcp)
		return 0;

	nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
	if (!nl_tcp)
		return -ENOBUFS;

	if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
			tcp->data_payload_max))
		return -ENOBUFS;

	if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
			tcp->data_payload_max))
		return -ENOBUFS;

	if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
		return -ENOBUFS;

	if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
				sizeof(*tcp->tok), tcp->tok))
		return -ENOBUFS;

	if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
			tcp->data_interval_max))
		return -ENOBUFS;

	if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
			tcp->wake_payload_max))
		return -ENOBUFS;

	nla_nest_end(msg, nl_tcp);
	return 0;
}

1032
static int nl80211_send_wowlan(struct sk_buff *msg,
1033
			       struct cfg80211_registered_device *rdev,
1034
			       bool large)
1035
{
1036
	struct nlattr *nl_wowlan;
1037

1038
	if (!rdev->wiphy.wowlan)
1039
		return 0;
1040

1041 1042 1043
	nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
	if (!nl_wowlan)
		return -ENOBUFS;
1044

1045
	if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
1046
	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
1047
	    ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
1048
	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
1049
	    ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
1050
	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
1051
	    ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
1052
	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
1053
	    ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
1054
	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
1055
	    ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
1056
	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
1057
	    ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
1058
	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
1059
	    ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
1060 1061
	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
		return -ENOBUFS;
1062

1063
	if (rdev->wiphy.wowlan->n_patterns) {
1064
		struct nl80211_pattern_support pat = {
1065 1066 1067 1068
			.max_patterns = rdev->wiphy.wowlan->n_patterns,
			.min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
			.max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
			.max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
1069
		};
1070

1071 1072 1073 1074
		if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
			    sizeof(pat), &pat))
			return -ENOBUFS;
	}
1075

1076
	if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
1077 1078
		return -ENOBUFS;

1079
	nla_nest_end(msg, nl_wowlan);
1080

1081 1082 1083
	return 0;
}
#endif
1084

1085
static int nl80211_send_coalesce(struct sk_buff *msg,
1086
				 struct cfg80211_registered_device *rdev)
1087 1088 1089
{
	struct nl80211_coalesce_rule_support rule;

1090
	if (!rdev->wiphy.coalesce)
1091 1092
		return 0;

1093 1094 1095 1096 1097 1098
	rule.max_rules = rdev->wiphy.coalesce->n_rules;
	rule.max_delay = rdev->wiphy.coalesce->max_delay;
	rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
	rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
	rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
	rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
1099 1100 1101 1102 1103 1104 1105

	if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
		return -ENOBUFS;

	return 0;
}

1106 1107 1108 1109 1110 1111
static int nl80211_send_band_rateinfo(struct sk_buff *msg,
				      struct ieee80211_supported_band *sband)
{
	struct nlattr *nl_rates, *nl_rate;
	struct ieee80211_rate *rate;
	int i;
1112

1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
	/* add HT info */
	if (sband->ht_cap.ht_supported &&
	    (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
		     sizeof(sband->ht_cap.mcs),
		     &sband->ht_cap.mcs) ||
	     nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
			 sband->ht_cap.cap) ||
	     nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
			sband->ht_cap.ampdu_factor) ||
	     nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
			sband->ht_cap.ampdu_density)))
		return -ENOBUFS;
1125

1126 1127 1128 1129 1130 1131 1132 1133
	/* add VHT info */
	if (sband->vht_cap.vht_supported &&
	    (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
		     sizeof(sband->vht_cap.vht_mcs),
		     &sband->vht_cap.vht_mcs) ||
	     nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
			 sband->vht_cap.cap)))
		return -ENOBUFS;
1134

1135 1136 1137 1138
	/* add bitrates */
	nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
	if (!nl_rates)
		return -ENOBUFS;
1139

1140 1141 1142 1143
	for (i = 0; i < sband->n_bitrates; i++) {
		nl_rate = nla_nest_start(msg, i);
		if (!nl_rate)
			return -ENOBUFS;
1144

1145 1146 1147 1148 1149 1150 1151 1152
		rate = &sband->bitrates[i];
		if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
				rate->bitrate))
			return -ENOBUFS;
		if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
		    nla_put_flag(msg,
				 NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
			return -ENOBUFS;
1153

1154 1155
		nla_nest_end(msg, nl_rate);
	}
J
Johannes Berg 已提交
1156

1157
	nla_nest_end(msg, nl_rates);
1158

1159 1160
	return 0;
}
1161

1162 1163 1164 1165 1166 1167 1168 1169
static int
nl80211_send_mgmt_stypes(struct sk_buff *msg,
			 const struct ieee80211_txrx_stypes *mgmt_stypes)
{
	u16 stypes;
	struct nlattr *nl_ftypes, *nl_ifs;
	enum nl80211_iftype ift;
	int i;
1170

1171 1172
	if (!mgmt_stypes)
		return 0;
1173

1174 1175 1176
	nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
	if (!nl_ifs)
		return -ENOBUFS;
1177

1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
	for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
		nl_ftypes = nla_nest_start(msg, ift);
		if (!nl_ftypes)
			return -ENOBUFS;
		i = 0;
		stypes = mgmt_stypes[ift].tx;
		while (stypes) {
			if ((stypes & 1) &&
			    nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
					(i << 4) | IEEE80211_FTYPE_MGMT))
				return -ENOBUFS;
			stypes >>= 1;
			i++;
1191
		}
1192 1193
		nla_nest_end(msg, nl_ftypes);
	}
1194

1195
	nla_nest_end(msg, nl_ifs);
1196

1197 1198 1199
	nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
	if (!nl_ifs)
		return -ENOBUFS;
1200

1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
	for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
		nl_ftypes = nla_nest_start(msg, ift);
		if (!nl_ftypes)
			return -ENOBUFS;
		i = 0;
		stypes = mgmt_stypes[ift].rx;
		while (stypes) {
			if ((stypes & 1) &&
			    nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
					(i << 4) | IEEE80211_FTYPE_MGMT))
				return -ENOBUFS;
			stypes >>= 1;
			i++;
		}
		nla_nest_end(msg, nl_ftypes);
	}
	nla_nest_end(msg, nl_ifs);
1218

1219 1220
	return 0;
}
1221

1222 1223 1224 1225 1226 1227 1228
struct nl80211_dump_wiphy_state {
	s64 filter_wiphy;
	long start;
	long split_start, band_start, chan_start;
	bool split;
};

1229
static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
1230
			      enum nl80211_commands cmd,
1231
			      struct sk_buff *msg, u32 portid, u32 seq,
1232
			      int flags, struct nl80211_dump_wiphy_state *state)
1233 1234 1235 1236 1237 1238 1239 1240 1241
{
	void *hdr;
	struct nlattr *nl_bands, *nl_band;
	struct nlattr *nl_freqs, *nl_freq;
	struct nlattr *nl_cmds;
	enum ieee80211_band band;
	struct ieee80211_channel *chan;
	int i;
	const struct ieee80211_txrx_stypes *mgmt_stypes =
1242
				rdev->wiphy.mgmt_stypes;
1243
	u32 features;
1244

1245
	hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
1246 1247
	if (!hdr)
		return -ENOBUFS;
1248

1249 1250
	if (WARN_ON(!state))
		return -EINVAL;
1251

1252
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
1253
	    nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
1254
			   wiphy_name(&rdev->wiphy)) ||
1255 1256
	    nla_put_u32(msg, NL80211_ATTR_GENERATION,
			cfg80211_rdev_list_generation))
1257 1258
		goto nla_put_failure;

1259 1260 1261
	if (cmd != NL80211_CMD_NEW_WIPHY)
		goto finish;

1262
	switch (state->split_start) {
1263 1264
	case 0:
		if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
1265
			       rdev->wiphy.retry_short) ||
1266
		    nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
1267
			       rdev->wiphy.retry_long) ||
1268
		    nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
1269
				rdev->wiphy.frag_threshold) ||
1270
		    nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
1271
				rdev->wiphy.rts_threshold) ||
1272
		    nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
1273
			       rdev->wiphy.coverage_class) ||
1274
		    nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
1275
			       rdev->wiphy.max_scan_ssids) ||
1276
		    nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
1277
			       rdev->wiphy.max_sched_scan_ssids) ||
1278
		    nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
1279
				rdev->wiphy.max_scan_ie_len) ||
1280
		    nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
1281
				rdev->wiphy.max_sched_scan_ie_len) ||
1282
		    nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
1283
			       rdev->wiphy.max_match_sets))
1284
			goto nla_put_failure;
1285

1286
		if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
1287
		    nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
1288
			goto nla_put_failure;
1289
		if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
1290 1291
		    nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
			goto nla_put_failure;
1292
		if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
1293 1294
		    nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
			goto nla_put_failure;
1295
		if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
1296 1297
		    nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
			goto nla_put_failure;
1298
		if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
1299 1300
		    nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
			goto nla_put_failure;
1301
		if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
1302
		    nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
1303
			goto nla_put_failure;
1304 1305
		state->split_start++;
		if (state->split)
1306 1307 1308
			break;
	case 1:
		if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
1309 1310
			    sizeof(u32) * rdev->wiphy.n_cipher_suites,
			    rdev->wiphy.cipher_suites))
1311
			goto nla_put_failure;
1312

1313
		if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
1314
			       rdev->wiphy.max_num_pmkids))
1315
			goto nla_put_failure;
S
Samuel Ortiz 已提交
1316

1317
		if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
1318
		    nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
1319
			goto nla_put_failure;
S
Samuel Ortiz 已提交
1320

1321
		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
1322
				rdev->wiphy.available_antennas_tx) ||
1323
		    nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
1324
				rdev->wiphy.available_antennas_rx))
1325
			goto nla_put_failure;
S
Samuel Ortiz 已提交
1326

1327
		if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
1328
		    nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
1329
				rdev->wiphy.probe_resp_offload))
1330
			goto nla_put_failure;
1331

1332 1333 1334
		if ((rdev->wiphy.available_antennas_tx ||
		     rdev->wiphy.available_antennas_rx) &&
		    rdev->ops->get_antenna) {
1335 1336
			u32 tx_ant = 0, rx_ant = 0;
			int res;
1337
			res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
			if (!res) {
				if (nla_put_u32(msg,
						NL80211_ATTR_WIPHY_ANTENNA_TX,
						tx_ant) ||
				    nla_put_u32(msg,
						NL80211_ATTR_WIPHY_ANTENNA_RX,
						rx_ant))
					goto nla_put_failure;
			}
		}
1348

1349 1350
		state->split_start++;
		if (state->split)
1351 1352 1353
			break;
	case 2:
		if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
1354
					rdev->wiphy.interface_modes))
1355
				goto nla_put_failure;
1356 1357
		state->split_start++;
		if (state->split)
1358 1359 1360 1361 1362
			break;
	case 3:
		nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
		if (!nl_bands)
			goto nla_put_failure;
1363

1364 1365
		for (band = state->band_start;
		     band < IEEE80211_NUM_BANDS; band++) {
1366
			struct ieee80211_supported_band *sband;
1367

1368
			sband = rdev->wiphy.bands[band];
1369

1370 1371 1372 1373 1374
			if (!sband)
				continue;

			nl_band = nla_nest_start(msg, band);
			if (!nl_band)
1375
				goto nla_put_failure;
1376

1377
			switch (state->chan_start) {
1378 1379
			case 0:
				if (nl80211_send_band_rateinfo(msg, sband))
1380
					goto nla_put_failure;
1381 1382
				state->chan_start++;
				if (state->split)
1383 1384 1385 1386 1387 1388 1389 1390
					break;
			default:
				/* add frequencies */
				nl_freqs = nla_nest_start(
					msg, NL80211_BAND_ATTR_FREQS);
				if (!nl_freqs)
					goto nla_put_failure;

1391
				for (i = state->chan_start - 1;
1392 1393 1394 1395 1396 1397 1398 1399
				     i < sband->n_channels;
				     i++) {
					nl_freq = nla_nest_start(msg, i);
					if (!nl_freq)
						goto nla_put_failure;

					chan = &sband->channels[i];

1400 1401 1402
					if (nl80211_msg_put_channel(
							msg, chan,
							state->split))
1403 1404 1405
						goto nla_put_failure;

					nla_nest_end(msg, nl_freq);
1406
					if (state->split)
1407 1408 1409
						break;
				}
				if (i < sband->n_channels)
1410
					state->chan_start = i + 2;
1411
				else
1412
					state->chan_start = 0;
1413 1414 1415 1416 1417
				nla_nest_end(msg, nl_freqs);
			}

			nla_nest_end(msg, nl_band);

1418
			if (state->split) {
1419
				/* start again here */
1420
				if (state->chan_start)
1421 1422
					band--;
				break;
1423 1424
			}
		}
1425
		nla_nest_end(msg, nl_bands);
1426

1427
		if (band < IEEE80211_NUM_BANDS)
1428
			state->band_start = band + 1;
1429
		else
1430
			state->band_start = 0;
J
Johannes Berg 已提交
1431

1432
		/* if bands & channels are done, continue outside */
1433 1434 1435
		if (state->band_start == 0 && state->chan_start == 0)
			state->split_start++;
		if (state->split)
1436 1437 1438 1439
			break;
	case 4:
		nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
		if (!nl_cmds)
1440 1441
			goto nla_put_failure;

1442 1443 1444
		i = 0;
#define CMD(op, n)							\
		 do {							\
1445
			if (rdev->ops->op) {				\
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
				i++;					\
				if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
					goto nla_put_failure;		\
			}						\
		} while (0)

		CMD(add_virtual_intf, NEW_INTERFACE);
		CMD(change_virtual_intf, SET_INTERFACE);
		CMD(add_key, NEW_KEY);
		CMD(start_ap, START_AP);
		CMD(add_station, NEW_STATION);
		CMD(add_mpath, NEW_MPATH);
		CMD(update_mesh_config, SET_MESH_CONFIG);
		CMD(change_bss, SET_BSS);
		CMD(auth, AUTHENTICATE);
		CMD(assoc, ASSOCIATE);
		CMD(deauth, DEAUTHENTICATE);
		CMD(disassoc, DISASSOCIATE);
		CMD(join_ibss, JOIN_IBSS);
		CMD(join_mesh, JOIN_MESH);
		CMD(set_pmksa, SET_PMKSA);
		CMD(del_pmksa, DEL_PMKSA);
		CMD(flush_pmksa, FLUSH_PMKSA);
1469
		if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1470 1471 1472 1473
			CMD(remain_on_channel, REMAIN_ON_CHANNEL);
		CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
		CMD(mgmt_tx, FRAME);
		CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1474
		if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1475 1476
			i++;
			if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1477 1478
				goto nla_put_failure;
		}
1479 1480
		if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
		    rdev->ops->join_mesh) {
1481 1482 1483 1484 1485
			i++;
			if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
				goto nla_put_failure;
		}
		CMD(set_wds_peer, SET_WDS_PEER);
1486
		if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1487 1488 1489
			CMD(tdls_mgmt, TDLS_MGMT);
			CMD(tdls_oper, TDLS_OPER);
		}
1490
		if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
1491 1492 1493
			CMD(sched_scan_start, START_SCHED_SCAN);
		CMD(probe_client, PROBE_CLIENT);
		CMD(set_noack_map, SET_NOACK_MAP);
1494
		if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1495 1496 1497 1498 1499 1500
			i++;
			if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
				goto nla_put_failure;
		}
		CMD(start_p2p_device, START_P2P_DEVICE);
		CMD(set_mcast_rate, SET_MCAST_RATE);
1501
		if (state->split) {
1502 1503
			CMD(crit_proto_start, CRIT_PROTOCOL_START);
			CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
1504
			if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
1505
				CMD(channel_switch, CHANNEL_SWITCH);
1506
		}
1507
		CMD(set_qos_map, SET_QOS_MAP);
1508

1509 1510 1511
#ifdef CONFIG_NL80211_TESTMODE
		CMD(testmode_cmd, TESTMODE);
#endif
J
Johannes Berg 已提交
1512

1513
#undef CMD
J
Johannes Berg 已提交
1514

1515
		if (rdev->ops->connect || rdev->ops->auth) {
1516 1517
			i++;
			if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1518
				goto nla_put_failure;
J
Johannes Berg 已提交
1519 1520
		}

1521
		if (rdev->ops->disconnect || rdev->ops->deauth) {
1522 1523 1524 1525 1526 1527
			i++;
			if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
				goto nla_put_failure;
		}

		nla_nest_end(msg, nl_cmds);
1528 1529
		state->split_start++;
		if (state->split)
1530 1531
			break;
	case 5:
1532 1533
		if (rdev->ops->remain_on_channel &&
		    (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
1534 1535
		    nla_put_u32(msg,
				NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
1536
				rdev->wiphy.max_remain_on_channel_duration))
1537 1538
			goto nla_put_failure;

1539
		if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
1540 1541 1542 1543 1544
		    nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
			goto nla_put_failure;

		if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
			goto nla_put_failure;
1545 1546
		state->split_start++;
		if (state->split)
1547 1548 1549
			break;
	case 6:
#ifdef CONFIG_PM
1550
		if (nl80211_send_wowlan(msg, rdev, state->split))
1551
			goto nla_put_failure;
1552 1553
		state->split_start++;
		if (state->split)
1554 1555
			break;
#else
1556
		state->split_start++;
1557
#endif
1558 1559
	case 7:
		if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
1560
					rdev->wiphy.software_iftypes))
1561
			goto nla_put_failure;
J
Johannes Berg 已提交
1562

1563
		if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
1564
						   state->split))
1565
			goto nla_put_failure;
1566

1567 1568
		state->split_start++;
		if (state->split)
1569 1570
			break;
	case 8:
1571
		if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
1572
		    nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
1573
				rdev->wiphy.ap_sme_capa))
1574
			goto nla_put_failure;
1575

1576
		features = rdev->wiphy.features;
1577 1578 1579 1580 1581
		/*
		 * We can only add the per-channel limit information if the
		 * dump is split, otherwise it makes it too big. Therefore
		 * only advertise it in that case.
		 */
1582
		if (state->split)
1583 1584
			features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
		if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
1585
			goto nla_put_failure;
J
Johannes Berg 已提交
1586

1587
		if (rdev->wiphy.ht_capa_mod_mask &&
1588
		    nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
1589 1590
			    sizeof(*rdev->wiphy.ht_capa_mod_mask),
			    rdev->wiphy.ht_capa_mod_mask))
1591
			goto nla_put_failure;
1592

1593 1594
		if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
		    rdev->wiphy.max_acl_mac_addrs &&
1595
		    nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
1596
				rdev->wiphy.max_acl_mac_addrs))
1597
			goto nla_put_failure;
1598

1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
		/*
		 * Any information below this point is only available to
		 * applications that can deal with it being split. This
		 * helps ensure that newly added capabilities don't break
		 * older tools by overrunning their buffers.
		 *
		 * We still increment split_start so that in the split
		 * case we'll continue with more data in the next round,
		 * but break unconditionally so unsplit data stops here.
		 */
1609
		state->split_start++;
1610 1611
		break;
	case 9:
1612
		if (rdev->wiphy.extended_capabilities &&
1613
		    (nla_put(msg, NL80211_ATTR_EXT_CAPA,
1614 1615
			     rdev->wiphy.extended_capabilities_len,
			     rdev->wiphy.extended_capabilities) ||
1616
		     nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
1617 1618
			     rdev->wiphy.extended_capabilities_len,
			     rdev->wiphy.extended_capabilities_mask)))
1619
			goto nla_put_failure;
1620

1621
		if (rdev->wiphy.vht_capa_mod_mask &&
1622
		    nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
1623 1624
			    sizeof(*rdev->wiphy.vht_capa_mod_mask),
			    rdev->wiphy.vht_capa_mod_mask))
1625 1626
			goto nla_put_failure;

1627 1628 1629
		state->split_start++;
		break;
	case 10:
1630
		if (nl80211_send_coalesce(msg, rdev))
1631 1632
			goto nla_put_failure;

1633
		if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
1634 1635 1636
		    (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
		     nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
			goto nla_put_failure;
1637

1638
		if (rdev->wiphy.max_ap_assoc_sta &&
1639
		    nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
1640
				rdev->wiphy.max_ap_assoc_sta))
1641 1642
			goto nla_put_failure;

J
Johannes Berg 已提交
1643 1644 1645
		state->split_start++;
		break;
	case 11:
1646
		if (rdev->wiphy.n_vendor_commands) {
1647 1648 1649 1650 1651 1652 1653
			const struct nl80211_vendor_cmd_info *info;
			struct nlattr *nested;

			nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
			if (!nested)
				goto nla_put_failure;

1654 1655
			for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
				info = &rdev->wiphy.vendor_commands[i].info;
1656 1657 1658 1659 1660 1661
				if (nla_put(msg, i + 1, sizeof(*info), info))
					goto nla_put_failure;
			}
			nla_nest_end(msg, nested);
		}

1662
		if (rdev->wiphy.n_vendor_events) {
1663 1664
			const struct nl80211_vendor_cmd_info *info;
			struct nlattr *nested;
J
Johannes Berg 已提交
1665

1666 1667 1668
			nested = nla_nest_start(msg,
						NL80211_ATTR_VENDOR_EVENTS);
			if (!nested)
J
Johannes Berg 已提交
1669
				goto nla_put_failure;
1670

1671 1672
			for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
				info = &rdev->wiphy.vendor_events[i];
1673 1674 1675 1676 1677
				if (nla_put(msg, i + 1, sizeof(*info), info))
					goto nla_put_failure;
			}
			nla_nest_end(msg, nested);
		}
1678 1679 1680 1681 1682 1683 1684
		state->split_start++;
		break;
	case 12:
		if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
		    nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
			       rdev->wiphy.max_num_csa_counters))
			goto nla_put_failure;
1685

1686
		/* done */
1687
		state->split_start = 0;
1688 1689
		break;
	}
1690
 finish:
1691 1692 1693
	return genlmsg_end(msg, hdr);

 nla_put_failure:
1694 1695
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
1696 1697
}

1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718
static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
				    struct netlink_callback *cb,
				    struct nl80211_dump_wiphy_state *state)
{
	struct nlattr **tb = nl80211_fam.attrbuf;
	int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
			      tb, nl80211_fam.maxattr, nl80211_policy);
	/* ignore parse errors for backward compatibility */
	if (ret)
		return 0;

	state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
	if (tb[NL80211_ATTR_WIPHY])
		state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
	if (tb[NL80211_ATTR_WDEV])
		state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
	if (tb[NL80211_ATTR_IFINDEX]) {
		struct net_device *netdev;
		struct cfg80211_registered_device *rdev;
		int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);

1719
		netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
1720 1721 1722
		if (!netdev)
			return -ENODEV;
		if (netdev->ieee80211_ptr) {
1723
			rdev = wiphy_to_rdev(
1724 1725 1726 1727 1728 1729 1730 1731
				netdev->ieee80211_ptr->wiphy);
			state->filter_wiphy = rdev->wiphy_idx;
		}
	}

	return 0;
}

1732 1733
static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
{
1734
	int idx = 0, ret;
1735
	struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
1736
	struct cfg80211_registered_device *rdev;
1737

1738
	rtnl_lock();
1739 1740
	if (!state) {
		state = kzalloc(sizeof(*state), GFP_KERNEL);
J
John W. Linville 已提交
1741 1742
		if (!state) {
			rtnl_unlock();
1743
			return -ENOMEM;
1744
		}
1745 1746 1747 1748 1749 1750
		state->filter_wiphy = -1;
		ret = nl80211_dump_wiphy_parse(skb, cb, state);
		if (ret) {
			kfree(state);
			rtnl_unlock();
			return ret;
1751
		}
1752
		cb->args[0] = (long)state;
1753 1754
	}

1755 1756
	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
		if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
1757
			continue;
1758
		if (++idx <= state->start)
1759
			continue;
1760
		if (state->filter_wiphy != -1 &&
1761
		    state->filter_wiphy != rdev->wiphy_idx)
1762 1763 1764
			continue;
		/* attempt to fit multiple wiphy data chunks into the skb */
		do {
1765 1766
			ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
						 skb,
1767 1768
						 NETLINK_CB(cb->skb).portid,
						 cb->nlh->nlmsg_seq,
1769
						 NLM_F_MULTI, state);
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784
			if (ret < 0) {
				/*
				 * If sending the wiphy data didn't fit (ENOBUFS
				 * or EMSGSIZE returned), this SKB is still
				 * empty (so it's not too big because another
				 * wiphy dataset is already in the skb) and
				 * we've not tried to adjust the dump allocation
				 * yet ... then adjust the alloc size to be
				 * bigger, and return 1 but with the empty skb.
				 * This results in an empty message being RX'ed
				 * in userspace, but that is ignored.
				 *
				 * We can then retry with the larger buffer.
				 */
				if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
1785
				    !skb->len && !state->split &&
1786 1787
				    cb->min_dump_alloc < 4096) {
					cb->min_dump_alloc = 4096;
1788
					state->split_start = 0;
1789
					rtnl_unlock();
1790 1791 1792 1793
					return 1;
				}
				idx--;
				break;
1794
			}
1795
		} while (state->split_start > 0);
1796
		break;
1797
	}
1798
	rtnl_unlock();
1799

1800
	state->start = idx;
1801 1802 1803 1804

	return skb->len;
}

1805 1806 1807 1808 1809 1810
static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
{
	kfree((void *)cb->args[0]);
	return 0;
}

1811 1812 1813
static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
{
	struct sk_buff *msg;
1814
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
1815
	struct nl80211_dump_wiphy_state state = {};
1816

1817
	msg = nlmsg_new(4096, GFP_KERNEL);
1818
	if (!msg)
1819
		return -ENOMEM;
1820

1821 1822
	if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
			       info->snd_portid, info->snd_seq, 0,
1823
			       &state) < 0) {
1824 1825 1826
		nlmsg_free(msg);
		return -ENOBUFS;
	}
1827

J
Johannes Berg 已提交
1828
	return genlmsg_reply(msg, info);
1829 1830
}

1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841
static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
	[NL80211_TXQ_ATTR_QUEUE]		= { .type = NLA_U8 },
	[NL80211_TXQ_ATTR_TXOP]			= { .type = NLA_U16 },
	[NL80211_TXQ_ATTR_CWMIN]		= { .type = NLA_U16 },
	[NL80211_TXQ_ATTR_CWMAX]		= { .type = NLA_U16 },
	[NL80211_TXQ_ATTR_AIFS]			= { .type = NLA_U8 },
};

static int parse_txq_params(struct nlattr *tb[],
			    struct ieee80211_txq_params *txq_params)
{
1842
	if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
1843 1844 1845 1846
	    !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
	    !tb[NL80211_TXQ_ATTR_AIFS])
		return -EINVAL;

1847
	txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
1848 1849 1850 1851 1852
	txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
	txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
	txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
	txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);

1853 1854 1855
	if (txq_params->ac >= NL80211_NUM_ACS)
		return -EINVAL;

1856 1857 1858
	return 0;
}

1859 1860 1861
static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
{
	/*
1862 1863 1864 1865 1866 1867 1868 1869 1870
	 * You can only set the channel explicitly for WDS interfaces,
	 * all others have their channel managed via their respective
	 * "establish a connection" command (connect, join, ...)
	 *
	 * For AP/GO and mesh mode, the channel can be set with the
	 * channel userspace API, but is only stored and passed to the
	 * low-level driver when the AP starts or the mesh is joined.
	 * This is for backward compatibility, userspace can also give
	 * the channel in the start-ap or join-mesh commands instead.
1871 1872
	 *
	 * Monitors are special as they are normally slaved to
1873 1874
	 * whatever else is going on, so they have their own special
	 * operation to set the monitor channel if possible.
1875 1876 1877 1878
	 */
	return !wdev ||
		wdev->iftype == NL80211_IFTYPE_AP ||
		wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
1879 1880
		wdev->iftype == NL80211_IFTYPE_MONITOR ||
		wdev->iftype == NL80211_IFTYPE_P2P_GO;
1881 1882
}

1883 1884 1885 1886
static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
				 struct genl_info *info,
				 struct cfg80211_chan_def *chandef)
{
1887
	u32 control_freq;
1888 1889 1890 1891 1892 1893 1894

	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
		return -EINVAL;

	control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);

	chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
1895 1896 1897
	chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
	chandef->center_freq1 = control_freq;
	chandef->center_freq2 = 0;
1898 1899 1900 1901 1902

	/* Primary channel not allowed */
	if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
		return -EINVAL;

1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932
	if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
		enum nl80211_channel_type chantype;

		chantype = nla_get_u32(
				info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);

		switch (chantype) {
		case NL80211_CHAN_NO_HT:
		case NL80211_CHAN_HT20:
		case NL80211_CHAN_HT40PLUS:
		case NL80211_CHAN_HT40MINUS:
			cfg80211_chandef_create(chandef, chandef->chan,
						chantype);
			break;
		default:
			return -EINVAL;
		}
	} else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
		chandef->width =
			nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
		if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
			chandef->center_freq1 =
				nla_get_u32(
					info->attrs[NL80211_ATTR_CENTER_FREQ1]);
		if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
			chandef->center_freq2 =
				nla_get_u32(
					info->attrs[NL80211_ATTR_CENTER_FREQ2]);
	}

1933
	if (!cfg80211_chandef_valid(chandef))
1934 1935
		return -EINVAL;

1936 1937
	if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
				     IEEE80211_CHAN_DISABLED))
1938 1939
		return -EINVAL;

1940 1941 1942 1943 1944
	if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
	     chandef->width == NL80211_CHAN_WIDTH_10) &&
	    !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
		return -EINVAL;

1945 1946 1947
	return 0;
}

1948
static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
1949
				 struct net_device *dev,
1950 1951
				 struct genl_info *info)
{
1952
	struct cfg80211_chan_def chandef;
1953
	int result;
1954
	enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
1955
	struct wireless_dev *wdev = NULL;
1956

1957 1958
	if (dev)
		wdev = dev->ieee80211_ptr;
1959 1960
	if (!nl80211_can_set_dev_channel(wdev))
		return -EOPNOTSUPP;
1961 1962
	if (wdev)
		iftype = wdev->iftype;
1963

1964 1965 1966
	result = nl80211_parse_chandef(rdev, info, &chandef);
	if (result)
		return result;
1967

1968
	switch (iftype) {
1969 1970
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
1971
		if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
1972 1973 1974
			result = -EINVAL;
			break;
		}
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
		if (wdev->beacon_interval) {
			if (!dev || !rdev->ops->set_ap_chanwidth ||
			    !(rdev->wiphy.features &
			      NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
				result = -EBUSY;
				break;
			}

			/* Only allow dynamic channel width changes */
			if (chandef.chan != wdev->preset_chandef.chan) {
				result = -EBUSY;
				break;
			}
			result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
			if (result)
				break;
		}
1992
		wdev->preset_chandef = chandef;
1993 1994
		result = 0;
		break;
1995
	case NL80211_IFTYPE_MESH_POINT:
1996
		result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
1997
		break;
1998
	case NL80211_IFTYPE_MONITOR:
1999
		result = cfg80211_set_monitor_channel(rdev, &chandef);
2000
		break;
2001
	default:
2002
		result = -EINVAL;
2003 2004 2005 2006 2007 2008 2009
	}

	return result;
}

static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
{
2010 2011
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *netdev = info->user_ptr[1];
2012

2013
	return __nl80211_set_channel(rdev, netdev, info);
2014 2015
}

2016 2017
static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
{
2018 2019 2020
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
J
Johannes Berg 已提交
2021
	const u8 *bssid;
2022 2023 2024 2025

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

2026 2027
	if (netif_running(dev))
		return -EBUSY;
2028

2029 2030
	if (!rdev->ops->set_wds_peer)
		return -EOPNOTSUPP;
2031

2032 2033
	if (wdev->iftype != NL80211_IFTYPE_WDS)
		return -EOPNOTSUPP;
2034 2035

	bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
2036
	return rdev_set_wds_peer(rdev, dev, bssid);
2037 2038 2039
}


2040 2041 2042
static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev;
2043 2044
	struct net_device *netdev = NULL;
	struct wireless_dev *wdev;
B
Bill Jordan 已提交
2045
	int result = 0, rem_txq_params = 0;
2046
	struct nlattr *nl_txq_params;
2047 2048 2049
	u32 changed;
	u8 retry_short = 0, retry_long = 0;
	u32 frag_threshold = 0, rts_threshold = 0;
2050
	u8 coverage_class = 0;
2051

2052 2053
	ASSERT_RTNL();

2054 2055 2056 2057 2058 2059 2060 2061 2062
	/*
	 * Try to find the wiphy and netdev. Normally this
	 * function shouldn't need the netdev, but this is
	 * done for backward compatibility -- previously
	 * setting the channel was done per wiphy, but now
	 * it is per netdev. Previous userland like hostapd
	 * also passed a netdev to set_wiphy, so that it is
	 * possible to let that go to the right netdev!
	 */
2063

2064 2065 2066
	if (info->attrs[NL80211_ATTR_IFINDEX]) {
		int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);

2067
		netdev = __dev_get_by_index(genl_info_net(info), ifindex);
2068
		if (netdev && netdev->ieee80211_ptr)
2069
			rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
2070
		else
2071
			netdev = NULL;
2072 2073
	}

2074
	if (!netdev) {
2075 2076
		rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
						  info->attrs);
2077
		if (IS_ERR(rdev))
2078
			return PTR_ERR(rdev);
2079 2080 2081
		wdev = NULL;
		netdev = NULL;
		result = 0;
2082
	} else
2083 2084 2085 2086 2087 2088
		wdev = netdev->ieee80211_ptr;

	/*
	 * end workaround code, by now the rdev is available
	 * and locked, and wdev may or may not be NULL.
	 */
2089 2090

	if (info->attrs[NL80211_ATTR_WIPHY_NAME])
2091 2092
		result = cfg80211_dev_rename(
			rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
2093 2094

	if (result)
2095
		return result;
2096 2097 2098 2099 2100

	if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
		struct ieee80211_txq_params txq_params;
		struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];

2101 2102
		if (!rdev->ops->set_txq_params)
			return -EOPNOTSUPP;
2103

2104 2105
		if (!netdev)
			return -EINVAL;
2106

2107
		if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2108 2109
		    netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
			return -EINVAL;
2110

2111 2112
		if (!netif_running(netdev))
			return -ENETDOWN;
2113

2114 2115 2116
		nla_for_each_nested(nl_txq_params,
				    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
				    rem_txq_params) {
2117 2118 2119 2120 2121 2122
			result = nla_parse(tb, NL80211_TXQ_ATTR_MAX,
					   nla_data(nl_txq_params),
					   nla_len(nl_txq_params),
					   txq_params_policy);
			if (result)
				return result;
2123 2124
			result = parse_txq_params(tb, &txq_params);
			if (result)
2125
				return result;
2126

2127 2128
			result = rdev_set_txq_params(rdev, netdev,
						     &txq_params);
2129
			if (result)
2130
				return result;
2131 2132
		}
	}
2133

2134
	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2135 2136 2137 2138
		result = __nl80211_set_channel(
			rdev,
			nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
			info);
2139
		if (result)
2140
			return result;
2141 2142
	}

2143
	if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
2144
		struct wireless_dev *txp_wdev = wdev;
2145 2146 2147
		enum nl80211_tx_power_setting type;
		int idx, mbm = 0;

2148 2149 2150
		if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
			txp_wdev = NULL;

2151 2152
		if (!rdev->ops->set_tx_power)
			return -EOPNOTSUPP;
2153 2154 2155 2156 2157

		idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
		type = nla_get_u32(info->attrs[idx]);

		if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
2158 2159
		    (type != NL80211_TX_POWER_AUTOMATIC))
			return -EINVAL;
2160 2161 2162 2163 2164 2165

		if (type != NL80211_TX_POWER_AUTOMATIC) {
			idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
			mbm = nla_get_u32(info->attrs[idx]);
		}

2166
		result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
2167
		if (result)
2168
			return result;
2169 2170
	}

2171 2172 2173
	if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
	    info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
		u32 tx_ant, rx_ant;
2174 2175
		if ((!rdev->wiphy.available_antennas_tx &&
		     !rdev->wiphy.available_antennas_rx) ||
2176 2177
		    !rdev->ops->set_antenna)
			return -EOPNOTSUPP;
2178 2179 2180 2181

		tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
		rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);

2182
		/* reject antenna configurations which don't match the
2183 2184
		 * available antenna masks, except for the "all" mask */
		if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
2185 2186
		    (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
			return -EINVAL;
2187

2188 2189
		tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
		rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
2190

2191
		result = rdev_set_antenna(rdev, tx_ant, rx_ant);
2192
		if (result)
2193
			return result;
2194 2195
	}

2196 2197 2198 2199 2200
	changed = 0;

	if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
		retry_short = nla_get_u8(
			info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
2201 2202 2203
		if (retry_short == 0)
			return -EINVAL;

2204 2205 2206 2207 2208 2209
		changed |= WIPHY_PARAM_RETRY_SHORT;
	}

	if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
		retry_long = nla_get_u8(
			info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
2210 2211 2212
		if (retry_long == 0)
			return -EINVAL;

2213 2214 2215 2216 2217 2218
		changed |= WIPHY_PARAM_RETRY_LONG;
	}

	if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
		frag_threshold = nla_get_u32(
			info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
2219 2220 2221
		if (frag_threshold < 256)
			return -EINVAL;

2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239
		if (frag_threshold != (u32) -1) {
			/*
			 * Fragments (apart from the last one) are required to
			 * have even length. Make the fragmentation code
			 * simpler by stripping LSB should someone try to use
			 * odd threshold value.
			 */
			frag_threshold &= ~0x1;
		}
		changed |= WIPHY_PARAM_FRAG_THRESHOLD;
	}

	if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
		rts_threshold = nla_get_u32(
			info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
		changed |= WIPHY_PARAM_RTS_THRESHOLD;
	}

2240 2241 2242 2243 2244 2245
	if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
		coverage_class = nla_get_u8(
			info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
		changed |= WIPHY_PARAM_COVERAGE_CLASS;
	}

2246 2247 2248
	if (changed) {
		u8 old_retry_short, old_retry_long;
		u32 old_frag_threshold, old_rts_threshold;
2249
		u8 old_coverage_class;
2250

2251 2252
		if (!rdev->ops->set_wiphy_params)
			return -EOPNOTSUPP;
2253 2254 2255 2256 2257

		old_retry_short = rdev->wiphy.retry_short;
		old_retry_long = rdev->wiphy.retry_long;
		old_frag_threshold = rdev->wiphy.frag_threshold;
		old_rts_threshold = rdev->wiphy.rts_threshold;
2258
		old_coverage_class = rdev->wiphy.coverage_class;
2259 2260 2261 2262 2263 2264 2265 2266 2267

		if (changed & WIPHY_PARAM_RETRY_SHORT)
			rdev->wiphy.retry_short = retry_short;
		if (changed & WIPHY_PARAM_RETRY_LONG)
			rdev->wiphy.retry_long = retry_long;
		if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
			rdev->wiphy.frag_threshold = frag_threshold;
		if (changed & WIPHY_PARAM_RTS_THRESHOLD)
			rdev->wiphy.rts_threshold = rts_threshold;
2268 2269
		if (changed & WIPHY_PARAM_COVERAGE_CLASS)
			rdev->wiphy.coverage_class = coverage_class;
2270

2271
		result = rdev_set_wiphy_params(rdev, changed);
2272 2273 2274 2275 2276
		if (result) {
			rdev->wiphy.retry_short = old_retry_short;
			rdev->wiphy.retry_long = old_retry_long;
			rdev->wiphy.frag_threshold = old_frag_threshold;
			rdev->wiphy.rts_threshold = old_rts_threshold;
2277
			rdev->wiphy.coverage_class = old_coverage_class;
2278 2279
		}
	}
2280
	return 0;
2281 2282
}

2283 2284 2285
static inline u64 wdev_id(struct wireless_dev *wdev)
{
	return (u64)wdev->identifier |
2286
	       ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
2287
}
2288

2289
static int nl80211_send_chandef(struct sk_buff *msg,
2290
				const struct cfg80211_chan_def *chandef)
2291
{
2292
	WARN_ON(!cfg80211_chandef_valid(chandef));
2293

2294 2295 2296
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
			chandef->chan->center_freq))
		return -ENOBUFS;
2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313
	switch (chandef->width) {
	case NL80211_CHAN_WIDTH_20_NOHT:
	case NL80211_CHAN_WIDTH_20:
	case NL80211_CHAN_WIDTH_40:
		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
				cfg80211_get_chandef_type(chandef)))
			return -ENOBUFS;
		break;
	default:
		break;
	}
	if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
		return -ENOBUFS;
	if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
		return -ENOBUFS;
	if (chandef->center_freq2 &&
	    nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
2314 2315 2316 2317
		return -ENOBUFS;
	return 0;
}

2318
static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
2319
			      struct cfg80211_registered_device *rdev,
2320
			      struct wireless_dev *wdev)
2321
{
2322
	struct net_device *dev = wdev->netdev;
2323 2324
	void *hdr;

2325
	hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_INTERFACE);
2326 2327 2328
	if (!hdr)
		return -1;

2329 2330
	if (dev &&
	    (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
2331
	     nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
2332 2333 2334 2335
		goto nla_put_failure;

	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
2336
	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
2337
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
2338 2339 2340 2341
	    nla_put_u32(msg, NL80211_ATTR_GENERATION,
			rdev->devlist_generation ^
			(cfg80211_rdev_list_generation << 2)))
		goto nla_put_failure;
2342

2343
	if (rdev->ops->get_channel) {
2344 2345 2346 2347 2348 2349 2350 2351
		int ret;
		struct cfg80211_chan_def chandef;

		ret = rdev_get_channel(rdev, wdev, &chandef);
		if (ret == 0) {
			if (nl80211_send_chandef(msg, &chandef))
				goto nla_put_failure;
		}
2352 2353
	}

2354 2355 2356 2357 2358
	if (wdev->ssid_len) {
		if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
			goto nla_put_failure;
	}

2359 2360 2361
	return genlmsg_end(msg, hdr);

 nla_put_failure:
2362 2363
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
2364 2365 2366 2367 2368 2369 2370 2371
}

static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
{
	int wp_idx = 0;
	int if_idx = 0;
	int wp_start = cb->args[0];
	int if_start = cb->args[1];
2372
	struct cfg80211_registered_device *rdev;
2373 2374
	struct wireless_dev *wdev;

2375
	rtnl_lock();
2376 2377
	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
		if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
2378
			continue;
J
Johannes Berg 已提交
2379 2380
		if (wp_idx < wp_start) {
			wp_idx++;
2381
			continue;
J
Johannes Berg 已提交
2382
		}
2383 2384
		if_idx = 0;

2385
		list_for_each_entry(wdev, &rdev->wdev_list, list) {
J
Johannes Berg 已提交
2386 2387
			if (if_idx < if_start) {
				if_idx++;
2388
				continue;
J
Johannes Berg 已提交
2389
			}
2390
			if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
2391
					       cb->nlh->nlmsg_seq, NLM_F_MULTI,
2392
					       rdev, wdev) < 0) {
J
Johannes Berg 已提交
2393 2394 2395
				goto out;
			}
			if_idx++;
2396
		}
J
Johannes Berg 已提交
2397 2398

		wp_idx++;
2399
	}
J
Johannes Berg 已提交
2400
 out:
2401
	rtnl_unlock();
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411

	cb->args[0] = wp_idx;
	cb->args[1] = if_idx;

	return skb->len;
}

static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
{
	struct sk_buff *msg;
2412
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
2413
	struct wireless_dev *wdev = info->user_ptr[1];
2414

2415
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2416
	if (!msg)
2417
		return -ENOMEM;
2418

2419
	if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
2420
			       rdev, wdev) < 0) {
2421 2422 2423
		nlmsg_free(msg);
		return -ENOBUFS;
	}
2424

J
Johannes Berg 已提交
2425
	return genlmsg_reply(msg, info);
2426 2427
}

2428 2429 2430 2431 2432 2433
static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
	[NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
	[NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
	[NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
	[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
	[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
2434
	[NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457
};

static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
{
	struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
	int flag;

	*mntrflags = 0;

	if (!nla)
		return -EINVAL;

	if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
			     nla, mntr_flags_policy))
		return -EINVAL;

	for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
		if (flags[flag])
			*mntrflags |= (1<<flag);

	return 0;
}

2458
static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
2459 2460
			       struct net_device *netdev, u8 use_4addr,
			       enum nl80211_iftype iftype)
2461
{
2462
	if (!use_4addr) {
2463
		if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
2464
			return -EBUSY;
2465
		return 0;
2466
	}
2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483

	switch (iftype) {
	case NL80211_IFTYPE_AP_VLAN:
		if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
			return 0;
		break;
	case NL80211_IFTYPE_STATION:
		if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
			return 0;
		break;
	default:
		break;
	}

	return -EOPNOTSUPP;
}

2484 2485
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
2486
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
2487
	struct vif_params params;
2488
	int err;
J
Johannes Berg 已提交
2489
	enum nl80211_iftype otype, ntype;
2490
	struct net_device *dev = info->user_ptr[1];
2491
	u32 _flags, *flags = NULL;
2492
	bool change = false;
2493

2494 2495
	memset(&params, 0, sizeof(params));

J
Johannes Berg 已提交
2496
	otype = ntype = dev->ieee80211_ptr->iftype;
2497

2498
	if (info->attrs[NL80211_ATTR_IFTYPE]) {
2499
		ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
J
Johannes Berg 已提交
2500
		if (otype != ntype)
2501
			change = true;
2502 2503
		if (ntype > NL80211_IFTYPE_MAX)
			return -EINVAL;
2504 2505
	}

2506
	if (info->attrs[NL80211_ATTR_MESH_ID]) {
2507 2508
		struct wireless_dev *wdev = dev->ieee80211_ptr;

2509 2510
		if (ntype != NL80211_IFTYPE_MESH_POINT)
			return -EINVAL;
2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521
		if (netif_running(dev))
			return -EBUSY;

		wdev_lock(wdev);
		BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
			     IEEE80211_MAX_MESH_ID_LEN);
		wdev->mesh_id_up_len =
			nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
		memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
		       wdev->mesh_id_up_len);
		wdev_unlock(wdev);
2522 2523
	}

2524 2525 2526
	if (info->attrs[NL80211_ATTR_4ADDR]) {
		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
		change = true;
2527
		err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
2528
		if (err)
2529
			return err;
2530 2531 2532 2533
	} else {
		params.use_4addr = -1;
	}

2534
	if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
2535 2536
		if (ntype != NL80211_IFTYPE_MONITOR)
			return -EINVAL;
2537 2538
		err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
					  &_flags);
2539
		if (err)
2540
			return err;
2541 2542 2543

		flags = &_flags;
		change = true;
2544
	}
J
Johannes Berg 已提交
2545

2546
	if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
2547 2548 2549
	    !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
		return -EOPNOTSUPP;

2550
	if (change)
2551
		err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
2552 2553
	else
		err = 0;
J
Johannes Berg 已提交
2554

2555 2556 2557
	if (!err && params.use_4addr != -1)
		dev->ieee80211_ptr->use_4addr = params.use_4addr;

2558 2559 2560 2561 2562
	return err;
}

static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{
2563
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
2564
	struct vif_params params;
2565
	struct wireless_dev *wdev;
2566
	struct sk_buff *msg;
2567 2568
	int err;
	enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
2569
	u32 flags;
2570

2571 2572 2573
	/* to avoid failing a new interface creation due to pending removal */
	cfg80211_destroy_ifaces(rdev);

2574 2575
	memset(&params, 0, sizeof(params));

2576 2577 2578 2579 2580 2581 2582 2583 2584
	if (!info->attrs[NL80211_ATTR_IFNAME])
		return -EINVAL;

	if (info->attrs[NL80211_ATTR_IFTYPE]) {
		type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
		if (type > NL80211_IFTYPE_MAX)
			return -EINVAL;
	}

2585
	if (!rdev->ops->add_virtual_intf ||
2586 2587
	    !(rdev->wiphy.interface_modes & (1 << type)))
		return -EOPNOTSUPP;
2588

2589 2590 2591 2592 2593 2594 2595
	if (type == NL80211_IFTYPE_P2P_DEVICE && info->attrs[NL80211_ATTR_MAC]) {
		nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
			   ETH_ALEN);
		if (!is_valid_ether_addr(params.macaddr))
			return -EADDRNOTAVAIL;
	}

2596
	if (info->attrs[NL80211_ATTR_4ADDR]) {
2597
		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
2598
		err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
2599
		if (err)
2600
			return err;
2601
	}
2602

2603 2604 2605 2606
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return -ENOMEM;

2607 2608 2609
	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
				  &flags);
2610

2611
	if (!err && (flags & MONITOR_FLAG_ACTIVE) &&
2612 2613 2614
	    !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
		return -EOPNOTSUPP;

2615 2616 2617
	wdev = rdev_add_virtual_intf(rdev,
				nla_data(info->attrs[NL80211_ATTR_IFNAME]),
				type, err ? NULL : &flags, &params);
2618 2619
	if (IS_ERR(wdev)) {
		nlmsg_free(msg);
2620
		return PTR_ERR(wdev);
2621
	}
2622

2623 2624 2625
	if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
		wdev->owner_nlportid = info->snd_portid;

2626 2627 2628 2629
	switch (type) {
	case NL80211_IFTYPE_MESH_POINT:
		if (!info->attrs[NL80211_ATTR_MESH_ID])
			break;
2630 2631 2632 2633 2634 2635 2636 2637
		wdev_lock(wdev);
		BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
			     IEEE80211_MAX_MESH_ID_LEN);
		wdev->mesh_id_up_len =
			nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
		memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
		       wdev->mesh_id_up_len);
		wdev_unlock(wdev);
2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655
		break;
	case NL80211_IFTYPE_P2P_DEVICE:
		/*
		 * P2P Device doesn't have a netdev, so doesn't go
		 * through the netdev notifier and must be added here
		 */
		mutex_init(&wdev->mtx);
		INIT_LIST_HEAD(&wdev->event_list);
		spin_lock_init(&wdev->event_lock);
		INIT_LIST_HEAD(&wdev->mgmt_registrations);
		spin_lock_init(&wdev->mgmt_registrations_lock);

		wdev->identifier = ++rdev->wdev_id;
		list_add_rcu(&wdev->list, &rdev->wdev_list);
		rdev->devlist_generation++;
		break;
	default:
		break;
2656 2657
	}

2658
	if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
2659 2660 2661 2662 2663 2664
			       rdev, wdev) < 0) {
		nlmsg_free(msg);
		return -ENOBUFS;
	}

	return genlmsg_reply(msg, info);
2665 2666 2667 2668
}

static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
{
2669
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
2670
	struct wireless_dev *wdev = info->user_ptr[1];
2671

2672 2673
	if (!rdev->ops->del_virtual_intf)
		return -EOPNOTSUPP;
2674

2675 2676 2677 2678 2679 2680 2681 2682 2683 2684
	/*
	 * If we remove a wireless device without a netdev then clear
	 * user_ptr[1] so that nl80211_post_doit won't dereference it
	 * to check if it needs to do dev_put(). Otherwise it crashes
	 * since the wdev has been freed, unlike with a netdev where
	 * we need the dev_put() for the netdev to really be freed.
	 */
	if (!wdev->netdev)
		info->user_ptr[1] = NULL;

2685
	return rdev_del_virtual_intf(rdev, wdev);
2686 2687
}

2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	u16 noack_map;

	if (!info->attrs[NL80211_ATTR_NOACK_MAP])
		return -EINVAL;

	if (!rdev->ops->set_noack_map)
		return -EOPNOTSUPP;

	noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);

2702
	return rdev_set_noack_map(rdev, dev, noack_map);
2703 2704
}

2705 2706 2707
struct get_key_cookie {
	struct sk_buff *msg;
	int error;
2708
	int idx;
2709 2710 2711 2712
};

static void get_key_callback(void *c, struct key_params *params)
{
2713
	struct nlattr *key;
2714 2715
	struct get_key_cookie *cookie = c;

2716 2717 2718 2719 2720 2721 2722 2723 2724 2725
	if ((params->key &&
	     nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
		     params->key_len, params->key)) ||
	    (params->seq &&
	     nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
		     params->seq_len, params->seq)) ||
	    (params->cipher &&
	     nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
			 params->cipher)))
		goto nla_put_failure;
2726

2727 2728 2729 2730
	key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
	if (!key)
		goto nla_put_failure;

2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
	if ((params->key &&
	     nla_put(cookie->msg, NL80211_KEY_DATA,
		     params->key_len, params->key)) ||
	    (params->seq &&
	     nla_put(cookie->msg, NL80211_KEY_SEQ,
		     params->seq_len, params->seq)) ||
	    (params->cipher &&
	     nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
			 params->cipher)))
		goto nla_put_failure;
2741

2742 2743
	if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx))
		goto nla_put_failure;
2744 2745 2746

	nla_nest_end(cookie->msg, key);

2747 2748 2749 2750 2751 2752 2753
	return;
 nla_put_failure:
	cookie->error = 1;
}

static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
{
2754
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
2755
	int err;
2756
	struct net_device *dev = info->user_ptr[1];
2757
	u8 key_idx = 0;
2758 2759
	const u8 *mac_addr = NULL;
	bool pairwise;
2760 2761 2762 2763 2764 2765 2766 2767 2768
	struct get_key_cookie cookie = {
		.error = 0,
	};
	void *hdr;
	struct sk_buff *msg;

	if (info->attrs[NL80211_ATTR_KEY_IDX])
		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);

2769
	if (key_idx > 5)
2770 2771 2772 2773 2774
		return -EINVAL;

	if (info->attrs[NL80211_ATTR_MAC])
		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785
	pairwise = !!mac_addr;
	if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
		u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
		if (kt >= NUM_NL80211_KEYTYPES)
			return -EINVAL;
		if (kt != NL80211_KEYTYPE_GROUP &&
		    kt != NL80211_KEYTYPE_PAIRWISE)
			return -EINVAL;
		pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
	}

2786 2787
	if (!rdev->ops->get_key)
		return -EOPNOTSUPP;
2788

2789
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2790 2791
	if (!msg)
		return -ENOMEM;
2792

2793
	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
2794
			     NL80211_CMD_NEW_KEY);
2795
	if (!hdr)
2796
		goto nla_put_failure;
2797 2798

	cookie.msg = msg;
2799
	cookie.idx = key_idx;
2800

2801 2802 2803 2804 2805 2806
	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
		goto nla_put_failure;
	if (mac_addr &&
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
		goto nla_put_failure;
2807

2808 2809 2810 2811
	if (pairwise && mac_addr &&
	    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
		return -ENOENT;

2812 2813
	err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
			   get_key_callback);
2814 2815

	if (err)
N
Niko Jokinen 已提交
2816
		goto free_msg;
2817 2818 2819 2820 2821

	if (cookie.error)
		goto nla_put_failure;

	genlmsg_end(msg, hdr);
2822
	return genlmsg_reply(msg, info);
2823 2824 2825

 nla_put_failure:
	err = -ENOBUFS;
N
Niko Jokinen 已提交
2826
 free_msg:
2827 2828 2829 2830 2831 2832
	nlmsg_free(msg);
	return err;
}

static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
{
2833
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
2834
	struct key_parse key;
2835
	int err;
2836
	struct net_device *dev = info->user_ptr[1];
2837

2838 2839 2840
	err = nl80211_parse_key(info, &key);
	if (err)
		return err;
2841

2842
	if (key.idx < 0)
2843 2844
		return -EINVAL;

2845 2846
	/* only support setting default key */
	if (!key.def && !key.defmgmt)
2847 2848
		return -EINVAL;

2849
	wdev_lock(dev->ieee80211_ptr);
2850

2851 2852 2853 2854 2855
	if (key.def) {
		if (!rdev->ops->set_default_key) {
			err = -EOPNOTSUPP;
			goto out;
		}
2856

2857 2858 2859 2860
		err = nl80211_key_allowed(dev->ieee80211_ptr);
		if (err)
			goto out;

2861
		err = rdev_set_default_key(rdev, dev, key.idx,
2862 2863 2864 2865
						 key.def_uni, key.def_multi);

		if (err)
			goto out;
J
Johannes Berg 已提交
2866

J
Johannes Berg 已提交
2867
#ifdef CONFIG_CFG80211_WEXT
2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884
		dev->ieee80211_ptr->wext.default_key = key.idx;
#endif
	} else {
		if (key.def_uni || !key.def_multi) {
			err = -EINVAL;
			goto out;
		}

		if (!rdev->ops->set_default_mgmt_key) {
			err = -EOPNOTSUPP;
			goto out;
		}

		err = nl80211_key_allowed(dev->ieee80211_ptr);
		if (err)
			goto out;

2885
		err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
2886 2887 2888 2889 2890
		if (err)
			goto out;

#ifdef CONFIG_CFG80211_WEXT
		dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
2891
#endif
2892 2893 2894
	}

 out:
J
Johannes Berg 已提交
2895
	wdev_unlock(dev->ieee80211_ptr);
2896 2897 2898 2899 2900 2901

	return err;
}

static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
{
2902
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
J
Johannes Berg 已提交
2903
	int err;
2904
	struct net_device *dev = info->user_ptr[1];
2905
	struct key_parse key;
2906
	const u8 *mac_addr = NULL;
2907

2908 2909 2910
	err = nl80211_parse_key(info, &key);
	if (err)
		return err;
2911

2912
	if (!key.p.key)
2913 2914 2915 2916 2917
		return -EINVAL;

	if (info->attrs[NL80211_ATTR_MAC])
		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929
	if (key.type == -1) {
		if (mac_addr)
			key.type = NL80211_KEYTYPE_PAIRWISE;
		else
			key.type = NL80211_KEYTYPE_GROUP;
	}

	/* for now */
	if (key.type != NL80211_KEYTYPE_PAIRWISE &&
	    key.type != NL80211_KEYTYPE_GROUP)
		return -EINVAL;

2930 2931
	if (!rdev->ops->add_key)
		return -EOPNOTSUPP;
2932

2933 2934 2935
	if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
					   key.type == NL80211_KEYTYPE_PAIRWISE,
					   mac_addr))
2936
		return -EINVAL;
2937

J
Johannes Berg 已提交
2938 2939 2940
	wdev_lock(dev->ieee80211_ptr);
	err = nl80211_key_allowed(dev->ieee80211_ptr);
	if (!err)
2941 2942 2943
		err = rdev_add_key(rdev, dev, key.idx,
				   key.type == NL80211_KEYTYPE_PAIRWISE,
				    mac_addr, &key.p);
J
Johannes Berg 已提交
2944
	wdev_unlock(dev->ieee80211_ptr);
2945 2946 2947 2948 2949 2950

	return err;
}

static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
{
2951
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
2952
	int err;
2953
	struct net_device *dev = info->user_ptr[1];
2954
	u8 *mac_addr = NULL;
2955
	struct key_parse key;
2956

2957 2958 2959
	err = nl80211_parse_key(info, &key);
	if (err)
		return err;
2960 2961 2962 2963

	if (info->attrs[NL80211_ATTR_MAC])
		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975
	if (key.type == -1) {
		if (mac_addr)
			key.type = NL80211_KEYTYPE_PAIRWISE;
		else
			key.type = NL80211_KEYTYPE_GROUP;
	}

	/* for now */
	if (key.type != NL80211_KEYTYPE_PAIRWISE &&
	    key.type != NL80211_KEYTYPE_GROUP)
		return -EINVAL;

2976 2977
	if (!rdev->ops->del_key)
		return -EOPNOTSUPP;
2978

J
Johannes Berg 已提交
2979 2980
	wdev_lock(dev->ieee80211_ptr);
	err = nl80211_key_allowed(dev->ieee80211_ptr);
2981 2982 2983 2984 2985

	if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr &&
	    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
		err = -ENOENT;

J
Johannes Berg 已提交
2986
	if (!err)
2987 2988 2989
		err = rdev_del_key(rdev, dev, key.idx,
				   key.type == NL80211_KEYTYPE_PAIRWISE,
				   mac_addr);
2990

J
Johannes Berg 已提交
2991
#ifdef CONFIG_CFG80211_WEXT
2992
	if (!err) {
2993
		if (key.idx == dev->ieee80211_ptr->wext.default_key)
2994
			dev->ieee80211_ptr->wext.default_key = -1;
2995
		else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
2996 2997 2998
			dev->ieee80211_ptr->wext.default_mgmt_key = -1;
	}
#endif
J
Johannes Berg 已提交
2999
	wdev_unlock(dev->ieee80211_ptr);
3000

3001 3002 3003
	return err;
}

3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094
/* This function returns an error or the number of nested attributes */
static int validate_acl_mac_addrs(struct nlattr *nl_attr)
{
	struct nlattr *attr;
	int n_entries = 0, tmp;

	nla_for_each_nested(attr, nl_attr, tmp) {
		if (nla_len(attr) != ETH_ALEN)
			return -EINVAL;

		n_entries++;
	}

	return n_entries;
}

/*
 * This function parses ACL information and allocates memory for ACL data.
 * On successful return, the calling function is responsible to free the
 * ACL buffer returned by this function.
 */
static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
						struct genl_info *info)
{
	enum nl80211_acl_policy acl_policy;
	struct nlattr *attr;
	struct cfg80211_acl_data *acl;
	int i = 0, n_entries, tmp;

	if (!wiphy->max_acl_mac_addrs)
		return ERR_PTR(-EOPNOTSUPP);

	if (!info->attrs[NL80211_ATTR_ACL_POLICY])
		return ERR_PTR(-EINVAL);

	acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
	if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
	    acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
		return ERR_PTR(-EINVAL);

	if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
		return ERR_PTR(-EINVAL);

	n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
	if (n_entries < 0)
		return ERR_PTR(n_entries);

	if (n_entries > wiphy->max_acl_mac_addrs)
		return ERR_PTR(-ENOTSUPP);

	acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
		      GFP_KERNEL);
	if (!acl)
		return ERR_PTR(-ENOMEM);

	nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
		memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
		i++;
	}

	acl->n_acl_entries = n_entries;
	acl->acl_policy = acl_policy;

	return acl;
}

static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct cfg80211_acl_data *acl;
	int err;

	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
		return -EOPNOTSUPP;

	if (!dev->ieee80211_ptr->beacon_interval)
		return -EINVAL;

	acl = parse_acl_data(&rdev->wiphy, info);
	if (IS_ERR(acl))
		return PTR_ERR(acl);

	err = rdev_set_mac_acl(rdev, dev, acl);

	kfree(acl);

	return err;
}

3095
static int nl80211_parse_beacon(struct nlattr *attrs[],
3096
				struct cfg80211_beacon_data *bcn)
3097
{
3098
	bool haveinfo = false;
3099

3100 3101 3102 3103
	if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
	    !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
	    !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
	    !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
3104 3105
		return -EINVAL;

3106
	memset(bcn, 0, sizeof(*bcn));
3107

3108 3109 3110
	if (attrs[NL80211_ATTR_BEACON_HEAD]) {
		bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
		bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
3111 3112 3113
		if (!bcn->head_len)
			return -EINVAL;
		haveinfo = true;
3114 3115
	}

3116 3117 3118
	if (attrs[NL80211_ATTR_BEACON_TAIL]) {
		bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
		bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
3119
		haveinfo = true;
3120 3121
	}

3122 3123
	if (!haveinfo)
		return -EINVAL;
J
Johannes Berg 已提交
3124

3125 3126 3127
	if (attrs[NL80211_ATTR_IE]) {
		bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
		bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
3128 3129
	}

3130
	if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
3131
		bcn->proberesp_ies =
3132
			nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
3133
		bcn->proberesp_ies_len =
3134
			nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
3135 3136
	}

3137
	if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
3138
		bcn->assocresp_ies =
3139
			nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
3140
		bcn->assocresp_ies_len =
3141
			nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
3142 3143
	}

3144 3145 3146
	if (attrs[NL80211_ATTR_PROBE_RESP]) {
		bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
		bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
3147 3148
	}

3149 3150 3151
	return 0;
}

3152 3153 3154 3155 3156 3157
static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
				   struct cfg80211_ap_settings *params)
{
	struct wireless_dev *wdev;
	bool ret = false;

3158
	list_for_each_entry(wdev, &rdev->wdev_list, list) {
3159 3160 3161 3162
		if (wdev->iftype != NL80211_IFTYPE_AP &&
		    wdev->iftype != NL80211_IFTYPE_P2P_GO)
			continue;

3163
		if (!wdev->preset_chandef.chan)
3164 3165
			continue;

3166
		params->chandef = wdev->preset_chandef;
3167 3168 3169 3170 3171 3172 3173
		ret = true;
		break;
	}

	return ret;
}

3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197
static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
				    enum nl80211_auth_type auth_type,
				    enum nl80211_commands cmd)
{
	if (auth_type > NL80211_AUTHTYPE_MAX)
		return false;

	switch (cmd) {
	case NL80211_CMD_AUTHENTICATE:
		if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
		    auth_type == NL80211_AUTHTYPE_SAE)
			return false;
		return true;
	case NL80211_CMD_CONNECT:
	case NL80211_CMD_START_AP:
		/* SAE not supported yet */
		if (auth_type == NL80211_AUTHTYPE_SAE)
			return false;
		return true;
	default:
		return false;
	}
}

3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223
static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_ap_settings params;
	int err;

	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
		return -EOPNOTSUPP;

	if (!rdev->ops->start_ap)
		return -EOPNOTSUPP;

	if (wdev->beacon_interval)
		return -EALREADY;

	memset(&params, 0, sizeof(params));

	/* these are required for START_AP */
	if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
	    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
	    !info->attrs[NL80211_ATTR_BEACON_HEAD])
		return -EINVAL;

3224
	err = nl80211_parse_beacon(info->attrs, &params.beacon);
3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266
	if (err)
		return err;

	params.beacon_interval =
		nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
	params.dtim_period =
		nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);

	err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
	if (err)
		return err;

	/*
	 * In theory, some of these attributes should be required here
	 * but since they were not used when the command was originally
	 * added, keep them optional for old user space programs to let
	 * them continue to work with drivers that do not need the
	 * additional information -- drivers must check!
	 */
	if (info->attrs[NL80211_ATTR_SSID]) {
		params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
		params.ssid_len =
			nla_len(info->attrs[NL80211_ATTR_SSID]);
		if (params.ssid_len == 0 ||
		    params.ssid_len > IEEE80211_MAX_SSID_LEN)
			return -EINVAL;
	}

	if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
		params.hidden_ssid = nla_get_u32(
			info->attrs[NL80211_ATTR_HIDDEN_SSID]);
		if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
		    params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
		    params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
			return -EINVAL;
	}

	params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];

	if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
		params.auth_type = nla_get_u32(
			info->attrs[NL80211_ATTR_AUTH_TYPE]);
3267 3268
		if (!nl80211_valid_auth_type(rdev, params.auth_type,
					     NL80211_CMD_START_AP))
3269 3270 3271 3272 3273 3274 3275 3276 3277
			return -EINVAL;
	} else
		params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;

	err = nl80211_crypto_settings(rdev, info, &params.crypto,
				      NL80211_MAX_NR_CIPHER_SUITES);
	if (err)
		return err;

3278 3279 3280 3281 3282 3283 3284
	if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
		if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
			return -EOPNOTSUPP;
		params.inactivity_timeout = nla_get_u16(
			info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
	}

3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310
	if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
			return -EINVAL;
		params.p2p_ctwindow =
			nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
		if (params.p2p_ctwindow > 127)
			return -EINVAL;
		if (params.p2p_ctwindow != 0 &&
		    !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
			return -EINVAL;
	}

	if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
		u8 tmp;

		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
			return -EINVAL;
		tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
		if (tmp > 1)
			return -EINVAL;
		params.p2p_opp_ps = tmp;
		if (params.p2p_opp_ps != 0 &&
		    !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
			return -EINVAL;
	}

3311
	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
3312 3313 3314 3315 3316
		err = nl80211_parse_chandef(rdev, info, &params.chandef);
		if (err)
			return err;
	} else if (wdev->preset_chandef.chan) {
		params.chandef = wdev->preset_chandef;
3317
	} else if (!nl80211_get_ap_channel(rdev, &params))
3318 3319
		return -EINVAL;

3320 3321
	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
				     wdev->iftype))
3322 3323
		return -EINVAL;

3324 3325 3326 3327 3328 3329
	if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
		params.acl = parse_acl_data(&rdev->wiphy, info);
		if (IS_ERR(params.acl))
			return PTR_ERR(params.acl);
	}

3330
	wdev_lock(wdev);
3331
	err = rdev_start_ap(rdev, dev, &params);
3332
	if (!err) {
3333
		wdev->preset_chandef = params.chandef;
3334
		wdev->beacon_interval = params.beacon_interval;
3335
		wdev->chandef = params.chandef;
3336 3337
		wdev->ssid_len = params.ssid_len;
		memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
3338
	}
3339
	wdev_unlock(wdev);
3340 3341 3342

	kfree(params.acl);

3343
	return err;
3344 3345
}

3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363
static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_beacon_data params;
	int err;

	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
		return -EOPNOTSUPP;

	if (!rdev->ops->change_beacon)
		return -EOPNOTSUPP;

	if (!wdev->beacon_interval)
		return -EINVAL;

3364
	err = nl80211_parse_beacon(info->attrs, &params);
3365 3366 3367
	if (err)
		return err;

3368 3369 3370 3371 3372
	wdev_lock(wdev);
	err = rdev_change_beacon(rdev, dev, &params);
	wdev_unlock(wdev);

	return err;
3373 3374 3375
}

static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
3376
{
3377 3378
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
3379

3380
	return cfg80211_stop_ap(rdev, dev, false);
3381 3382
}

3383 3384 3385 3386
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
	[NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
	[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
	[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
3387
	[NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
3388
	[NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
3389
	[NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
3390 3391
};

3392
static int parse_station_flags(struct genl_info *info,
3393
			       enum nl80211_iftype iftype,
3394
			       struct station_parameters *params)
3395 3396
{
	struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
3397
	struct nlattr *nla;
3398 3399
	int flag;

3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410
	/*
	 * Try parsing the new attribute first so userspace
	 * can specify both for older kernels.
	 */
	nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
	if (nla) {
		struct nl80211_sta_flag_update *sta_flags;

		sta_flags = nla_data(nla);
		params->sta_flags_mask = sta_flags->mask;
		params->sta_flags_set = sta_flags->set;
3411
		params->sta_flags_set &= params->sta_flags_mask;
3412 3413 3414 3415 3416 3417 3418
		if ((params->sta_flags_mask |
		     params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
			return -EINVAL;
		return 0;
	}

	/* if present, parse the old attribute */
3419

3420
	nla = info->attrs[NL80211_ATTR_STA_FLAGS];
3421 3422 3423 3424 3425 3426 3427
	if (!nla)
		return 0;

	if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
			     nla, sta_flags_policy))
		return -EINVAL;

3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454
	/*
	 * Only allow certain flags for interface types so that
	 * other attributes are silently ignored. Remember that
	 * this is backward compatibility code with old userspace
	 * and shouldn't be hit in other cases anyway.
	 */
	switch (iftype) {
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
	case NL80211_IFTYPE_P2P_GO:
		params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
					 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
					 BIT(NL80211_STA_FLAG_WME) |
					 BIT(NL80211_STA_FLAG_MFP);
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_STATION:
		params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
					 BIT(NL80211_STA_FLAG_TDLS_PEER);
		break;
	case NL80211_IFTYPE_MESH_POINT:
		params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
					 BIT(NL80211_STA_FLAG_MFP) |
					 BIT(NL80211_STA_FLAG_AUTHORIZED);
	default:
		return -EINVAL;
	}
3455

3456 3457
	for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
		if (flags[flag]) {
3458
			params->sta_flags_set |= (1<<flag);
3459

3460 3461 3462 3463 3464 3465
			/* no longer support new API additions in old API */
			if (flag > NL80211_STA_FLAG_MAX_OLD_API)
				return -EINVAL;
		}
	}

3466 3467 3468
	return 0;
}

3469 3470 3471 3472
static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
				 int attr)
{
	struct nlattr *rate;
3473 3474
	u32 bitrate;
	u16 bitrate_compat;
3475 3476 3477

	rate = nla_nest_start(msg, attr);
	if (!rate)
3478
		return false;
3479 3480 3481

	/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
	bitrate = cfg80211_calculate_bitrate(info);
3482 3483
	/* report 16-bit bitrate only if we can */
	bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520
	if (bitrate > 0 &&
	    nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
		return false;
	if (bitrate_compat > 0 &&
	    nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
		return false;

	if (info->flags & RATE_INFO_FLAGS_MCS) {
		if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
			return false;
		if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
		    nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
			return false;
		if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
		    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
			return false;
	} else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
		if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
			return false;
		if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
			return false;
		if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
		    nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
			return false;
		if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
		    nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
			return false;
		if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
		    nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
			return false;
		if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
		    nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
			return false;
		if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
		    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
			return false;
	}
3521 3522 3523 3524 3525

	nla_nest_end(msg, rate);
	return true;
}

3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551
static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
			       int id)
{
	void *attr;
	int i = 0;

	if (!mask)
		return true;

	attr = nla_nest_start(msg, id);
	if (!attr)
		return false;

	for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
		if (!(mask & BIT(i)))
			continue;

		if (nla_put_u8(msg, i, signal[i]))
			return false;
	}

	nla_nest_end(msg, attr);

	return true;
}

3552
static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
3553 3554 3555
				int flags,
				struct cfg80211_registered_device *rdev,
				struct net_device *dev,
3556
				const u8 *mac_addr, struct station_info *sinfo)
3557 3558
{
	void *hdr;
3559
	struct nlattr *sinfoattr, *bss_param;
3560

3561
	hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION);
3562 3563 3564
	if (!hdr)
		return -1;

3565 3566 3567 3568
	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
	    nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
		goto nla_put_failure;
3569

3570 3571
	sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
	if (!sinfoattr)
3572
		goto nla_put_failure;
3573 3574 3575 3576 3577 3578 3579 3580
	if ((sinfo->filled & STATION_INFO_CONNECTED_TIME) &&
	    nla_put_u32(msg, NL80211_STA_INFO_CONNECTED_TIME,
			sinfo->connected_time))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_INACTIVE_TIME) &&
	    nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME,
			sinfo->inactive_time))
		goto nla_put_failure;
3581 3582
	if ((sinfo->filled & (STATION_INFO_RX_BYTES |
			      STATION_INFO_RX_BYTES64)) &&
3583
	    nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
3584
			(u32)sinfo->rx_bytes))
3585
		goto nla_put_failure;
3586
	if ((sinfo->filled & (STATION_INFO_TX_BYTES |
3587
			      STATION_INFO_TX_BYTES64)) &&
3588
	    nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
3589 3590 3591 3592 3593 3594 3595 3596
			(u32)sinfo->tx_bytes))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_RX_BYTES64) &&
	    nla_put_u64(msg, NL80211_STA_INFO_RX_BYTES64,
			sinfo->rx_bytes))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_TX_BYTES64) &&
	    nla_put_u64(msg, NL80211_STA_INFO_TX_BYTES64,
3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608
			sinfo->tx_bytes))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_LLID) &&
	    nla_put_u16(msg, NL80211_STA_INFO_LLID, sinfo->llid))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_PLID) &&
	    nla_put_u16(msg, NL80211_STA_INFO_PLID, sinfo->plid))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_PLINK_STATE) &&
	    nla_put_u8(msg, NL80211_STA_INFO_PLINK_STATE,
		       sinfo->plink_state))
		goto nla_put_failure;
3609 3610
	switch (rdev->wiphy.signal_type) {
	case CFG80211_SIGNAL_TYPE_MBM:
3611 3612 3613 3614 3615 3616 3617 3618
		if ((sinfo->filled & STATION_INFO_SIGNAL) &&
		    nla_put_u8(msg, NL80211_STA_INFO_SIGNAL,
			       sinfo->signal))
			goto nla_put_failure;
		if ((sinfo->filled & STATION_INFO_SIGNAL_AVG) &&
		    nla_put_u8(msg, NL80211_STA_INFO_SIGNAL_AVG,
			       sinfo->signal_avg))
			goto nla_put_failure;
3619 3620 3621 3622
		break;
	default:
		break;
	}
3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634
	if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) {
		if (!nl80211_put_signal(msg, sinfo->chains,
					sinfo->chain_signal,
					NL80211_STA_INFO_CHAIN_SIGNAL))
			goto nla_put_failure;
	}
	if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) {
		if (!nl80211_put_signal(msg, sinfo->chains,
					sinfo->chain_signal_avg,
					NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
			goto nla_put_failure;
	}
3635
	if (sinfo->filled & STATION_INFO_TX_BITRATE) {
3636 3637 3638 3639 3640 3641 3642
		if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
					  NL80211_STA_INFO_TX_BITRATE))
			goto nla_put_failure;
	}
	if (sinfo->filled & STATION_INFO_RX_BITRATE) {
		if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
					  NL80211_STA_INFO_RX_BITRATE))
3643 3644
			goto nla_put_failure;
	}
3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660
	if ((sinfo->filled & STATION_INFO_RX_PACKETS) &&
	    nla_put_u32(msg, NL80211_STA_INFO_RX_PACKETS,
			sinfo->rx_packets))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_TX_PACKETS) &&
	    nla_put_u32(msg, NL80211_STA_INFO_TX_PACKETS,
			sinfo->tx_packets))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_TX_RETRIES) &&
	    nla_put_u32(msg, NL80211_STA_INFO_TX_RETRIES,
			sinfo->tx_retries))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_TX_FAILED) &&
	    nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED,
			sinfo->tx_failed))
		goto nla_put_failure;
3661 3662 3663 3664
	if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) &&
	    nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT,
			sinfo->expected_throughput))
		goto nla_put_failure;
3665 3666 3667 3668
	if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) &&
	    nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS,
			sinfo->beacon_loss_count))
		goto nla_put_failure;
3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680
	if ((sinfo->filled & STATION_INFO_LOCAL_PM) &&
	    nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM,
			sinfo->local_pm))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_PEER_PM) &&
	    nla_put_u32(msg, NL80211_STA_INFO_PEER_PM,
			sinfo->peer_pm))
		goto nla_put_failure;
	if ((sinfo->filled & STATION_INFO_NONPEER_PM) &&
	    nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM,
			sinfo->nonpeer_pm))
		goto nla_put_failure;
3681 3682 3683 3684 3685
	if (sinfo->filled & STATION_INFO_BSS_PARAM) {
		bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
		if (!bss_param)
			goto nla_put_failure;

3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696
		if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
		     nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
		    ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
		     nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
		    ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
		     nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
		    nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
			       sinfo->bss_param.dtim_period) ||
		    nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
				sinfo->bss_param.beacon_interval))
			goto nla_put_failure;
3697 3698 3699

		nla_nest_end(msg, bss_param);
	}
3700 3701 3702 3703 3704
	if ((sinfo->filled & STATION_INFO_STA_FLAGS) &&
	    nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
		    sizeof(struct nl80211_sta_flag_update),
		    &sinfo->sta_flags))
		goto nla_put_failure;
3705 3706 3707 3708
	if ((sinfo->filled & STATION_INFO_T_OFFSET) &&
		nla_put_u64(msg, NL80211_STA_INFO_T_OFFSET,
			    sinfo->t_offset))
		goto nla_put_failure;
3709
	nla_nest_end(msg, sinfoattr);
3710

3711 3712 3713 3714
	if ((sinfo->filled & STATION_INFO_ASSOC_REQ_IES) &&
	    nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
		    sinfo->assoc_req_ies))
		goto nla_put_failure;
3715

3716 3717 3718
	return genlmsg_end(msg, hdr);

 nla_put_failure:
3719 3720
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
3721 3722
}

3723
static int nl80211_dump_station(struct sk_buff *skb,
J
Johannes Berg 已提交
3724
				struct netlink_callback *cb)
3725 3726
{
	struct station_info sinfo;
3727
	struct cfg80211_registered_device *rdev;
3728
	struct wireless_dev *wdev;
3729
	u8 mac_addr[ETH_ALEN];
3730
	int sta_idx = cb->args[2];
3731 3732
	int err;

3733
	err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
3734 3735
	if (err)
		return err;
J
Johannes Berg 已提交
3736

3737 3738 3739 3740 3741
	if (!wdev->netdev) {
		err = -EINVAL;
		goto out_err;
	}

3742
	if (!rdev->ops->dump_station) {
3743
		err = -EOPNOTSUPP;
J
Johannes Berg 已提交
3744 3745 3746 3747
		goto out_err;
	}

	while (1) {
3748
		memset(&sinfo, 0, sizeof(sinfo));
3749
		err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
3750
					mac_addr, &sinfo);
J
Johannes Berg 已提交
3751 3752 3753
		if (err == -ENOENT)
			break;
		if (err)
J
Johannes Berg 已提交
3754
			goto out_err;
J
Johannes Berg 已提交
3755 3756

		if (nl80211_send_station(skb,
3757
				NETLINK_CB(cb->skb).portid,
J
Johannes Berg 已提交
3758
				cb->nlh->nlmsg_seq, NLM_F_MULTI,
3759
				rdev, wdev->netdev, mac_addr,
J
Johannes Berg 已提交
3760 3761 3762 3763 3764 3765 3766 3767
				&sinfo) < 0)
			goto out;

		sta_idx++;
	}


 out:
3768
	cb->args[2] = sta_idx;
J
Johannes Berg 已提交
3769 3770
	err = skb->len;
 out_err:
3771
	nl80211_finish_wdev_dump(rdev);
J
Johannes Berg 已提交
3772 3773

	return err;
3774
}
3775

3776 3777
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
{
3778 3779
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
3780
	struct station_info sinfo;
3781 3782
	struct sk_buff *msg;
	u8 *mac_addr = NULL;
3783
	int err;
3784

3785
	memset(&sinfo, 0, sizeof(sinfo));
3786 3787 3788 3789 3790 3791

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

3792 3793
	if (!rdev->ops->get_station)
		return -EOPNOTSUPP;
J
Johannes Berg 已提交
3794

3795
	err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
3796
	if (err)
3797
		return err;
3798

3799
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3800
	if (!msg)
3801
		return -ENOMEM;
3802

3803
	if (nl80211_send_station(msg, info->snd_portid, info->snd_seq, 0,
3804
				 rdev, dev, mac_addr, &sinfo) < 0) {
3805 3806 3807
		nlmsg_free(msg);
		return -ENOBUFS;
	}
J
Johannes Berg 已提交
3808

3809
	return genlmsg_reply(msg, info);
3810 3811
}

3812 3813 3814 3815 3816 3817
int cfg80211_check_station_change(struct wiphy *wiphy,
				  struct station_parameters *params,
				  enum cfg80211_station_type statype)
{
	if (params->listen_interval != -1)
		return -EINVAL;
3818 3819
	if (params->aid &&
	    !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
3820 3821 3822 3823 3824 3825
		return -EINVAL;

	/* When you run into this, adjust the code below for the new flag */
	BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);

	switch (statype) {
3826 3827
	case CFG80211_STA_MESH_PEER_KERNEL:
	case CFG80211_STA_MESH_PEER_USER:
3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928
		/*
		 * No ignoring the TDLS flag here -- the userspace mesh
		 * code doesn't have the bug of including TDLS in the
		 * mask everywhere.
		 */
		if (params->sta_flags_mask &
				~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
				  BIT(NL80211_STA_FLAG_MFP) |
				  BIT(NL80211_STA_FLAG_AUTHORIZED)))
			return -EINVAL;
		break;
	case CFG80211_STA_TDLS_PEER_SETUP:
	case CFG80211_STA_TDLS_PEER_ACTIVE:
		if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
			return -EINVAL;
		/* ignore since it can't change */
		params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
		break;
	default:
		/* disallow mesh-specific things */
		if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
			return -EINVAL;
		if (params->local_pm)
			return -EINVAL;
		if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
			return -EINVAL;
	}

	if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
	    statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
		/* TDLS can't be set, ... */
		if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
			return -EINVAL;
		/*
		 * ... but don't bother the driver with it. This works around
		 * a hostapd/wpa_supplicant issue -- it always includes the
		 * TLDS_PEER flag in the mask even for AP mode.
		 */
		params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
	}

	if (statype != CFG80211_STA_TDLS_PEER_SETUP) {
		/* reject other things that can't change */
		if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
			return -EINVAL;
		if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
			return -EINVAL;
		if (params->supported_rates)
			return -EINVAL;
		if (params->ext_capab || params->ht_capa || params->vht_capa)
			return -EINVAL;
	}

	if (statype != CFG80211_STA_AP_CLIENT) {
		if (params->vlan)
			return -EINVAL;
	}

	switch (statype) {
	case CFG80211_STA_AP_MLME_CLIENT:
		/* Use this only for authorizing/unauthorizing a station */
		if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
			return -EOPNOTSUPP;
		break;
	case CFG80211_STA_AP_CLIENT:
		/* accept only the listed bits */
		if (params->sta_flags_mask &
				~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
				  BIT(NL80211_STA_FLAG_AUTHENTICATED) |
				  BIT(NL80211_STA_FLAG_ASSOCIATED) |
				  BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
				  BIT(NL80211_STA_FLAG_WME) |
				  BIT(NL80211_STA_FLAG_MFP)))
			return -EINVAL;

		/* but authenticated/associated only if driver handles it */
		if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
		    params->sta_flags_mask &
				(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
				 BIT(NL80211_STA_FLAG_ASSOCIATED)))
			return -EINVAL;
		break;
	case CFG80211_STA_IBSS:
	case CFG80211_STA_AP_STA:
		/* reject any changes other than AUTHORIZED */
		if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
			return -EINVAL;
		break;
	case CFG80211_STA_TDLS_PEER_SETUP:
		/* reject any changes other than AUTHORIZED or WME */
		if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
					       BIT(NL80211_STA_FLAG_WME)))
			return -EINVAL;
		/* force (at least) rates when authorizing */
		if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
		    !params->supported_rates)
			return -EINVAL;
		break;
	case CFG80211_STA_TDLS_PEER_ACTIVE:
		/* reject any changes */
		return -EINVAL;
3929
	case CFG80211_STA_MESH_PEER_KERNEL:
3930 3931 3932
		if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
			return -EINVAL;
		break;
3933
	case CFG80211_STA_MESH_PEER_USER:
3934 3935 3936 3937 3938 3939 3940 3941 3942
		if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
			return -EINVAL;
		break;
	}

	return 0;
}
EXPORT_SYMBOL(cfg80211_check_station_change);

3943
/*
3944
 * Get vlan interface making sure it is running and on the right wiphy.
3945
 */
3946 3947
static struct net_device *get_vlan(struct genl_info *info,
				   struct cfg80211_registered_device *rdev)
3948
{
3949
	struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962
	struct net_device *v;
	int ret;

	if (!vlanattr)
		return NULL;

	v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
	if (!v)
		return ERR_PTR(-ENODEV);

	if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
		ret = -EINVAL;
		goto error;
3963
	}
3964

3965 3966 3967 3968 3969 3970 3971
	if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
	    v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
	    v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
		ret = -EINVAL;
		goto error;
	}

3972 3973 3974 3975 3976 3977 3978 3979 3980
	if (!netif_running(v)) {
		ret = -ENETDOWN;
		goto error;
	}

	return v;
 error:
	dev_put(v);
	return ERR_PTR(ret);
3981 3982
}

3983 3984
static const struct nla_policy
nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
3985 3986 3987 3988
	[NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
	[NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
};

3989 3990
static int nl80211_parse_sta_wme(struct genl_info *info,
				 struct station_parameters *params)
3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022
{
	struct nlattr *tb[NL80211_STA_WME_MAX + 1];
	struct nlattr *nla;
	int err;

	/* parse WME attributes if present */
	if (!info->attrs[NL80211_ATTR_STA_WME])
		return 0;

	nla = info->attrs[NL80211_ATTR_STA_WME];
	err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
			       nl80211_sta_wme_policy);
	if (err)
		return err;

	if (tb[NL80211_STA_WME_UAPSD_QUEUES])
		params->uapsd_queues = nla_get_u8(
			tb[NL80211_STA_WME_UAPSD_QUEUES]);
	if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
		return -EINVAL;

	if (tb[NL80211_STA_WME_MAX_SP])
		params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);

	if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
		return -EINVAL;

	params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;

	return 0;
}

4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057
static int nl80211_parse_sta_channel_info(struct genl_info *info,
				      struct station_parameters *params)
{
	if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
		params->supported_channels =
		     nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
		params->supported_channels_len =
		     nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
		/*
		 * Need to include at least one (first channel, number of
		 * channels) tuple for each subband, and must have proper
		 * tuples for the rest of the data as well.
		 */
		if (params->supported_channels_len < 2)
			return -EINVAL;
		if (params->supported_channels_len % 2)
			return -EINVAL;
	}

	if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
		params->supported_oper_classes =
		 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
		params->supported_oper_classes_len =
		  nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
		/*
		 * The value of the Length field of the Supported Operating
		 * Classes element is between 2 and 253.
		 */
		if (params->supported_oper_classes_len < 2 ||
		    params->supported_oper_classes_len > 253)
			return -EINVAL;
	}
	return 0;
}

4058 4059 4060
static int nl80211_set_station_tdls(struct genl_info *info,
				    struct station_parameters *params)
{
4061
	int err;
4062
	/* Dummy STA entry gets updated once the peer capabilities are known */
4063 4064
	if (info->attrs[NL80211_ATTR_PEER_AID])
		params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
4065 4066 4067 4068 4069 4070 4071
	if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
		params->ht_capa =
			nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
	if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
		params->vht_capa =
			nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);

4072 4073 4074 4075
	err = nl80211_parse_sta_channel_info(info, params);
	if (err)
		return err;

4076 4077 4078
	return nl80211_parse_sta_wme(info, params);
}

4079 4080
static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
{
4081 4082
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
4083
	struct station_parameters params;
4084 4085
	u8 *mac_addr;
	int err;
4086 4087 4088 4089 4090

	memset(&params, 0, sizeof(params));

	params.listen_interval = -1;

4091 4092 4093
	if (!rdev->ops->change_station)
		return -EOPNOTSUPP;

4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108
	if (info->attrs[NL80211_ATTR_STA_AID])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

	if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
		params.supported_rates =
			nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
		params.supported_rates_len =
			nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
	}

4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121
	if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
		params.capability =
			nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
		params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
	}

	if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
		params.ext_capab =
			nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
		params.ext_capab_len =
			nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
	}

4122
	if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4123
		return -EINVAL;
4124

4125
	if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
4126 4127
		return -EINVAL;

4128
	if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
4129
		params.plink_action =
4130 4131 4132 4133
			nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
		if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
			return -EINVAL;
	}
4134

4135
	if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
4136
		params.plink_state =
4137 4138 4139 4140 4141
			nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
		if (params.plink_state >= NUM_NL80211_PLINK_STATES)
			return -EINVAL;
		params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
	}
4142

4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153
	if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
		enum nl80211_mesh_power_mode pm = nla_get_u32(
			info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);

		if (pm <= NL80211_MESH_POWER_UNKNOWN ||
		    pm > NL80211_MESH_POWER_MAX)
			return -EINVAL;

		params.local_pm = pm;
	}

4154 4155 4156 4157 4158 4159 4160 4161 4162
	/* Include parameters for TDLS peer (will check later) */
	err = nl80211_set_station_tdls(info, &params);
	if (err)
		return err;

	params.vlan = get_vlan(info, rdev);
	if (IS_ERR(params.vlan))
		return PTR_ERR(params.vlan);

4163 4164 4165
	switch (dev->ieee80211_ptr->iftype) {
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
4166 4167
	case NL80211_IFTYPE_P2P_GO:
	case NL80211_IFTYPE_P2P_CLIENT:
4168
	case NL80211_IFTYPE_STATION:
4169
	case NL80211_IFTYPE_ADHOC:
4170 4171 4172
	case NL80211_IFTYPE_MESH_POINT:
		break;
	default:
4173 4174
		err = -EOPNOTSUPP;
		goto out_put_vlan;
4175 4176
	}

4177
	/* driver will call cfg80211_check_station_change() */
4178
	err = rdev_change_station(rdev, dev, mac_addr, &params);
4179

4180
 out_put_vlan:
4181 4182
	if (params.vlan)
		dev_put(params.vlan);
J
Johannes Berg 已提交
4183

4184 4185 4186 4187 4188
	return err;
}

static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
{
4189
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
4190
	int err;
4191
	struct net_device *dev = info->user_ptr[1];
4192 4193 4194 4195 4196
	struct station_parameters params;
	u8 *mac_addr = NULL;

	memset(&params, 0, sizeof(params));

4197 4198 4199
	if (!rdev->ops->add_station)
		return -EOPNOTSUPP;

4200 4201 4202 4203 4204 4205 4206 4207 4208
	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
		return -EINVAL;

4209 4210
	if (!info->attrs[NL80211_ATTR_STA_AID] &&
	    !info->attrs[NL80211_ATTR_PEER_AID])
4211 4212
		return -EINVAL;

4213 4214 4215 4216 4217 4218 4219
	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
	params.supported_rates =
		nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
	params.supported_rates_len =
		nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
	params.listen_interval =
		nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
4220

4221
	if (info->attrs[NL80211_ATTR_PEER_AID])
4222
		params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
4223 4224
	else
		params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
4225 4226
	if (!params.aid || params.aid > IEEE80211_MAX_AID)
		return -EINVAL;
4227

4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240
	if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
		params.capability =
			nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
		params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
	}

	if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
		params.ext_capab =
			nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
		params.ext_capab_len =
			nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
	}

4241 4242 4243
	if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
		params.ht_capa =
			nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
4244

M
Mahesh Palivela 已提交
4245 4246 4247 4248
	if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
		params.vht_capa =
			nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);

4249 4250 4251 4252 4253 4254
	if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
		params.opmode_notif_used = true;
		params.opmode_notif =
			nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
	}

4255
	if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
4256
		params.plink_action =
4257 4258 4259 4260
			nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
		if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
			return -EINVAL;
	}
4261

4262 4263 4264 4265
	err = nl80211_parse_sta_channel_info(info, &params);
	if (err)
		return err;

4266 4267 4268
	err = nl80211_parse_sta_wme(info, &params);
	if (err)
		return err;
4269

4270
	if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
4271 4272
		return -EINVAL;

4273 4274 4275
	/* When you run into this, adjust the code below for the new flag */
	BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);

4276 4277 4278 4279
	switch (dev->ieee80211_ptr->iftype) {
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
	case NL80211_IFTYPE_P2P_GO:
4280 4281 4282 4283
		/* ignore WME attributes if iface/sta is not capable */
		if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
		    !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
			params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
4284

4285
		/* TDLS peers cannot be added */
4286 4287
		if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
		    info->attrs[NL80211_ATTR_PEER_AID])
4288
			return -EINVAL;
4289 4290
		/* but don't bother the driver with it */
		params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4291

4292 4293 4294 4295 4296 4297 4298 4299
		/* allow authenticated/associated only if driver handles it */
		if (!(rdev->wiphy.features &
				NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
		    params.sta_flags_mask &
				(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
				 BIT(NL80211_STA_FLAG_ASSOCIATED)))
			return -EINVAL;

4300 4301 4302 4303 4304 4305
		/* must be last in here for error handling */
		params.vlan = get_vlan(info, rdev);
		if (IS_ERR(params.vlan))
			return PTR_ERR(params.vlan);
		break;
	case NL80211_IFTYPE_MESH_POINT:
4306 4307 4308
		/* ignore uAPSD data */
		params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;

4309 4310 4311
		/* associated is disallowed */
		if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
			return -EINVAL;
4312
		/* TDLS peers cannot be added */
4313 4314
		if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
		    info->attrs[NL80211_ATTR_PEER_AID])
4315 4316 4317
			return -EINVAL;
		break;
	case NL80211_IFTYPE_STATION:
4318
	case NL80211_IFTYPE_P2P_CLIENT:
4319 4320 4321
		/* ignore uAPSD data */
		params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;

4322 4323 4324 4325
		/* these are disallowed */
		if (params.sta_flags_mask &
				(BIT(NL80211_STA_FLAG_ASSOCIATED) |
				 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
4326
			return -EINVAL;
4327 4328 4329 4330 4331 4332 4333 4334 4335
		/* Only TDLS peers can be added */
		if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
			return -EINVAL;
		/* Can only add if TDLS ... */
		if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
			return -EOPNOTSUPP;
		/* ... with external setup is supported */
		if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
			return -EOPNOTSUPP;
4336 4337 4338 4339 4340
		/*
		 * Older wpa_supplicant versions always mark the TDLS peer
		 * as authorized, but it shouldn't yet be.
		 */
		params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
4341 4342 4343
		break;
	default:
		return -EOPNOTSUPP;
4344 4345
	}

4346
	/* be aware of params.vlan when changing code here */
4347

4348
	err = rdev_add_station(rdev, dev, mac_addr, &params);
4349 4350 4351 4352 4353 4354 4355 4356

	if (params.vlan)
		dev_put(params.vlan);
	return err;
}

static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
{
4357 4358
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
4359 4360 4361 4362 4363
	u8 *mac_addr = NULL;

	if (info->attrs[NL80211_ATTR_MAC])
		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

4364
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4365
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
4366
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
4367 4368
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
		return -EINVAL;
4369

4370 4371
	if (!rdev->ops->del_station)
		return -EOPNOTSUPP;
J
Johannes Berg 已提交
4372

4373
	return rdev_del_station(rdev, dev, mac_addr);
4374 4375
}

4376
static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
4377 4378 4379 4380 4381 4382 4383
				int flags, struct net_device *dev,
				u8 *dst, u8 *next_hop,
				struct mpath_info *pinfo)
{
	void *hdr;
	struct nlattr *pinfoattr;

4384
	hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION);
4385 4386 4387
	if (!hdr)
		return -1;

4388 4389 4390 4391 4392
	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
	    nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
	    nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
		goto nla_put_failure;
4393

4394 4395 4396
	pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
	if (!pinfoattr)
		goto nla_put_failure;
4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418
	if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
	    nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
			pinfo->frame_qlen))
		goto nla_put_failure;
	if (((pinfo->filled & MPATH_INFO_SN) &&
	     nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
	    ((pinfo->filled & MPATH_INFO_METRIC) &&
	     nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
			 pinfo->metric)) ||
	    ((pinfo->filled & MPATH_INFO_EXPTIME) &&
	     nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
			 pinfo->exptime)) ||
	    ((pinfo->filled & MPATH_INFO_FLAGS) &&
	     nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
			pinfo->flags)) ||
	    ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
	     nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
			 pinfo->discovery_timeout)) ||
	    ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
	     nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
			pinfo->discovery_retries)))
		goto nla_put_failure;
4419 4420 4421 4422 4423 4424

	nla_nest_end(msg, pinfoattr);

	return genlmsg_end(msg, hdr);

 nla_put_failure:
4425 4426
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
4427 4428 4429
}

static int nl80211_dump_mpath(struct sk_buff *skb,
J
Johannes Berg 已提交
4430
			      struct netlink_callback *cb)
4431 4432
{
	struct mpath_info pinfo;
4433
	struct cfg80211_registered_device *rdev;
4434
	struct wireless_dev *wdev;
4435 4436
	u8 dst[ETH_ALEN];
	u8 next_hop[ETH_ALEN];
4437
	int path_idx = cb->args[2];
4438 4439
	int err;

4440
	err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
4441 4442
	if (err)
		return err;
J
Johannes Berg 已提交
4443

4444
	if (!rdev->ops->dump_mpath) {
4445
		err = -EOPNOTSUPP;
J
Johannes Berg 已提交
4446 4447 4448
		goto out_err;
	}

4449
	if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
4450
		err = -EOPNOTSUPP;
4451
		goto out_err;
4452 4453
	}

J
Johannes Berg 已提交
4454
	while (1) {
4455
		err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
4456
				      next_hop, &pinfo);
J
Johannes Berg 已提交
4457
		if (err == -ENOENT)
4458
			break;
J
Johannes Berg 已提交
4459
		if (err)
J
Johannes Berg 已提交
4460
			goto out_err;
4461

4462
		if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
J
Johannes Berg 已提交
4463
				       cb->nlh->nlmsg_seq, NLM_F_MULTI,
4464
				       wdev->netdev, dst, next_hop,
J
Johannes Berg 已提交
4465 4466
				       &pinfo) < 0)
			goto out;
4467

J
Johannes Berg 已提交
4468
		path_idx++;
4469 4470 4471
	}


J
Johannes Berg 已提交
4472
 out:
4473
	cb->args[2] = path_idx;
J
Johannes Berg 已提交
4474 4475
	err = skb->len;
 out_err:
4476
	nl80211_finish_wdev_dump(rdev);
J
Johannes Berg 已提交
4477
	return err;
4478 4479 4480 4481
}

static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
{
4482
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
4483
	int err;
4484
	struct net_device *dev = info->user_ptr[1];
4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496
	struct mpath_info pinfo;
	struct sk_buff *msg;
	u8 *dst = NULL;
	u8 next_hop[ETH_ALEN];

	memset(&pinfo, 0, sizeof(pinfo));

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	dst = nla_data(info->attrs[NL80211_ATTR_MAC]);

4497 4498
	if (!rdev->ops->get_mpath)
		return -EOPNOTSUPP;
4499

4500 4501
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
		return -EOPNOTSUPP;
4502

4503
	err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
4504
	if (err)
4505
		return err;
4506

4507
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4508
	if (!msg)
4509
		return -ENOMEM;
4510

4511
	if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
4512 4513 4514 4515
				 dev, dst, next_hop, &pinfo) < 0) {
		nlmsg_free(msg);
		return -ENOBUFS;
	}
J
Johannes Berg 已提交
4516

4517
	return genlmsg_reply(msg, info);
4518 4519 4520 4521
}

static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
{
4522 4523
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535
	u8 *dst = NULL;
	u8 *next_hop = NULL;

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
		return -EINVAL;

	dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
	next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);

4536 4537
	if (!rdev->ops->change_mpath)
		return -EOPNOTSUPP;
4538

4539 4540
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
		return -EOPNOTSUPP;
4541

4542
	return rdev_change_mpath(rdev, dev, dst, next_hop);
4543
}
4544

4545 4546
static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
{
4547 4548
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560
	u8 *dst = NULL;
	u8 *next_hop = NULL;

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
		return -EINVAL;

	dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
	next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);

4561 4562
	if (!rdev->ops->add_mpath)
		return -EOPNOTSUPP;
4563

4564 4565
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
		return -EOPNOTSUPP;
4566

4567
	return rdev_add_mpath(rdev, dev, dst, next_hop);
4568 4569 4570 4571
}

static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
{
4572 4573
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
4574 4575 4576 4577 4578
	u8 *dst = NULL;

	if (info->attrs[NL80211_ATTR_MAC])
		dst = nla_data(info->attrs[NL80211_ATTR_MAC]);

4579 4580
	if (!rdev->ops->del_mpath)
		return -EOPNOTSUPP;
J
Johannes Berg 已提交
4581

4582
	return rdev_del_mpath(rdev, dev, dst);
4583 4584
}

4585 4586
static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
{
4587 4588
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
4589
	struct wireless_dev *wdev = dev->ieee80211_ptr;
4590
	struct bss_parameters params;
4591
	int err;
4592 4593 4594 4595 4596 4597

	memset(&params, 0, sizeof(params));
	/* default to not changing parameters */
	params.use_cts_prot = -1;
	params.use_short_preamble = -1;
	params.use_short_slot_time = -1;
4598
	params.ap_isolate = -1;
4599
	params.ht_opmode = -1;
4600 4601
	params.p2p_ctwindow = -1;
	params.p2p_opp_ps = -1;
4602 4603 4604 4605 4606 4607 4608 4609 4610 4611

	if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
		params.use_cts_prot =
		    nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
	if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
		params.use_short_preamble =
		    nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
	if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
		params.use_short_slot_time =
		    nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
4612 4613 4614 4615 4616 4617
	if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
		params.basic_rates =
			nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
		params.basic_rates_len =
			nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
	}
4618 4619
	if (info->attrs[NL80211_ATTR_AP_ISOLATE])
		params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
4620 4621 4622
	if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
		params.ht_opmode =
			nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
4623

4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649
	if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
			return -EINVAL;
		params.p2p_ctwindow =
			nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
		if (params.p2p_ctwindow < 0)
			return -EINVAL;
		if (params.p2p_ctwindow != 0 &&
		    !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
			return -EINVAL;
	}

	if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
		u8 tmp;

		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
			return -EINVAL;
		tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
		if (tmp > 1)
			return -EINVAL;
		params.p2p_opp_ps = tmp;
		if (params.p2p_opp_ps &&
		    !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
			return -EINVAL;
	}

4650 4651
	if (!rdev->ops->change_bss)
		return -EOPNOTSUPP;
4652

4653
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4654 4655
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
		return -EOPNOTSUPP;
J
Johannes Berg 已提交
4656

4657 4658 4659 4660 4661
	wdev_lock(wdev);
	err = rdev_change_bss(rdev, dev, &params);
	wdev_unlock(wdev);

	return err;
4662 4663
}

A
Alexey Dobriyan 已提交
4664
static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
4665 4666 4667 4668 4669 4670
	[NL80211_ATTR_REG_RULE_FLAGS]		= { .type = NLA_U32 },
	[NL80211_ATTR_FREQ_RANGE_START]		= { .type = NLA_U32 },
	[NL80211_ATTR_FREQ_RANGE_END]		= { .type = NLA_U32 },
	[NL80211_ATTR_FREQ_RANGE_MAX_BW]	= { .type = NLA_U32 },
	[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]	= { .type = NLA_U32 },
	[NL80211_ATTR_POWER_RULE_MAX_EIRP]	= { .type = NLA_U32 },
4671
	[NL80211_ATTR_DFS_CAC_TIME]		= { .type = NLA_U32 },
4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685
};

static int parse_reg_rule(struct nlattr *tb[],
	struct ieee80211_reg_rule *reg_rule)
{
	struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
	struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;

	if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
		return -EINVAL;
	if (!tb[NL80211_ATTR_FREQ_RANGE_START])
		return -EINVAL;
	if (!tb[NL80211_ATTR_FREQ_RANGE_END])
		return -EINVAL;
4686 4687
	if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
		return -EINVAL;
4688 4689 4690 4691 4692 4693 4694 4695 4696
	if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
		return -EINVAL;

	reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);

	freq_range->start_freq_khz =
		nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
	freq_range->end_freq_khz =
		nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
4697 4698
	freq_range->max_bandwidth_khz =
		nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
4699 4700 4701 4702 4703 4704 4705 4706

	power_rule->max_eirp =
		nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);

	if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
		power_rule->max_antenna_gain =
			nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);

4707 4708 4709 4710
	if (tb[NL80211_ATTR_DFS_CAC_TIME])
		reg_rule->dfs_cac_ms =
			nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);

4711 4712 4713 4714 4715 4716
	return 0;
}

static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{
	char *data = NULL;
4717
	enum nl80211_user_reg_hint_type user_reg_hint_type;
4718

4719 4720 4721 4722 4723 4724
	/*
	 * You should only get this when cfg80211 hasn't yet initialized
	 * completely when built-in to the kernel right between the time
	 * window between nl80211_init() and regulatory_init(), if that is
	 * even possible.
	 */
4725
	if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
4726
		return -EINPROGRESS;
4727

4728 4729 4730 4731 4732 4733 4734 4735 4736
	if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
		user_reg_hint_type =
		  nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
	else
		user_reg_hint_type = NL80211_USER_REG_HINT_USER;

	switch (user_reg_hint_type) {
	case NL80211_USER_REG_HINT_USER:
	case NL80211_USER_REG_HINT_CELL_BASE:
4737 4738 4739 4740 4741 4742 4743
		if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
			return -EINVAL;

		data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
		return regulatory_hint_user(data, user_reg_hint_type);
	case NL80211_USER_REG_HINT_INDOOR:
		return regulatory_hint_indoor_user();
4744 4745 4746
	default:
		return -EINVAL;
	}
4747 4748
}

4749
static int nl80211_get_mesh_config(struct sk_buff *skb,
4750
				   struct genl_info *info)
4751
{
4752 4753
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
4754 4755 4756
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct mesh_config cur_params;
	int err = 0;
4757 4758 4759 4760
	void *hdr;
	struct nlattr *pinfoattr;
	struct sk_buff *msg;

4761 4762 4763
	if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
		return -EOPNOTSUPP;

4764
	if (!rdev->ops->get_mesh_config)
4765
		return -EOPNOTSUPP;
4766

4767 4768 4769 4770 4771
	wdev_lock(wdev);
	/* If not connected, get default parameters */
	if (!wdev->mesh_id_len)
		memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
	else
4772
		err = rdev_get_mesh_config(rdev, dev, &cur_params);
4773 4774
	wdev_unlock(wdev);

4775
	if (err)
4776
		return err;
4777 4778

	/* Draw up a netlink message to send back */
4779
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4780 4781
	if (!msg)
		return -ENOMEM;
4782
	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
4783
			     NL80211_CMD_GET_MESH_CONFIG);
4784
	if (!hdr)
4785
		goto out;
4786
	pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
4787 4788
	if (!pinfoattr)
		goto nla_put_failure;
4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805
	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
			cur_params.dot11MeshRetryTimeout) ||
	    nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
			cur_params.dot11MeshConfirmTimeout) ||
	    nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
			cur_params.dot11MeshHoldingTimeout) ||
	    nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
			cur_params.dot11MeshMaxPeerLinks) ||
	    nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
		       cur_params.dot11MeshMaxRetries) ||
	    nla_put_u8(msg, NL80211_MESHCONF_TTL,
		       cur_params.dot11MeshTTL) ||
	    nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
		       cur_params.element_ttl) ||
	    nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
		       cur_params.auto_open_plinks) ||
4806 4807
	    nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
			cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830
	    nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
		       cur_params.dot11MeshHWMPmaxPREQretries) ||
	    nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
			cur_params.path_refresh_time) ||
	    nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
			cur_params.min_discovery_timeout) ||
	    nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
			cur_params.dot11MeshHWMPactivePathTimeout) ||
	    nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
			cur_params.dot11MeshHWMPpreqMinInterval) ||
	    nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
			cur_params.dot11MeshHWMPperrMinInterval) ||
	    nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
			cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
	    nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
		       cur_params.dot11MeshHWMPRootMode) ||
	    nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
			cur_params.dot11MeshHWMPRannInterval) ||
	    nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
		       cur_params.dot11MeshGateAnnouncementProtocol) ||
	    nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
		       cur_params.dot11MeshForwarding) ||
	    nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
4831 4832
			cur_params.rssi_threshold) ||
	    nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
4833 4834 4835 4836
			cur_params.ht_opmode) ||
	    nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
			cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
	    nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
4837 4838
			cur_params.dot11MeshHWMProotInterval) ||
	    nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
4839 4840 4841 4842
			cur_params.dot11MeshHWMPconfirmationInterval) ||
	    nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
			cur_params.power_mode) ||
	    nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
4843 4844 4845
			cur_params.dot11MeshAwakeWindowDuration) ||
	    nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
			cur_params.plink_timeout))
4846
		goto nla_put_failure;
4847 4848
	nla_nest_end(msg, pinfoattr);
	genlmsg_end(msg, hdr);
4849
	return genlmsg_reply(msg, info);
4850

J
Johannes Berg 已提交
4851
 nla_put_failure:
4852
	genlmsg_cancel(msg, hdr);
4853
 out:
Y
Yuri Ershov 已提交
4854
	nlmsg_free(msg);
4855
	return -ENOBUFS;
4856 4857
}

A
Alexey Dobriyan 已提交
4858
static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
4859 4860 4861 4862 4863 4864
	[NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
	[NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
	[NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
	[NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
	[NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
	[NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
4865
	[NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
4866
	[NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
4867
	[NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
4868 4869 4870 4871 4872
	[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
	[NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
	[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
	[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
	[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
4873
	[NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
4874
	[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
4875
	[NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
4876
	[NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
4877
	[NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
4878
	[NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
4879 4880
	[NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
	[NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
4881 4882
	[NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
	[NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
4883
	[NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
4884 4885
	[NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
	[NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
4886
	[NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
4887 4888
};

4889 4890
static const struct nla_policy
	nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
4891
	[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
4892 4893
	[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
	[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
4894
	[NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
4895
	[NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
4896
	[NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
4897
	[NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
4898
				    .len = IEEE80211_MAX_DATA_LEN },
4899
	[NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
4900 4901
};

4902
static int nl80211_parse_mesh_config(struct genl_info *info,
4903 4904
				     struct mesh_config *cfg,
				     u32 *mask_out)
4905 4906
{
	struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
4907
	u32 mask = 0;
4908

4909 4910 4911 4912 4913 4914 4915 4916 4917
#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
do {									    \
	if (tb[attr]) {							    \
		if (fn(tb[attr]) < min || fn(tb[attr]) > max)		    \
			return -EINVAL;					    \
		cfg->param = fn(tb[attr]);				    \
		mask |= (1 << (attr - 1));				    \
	}								    \
} while (0)
4918 4919


4920
	if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
4921 4922
		return -EINVAL;
	if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
4923
			     info->attrs[NL80211_ATTR_MESH_CONFIG],
4924
			     nl80211_meshconf_params_policy))
4925 4926 4927 4928 4929 4930 4931
		return -EINVAL;

	/* This makes sure that there aren't more than 32 mesh config
	 * parameters (otherwise our bitfield scheme would not work.) */
	BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);

	/* Fill in the params struct */
4932
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
4933 4934
				  mask, NL80211_MESHCONF_RETRY_TIMEOUT,
				  nla_get_u16);
4935
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
4936 4937
				  mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
				  nla_get_u16);
4938
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
4939 4940
				  mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
				  nla_get_u16);
4941
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
4942 4943
				  mask, NL80211_MESHCONF_MAX_PEER_LINKS,
				  nla_get_u16);
4944
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
4945 4946
				  mask, NL80211_MESHCONF_MAX_RETRIES,
				  nla_get_u8);
4947
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
4948
				  mask, NL80211_MESHCONF_TTL, nla_get_u8);
4949
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
4950 4951
				  mask, NL80211_MESHCONF_ELEMENT_TTL,
				  nla_get_u8);
4952
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
4953 4954
				  mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
				  nla_get_u8);
4955 4956
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
				  1, 255, mask,
4957 4958
				  NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
				  nla_get_u32);
4959
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
4960 4961
				  mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
				  nla_get_u8);
4962
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
4963 4964
				  mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
				  nla_get_u32);
4965
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
4966 4967
				  mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
				  nla_get_u16);
4968 4969
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
				  1, 65535, mask,
4970 4971
				  NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
				  nla_get_u32);
4972
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
4973 4974
				  1, 65535, mask,
				  NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
4975
				  nla_get_u16);
4976
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
4977 4978
				  1, 65535, mask,
				  NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
4979
				  nla_get_u16);
4980
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
4981 4982
				  dot11MeshHWMPnetDiameterTraversalTime,
				  1, 65535, mask,
4983 4984
				  NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
				  nla_get_u16);
4985 4986 4987 4988 4989
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
				  mask, NL80211_MESHCONF_HWMP_ROOTMODE,
				  nla_get_u8);
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
				  mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
4990
				  nla_get_u16);
4991
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
4992 4993
				  dot11MeshGateAnnouncementProtocol, 0, 1,
				  mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
4994
				  nla_get_u8);
4995
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
4996 4997
				  mask, NL80211_MESHCONF_FORWARDING,
				  nla_get_u8);
4998
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
4999
				  mask, NL80211_MESHCONF_RSSI_THRESHOLD,
5000
				  nla_get_s32);
5001
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
5002
				  mask, NL80211_MESHCONF_HT_OPMODE,
5003 5004
				  nla_get_u16);
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
5005
				  1, 65535, mask,
5006 5007
				  NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
				  nla_get_u32);
5008
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
5009
				  mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
5010 5011
				  nla_get_u16);
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
5012 5013
				  dot11MeshHWMPconfirmationInterval,
				  1, 65535, mask,
5014
				  NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
5015
				  nla_get_u16);
5016 5017 5018 5019 5020 5021 5022 5023
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
				  NL80211_MESH_POWER_ACTIVE,
				  NL80211_MESH_POWER_MAX,
				  mask, NL80211_MESHCONF_POWER_MODE,
				  nla_get_u32);
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
				  0, 65535, mask,
				  NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
5024 5025 5026
	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff,
				  mask, NL80211_MESHCONF_PLINK_TIMEOUT,
				  nla_get_u32);
5027 5028
	if (mask_out)
		*mask_out = mask;
5029

5030 5031 5032 5033 5034
	return 0;

#undef FILL_IN_MESH_PARAM_IF_SET
}

5035 5036 5037
static int nl80211_parse_mesh_setup(struct genl_info *info,
				     struct mesh_setup *setup)
{
5038
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
5039 5040 5041 5042 5043 5044 5045 5046 5047
	struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];

	if (!info->attrs[NL80211_ATTR_MESH_SETUP])
		return -EINVAL;
	if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX,
			     info->attrs[NL80211_ATTR_MESH_SETUP],
			     nl80211_mesh_setup_params_policy))
		return -EINVAL;

5048 5049 5050 5051 5052 5053
	if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
		setup->sync_method =
		(nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
		 IEEE80211_SYNC_METHOD_VENDOR :
		 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;

5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065
	if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
		setup->path_sel_proto =
		(nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
		 IEEE80211_PATH_PROTOCOL_VENDOR :
		 IEEE80211_PATH_PROTOCOL_HWMP;

	if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
		setup->path_metric =
		(nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
		 IEEE80211_PATH_METRIC_VENDOR :
		 IEEE80211_PATH_METRIC_AIRTIME;

5066 5067

	if (tb[NL80211_MESH_SETUP_IE]) {
5068
		struct nlattr *ieattr =
5069
			tb[NL80211_MESH_SETUP_IE];
5070 5071
		if (!is_valid_ie_attr(ieattr))
			return -EINVAL;
5072 5073
		setup->ie = nla_data(ieattr);
		setup->ie_len = nla_len(ieattr);
5074
	}
5075 5076 5077 5078
	if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
	    !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
		return -EINVAL;
	setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
5079 5080
	setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
	setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
5081 5082
	if (setup->is_secure)
		setup->user_mpm = true;
5083

5084 5085 5086 5087 5088 5089 5090
	if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
		if (!setup->user_mpm)
			return -EINVAL;
		setup->auth_id =
			nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
	}

5091 5092 5093
	return 0;
}

5094
static int nl80211_update_mesh_config(struct sk_buff *skb,
5095
				      struct genl_info *info)
5096 5097 5098
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
5099
	struct wireless_dev *wdev = dev->ieee80211_ptr;
5100 5101 5102 5103
	struct mesh_config cfg;
	u32 mask;
	int err;

5104 5105 5106
	if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
		return -EOPNOTSUPP;

5107
	if (!rdev->ops->update_mesh_config)
5108 5109
		return -EOPNOTSUPP;

5110
	err = nl80211_parse_mesh_config(info, &cfg, &mask);
5111 5112 5113
	if (err)
		return err;

5114 5115 5116 5117 5118
	wdev_lock(wdev);
	if (!wdev->mesh_id_len)
		err = -ENOLINK;

	if (!err)
5119
		err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
5120 5121 5122 5123

	wdev_unlock(wdev);

	return err;
5124 5125
}

5126 5127
static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
{
5128
	const struct ieee80211_regdomain *regdom;
5129 5130 5131 5132 5133 5134
	struct sk_buff *msg;
	void *hdr = NULL;
	struct nlattr *nl_reg_rules;
	unsigned int i;

	if (!cfg80211_regdomain)
5135
		return -EINVAL;
5136

5137
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5138 5139
	if (!msg)
		return -ENOBUFS;
5140

5141
	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
5142 5143
			     NL80211_CMD_GET_REG);
	if (!hdr)
5144
		goto put_failure;
5145

5146 5147 5148 5149 5150
	if (reg_last_request_cell_base() &&
	    nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
			NL80211_USER_REG_HINT_CELL_BASE))
		goto nla_put_failure;

5151 5152 5153 5154 5155 5156 5157 5158
	rcu_read_lock();
	regdom = rcu_dereference(cfg80211_regdomain);

	if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
	    (regdom->dfs_region &&
	     nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
		goto nla_put_failure_rcu;

5159 5160
	nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
	if (!nl_reg_rules)
5161
		goto nla_put_failure_rcu;
5162

5163
	for (i = 0; i < regdom->n_reg_rules; i++) {
5164 5165 5166 5167
		struct nlattr *nl_reg_rule;
		const struct ieee80211_reg_rule *reg_rule;
		const struct ieee80211_freq_range *freq_range;
		const struct ieee80211_power_rule *power_rule;
5168
		unsigned int max_bandwidth_khz;
5169

5170
		reg_rule = &regdom->reg_rules[i];
5171 5172 5173 5174 5175
		freq_range = &reg_rule->freq_range;
		power_rule = &reg_rule->power_rule;

		nl_reg_rule = nla_nest_start(msg, i);
		if (!nl_reg_rule)
5176
			goto nla_put_failure_rcu;
5177

5178 5179 5180 5181 5182
		max_bandwidth_khz = freq_range->max_bandwidth_khz;
		if (!max_bandwidth_khz)
			max_bandwidth_khz = reg_get_max_bandwidth(regdom,
								  reg_rule);

5183 5184 5185 5186 5187 5188 5189
		if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
				reg_rule->flags) ||
		    nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
				freq_range->start_freq_khz) ||
		    nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
				freq_range->end_freq_khz) ||
		    nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
5190
				max_bandwidth_khz) ||
5191 5192 5193
		    nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
				power_rule->max_antenna_gain) ||
		    nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
5194 5195 5196
				power_rule->max_eirp) ||
		    nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
				reg_rule->dfs_cac_ms))
5197
			goto nla_put_failure_rcu;
5198 5199 5200

		nla_nest_end(msg, nl_reg_rule);
	}
5201
	rcu_read_unlock();
5202 5203 5204 5205

	nla_nest_end(msg, nl_reg_rules);

	genlmsg_end(msg, hdr);
5206
	return genlmsg_reply(msg, info);
5207

5208 5209
nla_put_failure_rcu:
	rcu_read_unlock();
5210 5211
nla_put_failure:
	genlmsg_cancel(msg, hdr);
5212
put_failure:
Y
Yuri Ershov 已提交
5213
	nlmsg_free(msg);
5214
	return -EMSGSIZE;
5215 5216
}

5217 5218 5219 5220 5221 5222 5223
static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
{
	struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
	struct nlattr *nl_reg_rule;
	char *alpha2 = NULL;
	int rem_reg_rules = 0, r = 0;
	u32 num_rules = 0, rule_idx = 0, size_of_regd;
5224
	enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
5225 5226 5227 5228 5229 5230 5231 5232 5233 5234
	struct ieee80211_regdomain *rd = NULL;

	if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_REG_RULES])
		return -EINVAL;

	alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);

5235 5236 5237
	if (info->attrs[NL80211_ATTR_DFS_REGION])
		dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);

5238
	nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
J
Johannes Berg 已提交
5239
			    rem_reg_rules) {
5240 5241
		num_rules++;
		if (num_rules > NL80211_MAX_SUPP_REG_RULES)
5242
			return -EINVAL;
5243 5244
	}

5245 5246 5247
	if (!reg_is_valid_request(alpha2))
		return -EINVAL;

5248
	size_of_regd = sizeof(struct ieee80211_regdomain) +
J
Johannes Berg 已提交
5249
		       num_rules * sizeof(struct ieee80211_reg_rule);
5250 5251

	rd = kzalloc(size_of_regd, GFP_KERNEL);
5252 5253
	if (!rd)
		return -ENOMEM;
5254 5255 5256 5257 5258

	rd->n_reg_rules = num_rules;
	rd->alpha2[0] = alpha2[0];
	rd->alpha2[1] = alpha2[1];

5259 5260 5261 5262 5263 5264 5265
	/*
	 * Disable DFS master mode if the DFS region was
	 * not supported or known on this kernel.
	 */
	if (reg_supported_dfs_region(dfs_region))
		rd->dfs_region = dfs_region;

5266
	nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
J
Johannes Berg 已提交
5267
			    rem_reg_rules) {
5268 5269 5270 5271 5272
		r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
			      nla_data(nl_reg_rule), nla_len(nl_reg_rule),
			      reg_rule_policy);
		if (r)
			goto bad_reg;
5273 5274 5275 5276 5277 5278
		r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
		if (r)
			goto bad_reg;

		rule_idx++;

5279 5280
		if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
			r = -EINVAL;
5281
			goto bad_reg;
5282
		}
5283 5284 5285
	}

	r = set_regdom(rd);
5286
	/* set_regdom took ownership */
J
Johannes Berg 已提交
5287
	rd = NULL;
5288

5289
 bad_reg:
5290
	kfree(rd);
5291
	return r;
5292 5293
}

5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318
static int validate_scan_freqs(struct nlattr *freqs)
{
	struct nlattr *attr1, *attr2;
	int n_channels = 0, tmp1, tmp2;

	nla_for_each_nested(attr1, freqs, tmp1) {
		n_channels++;
		/*
		 * Some hardware has a limited channel list for
		 * scanning, and it is pretty much nonsensical
		 * to scan for a channel twice, so disallow that
		 * and don't require drivers to check that the
		 * channel list they get isn't longer than what
		 * they can scan, as long as they can scan all
		 * the channels they registered at once.
		 */
		nla_for_each_nested(attr2, freqs, tmp2)
			if (attr1 != attr2 &&
			    nla_get_u32(attr1) == nla_get_u32(attr2))
				return 0;
	}

	return n_channels;
}

5319 5320
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
5321
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
J
Johannes Berg 已提交
5322
	struct wireless_dev *wdev = info->user_ptr[1];
5323 5324 5325
	struct cfg80211_scan_request *request;
	struct nlattr *attr;
	struct wiphy *wiphy;
5326
	int err, tmp, n_ssids = 0, n_channels, i;
5327
	size_t ie_len;
5328

5329 5330 5331
	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

5332
	wiphy = &rdev->wiphy;
5333

5334 5335
	if (!rdev->ops->scan)
		return -EOPNOTSUPP;
5336

5337
	if (rdev->scan_req || rdev->scan_msg) {
5338 5339 5340
		err = -EBUSY;
		goto unlock;
	}
5341 5342

	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
5343 5344
		n_channels = validate_scan_freqs(
				info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
5345 5346 5347 5348
		if (!n_channels) {
			err = -EINVAL;
			goto unlock;
		}
5349
	} else {
5350
		n_channels = ieee80211_get_num_supported_channels(wiphy);
5351 5352 5353 5354 5355 5356
	}

	if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
			n_ssids++;

5357 5358 5359 5360
	if (n_ssids > wiphy->max_scan_ssids) {
		err = -EINVAL;
		goto unlock;
	}
5361

5362 5363 5364 5365 5366
	if (info->attrs[NL80211_ATTR_IE])
		ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
	else
		ie_len = 0;

5367 5368 5369 5370
	if (ie_len > wiphy->max_scan_ie_len) {
		err = -EINVAL;
		goto unlock;
	}
5371

5372
	request = kzalloc(sizeof(*request)
5373 5374
			+ sizeof(*request->ssids) * n_ssids
			+ sizeof(*request->channels) * n_channels
5375
			+ ie_len, GFP_KERNEL);
5376 5377 5378 5379
	if (!request) {
		err = -ENOMEM;
		goto unlock;
	}
5380 5381

	if (n_ssids)
5382
		request->ssids = (void *)&request->channels[n_channels];
5383
	request->n_ssids = n_ssids;
5384 5385 5386 5387 5388 5389
	if (ie_len) {
		if (request->ssids)
			request->ie = (void *)(request->ssids + n_ssids);
		else
			request->ie = (void *)(request->channels + n_channels);
	}
5390

J
Johannes Berg 已提交
5391
	i = 0;
5392 5393 5394
	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
		/* user specified, bail out if channel not found */
		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
J
Johannes Berg 已提交
5395 5396 5397 5398 5399
			struct ieee80211_channel *chan;

			chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));

			if (!chan) {
5400 5401 5402
				err = -EINVAL;
				goto out_free;
			}
J
Johannes Berg 已提交
5403 5404 5405 5406 5407 5408

			/* ignore disabled channels */
			if (chan->flags & IEEE80211_CHAN_DISABLED)
				continue;

			request->channels[i] = chan;
5409 5410 5411
			i++;
		}
	} else {
5412 5413
		enum ieee80211_band band;

5414 5415 5416 5417 5418 5419
		/* all channels */
		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
			int j;
			if (!wiphy->bands[band])
				continue;
			for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
J
Johannes Berg 已提交
5420 5421 5422 5423 5424 5425 5426 5427
				struct ieee80211_channel *chan;

				chan = &wiphy->bands[band]->channels[j];

				if (chan->flags & IEEE80211_CHAN_DISABLED)
					continue;

				request->channels[i] = chan;
5428 5429 5430 5431 5432
				i++;
			}
		}
	}

J
Johannes Berg 已提交
5433 5434 5435 5436 5437 5438 5439
	if (!i) {
		err = -EINVAL;
		goto out_free;
	}

	request->n_channels = i;

5440 5441 5442
	i = 0;
	if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
5443
			if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
5444 5445 5446
				err = -EINVAL;
				goto out_free;
			}
5447
			request->ssids[i].ssid_len = nla_len(attr);
5448 5449 5450 5451 5452
			memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
			i++;
		}
	}

5453 5454
	if (info->attrs[NL80211_ATTR_IE]) {
		request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
5455 5456
		memcpy((void *)request->ie,
		       nla_data(info->attrs[NL80211_ATTR_IE]),
5457 5458 5459
		       request->ie_len);
	}

5460
	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
5461 5462 5463
		if (wiphy->bands[i])
			request->rates[i] =
				(1 << wiphy->bands[i]->n_bitrates) - 1;
5464 5465 5466 5467 5468 5469 5470

	if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
		nla_for_each_nested(attr,
				    info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
				    tmp) {
			enum ieee80211_band band = nla_type(attr);

5471
			if (band < 0 || band >= IEEE80211_NUM_BANDS) {
5472 5473 5474
				err = -EINVAL;
				goto out_free;
			}
5475 5476 5477 5478

			if (!wiphy->bands[band])
				continue;

5479 5480 5481 5482 5483 5484 5485 5486 5487
			err = ieee80211_get_ratemask(wiphy->bands[band],
						     nla_data(attr),
						     nla_len(attr),
						     &request->rates[band]);
			if (err)
				goto out_free;
		}
	}

5488
	if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
5489 5490
		request->flags = nla_get_u32(
			info->attrs[NL80211_ATTR_SCAN_FLAGS]);
5491 5492
		if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
		    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
5493 5494 5495 5496
			err = -EOPNOTSUPP;
			goto out_free;
		}
	}
5497

5498 5499 5500
	request->no_cck =
		nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);

J
Johannes Berg 已提交
5501
	request->wdev = wdev;
5502
	request->wiphy = &rdev->wiphy;
5503
	request->scan_start = jiffies;
5504

5505
	rdev->scan_req = request;
5506
	err = rdev_scan(rdev, request);
5507

5508
	if (!err) {
J
Johannes Berg 已提交
5509 5510 5511
		nl80211_send_scan_start(rdev, wdev);
		if (wdev->netdev)
			dev_hold(wdev->netdev);
5512
	} else {
5513
 out_free:
5514
		rdev->scan_req = NULL;
5515 5516
		kfree(request);
	}
J
Johannes Berg 已提交
5517

5518
 unlock:
5519 5520 5521
	return err;
}

5522 5523 5524 5525 5526 5527 5528 5529
static int nl80211_start_sched_scan(struct sk_buff *skb,
				    struct genl_info *info)
{
	struct cfg80211_sched_scan_request *request;
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct nlattr *attr;
	struct wiphy *wiphy;
5530
	int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i;
5531
	u32 interval;
5532 5533
	enum ieee80211_band band;
	size_t ie_len;
5534
	struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
5535
	s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
5536 5537 5538 5539 5540 5541 5542 5543

	if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
	    !rdev->ops->sched_scan_start)
		return -EOPNOTSUPP;

	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

5544 5545 5546 5547 5548 5549 5550
	if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
		return -EINVAL;

	interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
	if (interval == 0)
		return -EINVAL;

5551 5552 5553 5554 5555 5556 5557 5558
	wiphy = &rdev->wiphy;

	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
		n_channels = validate_scan_freqs(
				info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
		if (!n_channels)
			return -EINVAL;
	} else {
5559
		n_channels = ieee80211_get_num_supported_channels(wiphy);
5560 5561 5562 5563 5564 5565 5566
	}

	if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
				    tmp)
			n_ssids++;

5567
	if (n_ssids > wiphy->max_sched_scan_ssids)
5568 5569
		return -EINVAL;

5570 5571 5572 5573 5574 5575 5576 5577 5578 5579
	/*
	 * First, count the number of 'real' matchsets. Due to an issue with
	 * the old implementation, matchsets containing only the RSSI attribute
	 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
	 * RSSI for all matchsets, rather than their own matchset for reporting
	 * all APs with a strong RSSI. This is needed to be compatible with
	 * older userspace that treated a matchset with only the RSSI as the
	 * global RSSI for all other matchsets - if there are other matchsets.
	 */
	if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
5580 5581
		nla_for_each_nested(attr,
				    info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603
				    tmp) {
			struct nlattr *rssi;

			err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
					nla_data(attr), nla_len(attr),
					nl80211_match_policy);
			if (err)
				return err;
			/* add other standalone attributes here */
			if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
				n_match_sets++;
				continue;
			}
			rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
			if (rssi)
				default_match_rssi = nla_get_s32(rssi);
		}
	}

	/* However, if there's no other matchset, add the RSSI one */
	if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
		n_match_sets = 1;
5604 5605 5606 5607

	if (n_match_sets > wiphy->max_match_sets)
		return -EINVAL;

5608 5609 5610 5611 5612
	if (info->attrs[NL80211_ATTR_IE])
		ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
	else
		ie_len = 0;

5613
	if (ie_len > wiphy->max_sched_scan_ie_len)
5614 5615
		return -EINVAL;

5616 5617 5618 5619 5620
	if (rdev->sched_scan_req) {
		err = -EINPROGRESS;
		goto out;
	}

5621
	request = kzalloc(sizeof(*request)
5622
			+ sizeof(*request->ssids) * n_ssids
5623
			+ sizeof(*request->match_sets) * n_match_sets
5624
			+ sizeof(*request->channels) * n_channels
5625
			+ ie_len, GFP_KERNEL);
5626 5627 5628 5629
	if (!request) {
		err = -ENOMEM;
		goto out;
	}
5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640

	if (n_ssids)
		request->ssids = (void *)&request->channels[n_channels];
	request->n_ssids = n_ssids;
	if (ie_len) {
		if (request->ssids)
			request->ie = (void *)(request->ssids + n_ssids);
		else
			request->ie = (void *)(request->channels + n_channels);
	}

5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652
	if (n_match_sets) {
		if (request->ie)
			request->match_sets = (void *)(request->ie + ie_len);
		else if (request->ssids)
			request->match_sets =
				(void *)(request->ssids + n_ssids);
		else
			request->match_sets =
				(void *)(request->channels + n_channels);
	}
	request->n_match_sets = n_match_sets;

5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705
	i = 0;
	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
		/* user specified, bail out if channel not found */
		nla_for_each_nested(attr,
				    info->attrs[NL80211_ATTR_SCAN_FREQUENCIES],
				    tmp) {
			struct ieee80211_channel *chan;

			chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));

			if (!chan) {
				err = -EINVAL;
				goto out_free;
			}

			/* ignore disabled channels */
			if (chan->flags & IEEE80211_CHAN_DISABLED)
				continue;

			request->channels[i] = chan;
			i++;
		}
	} else {
		/* all channels */
		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
			int j;
			if (!wiphy->bands[band])
				continue;
			for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
				struct ieee80211_channel *chan;

				chan = &wiphy->bands[band]->channels[j];

				if (chan->flags & IEEE80211_CHAN_DISABLED)
					continue;

				request->channels[i] = chan;
				i++;
			}
		}
	}

	if (!i) {
		err = -EINVAL;
		goto out_free;
	}

	request->n_channels = i;

	i = 0;
	if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
				    tmp) {
5706
			if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
5707 5708 5709
				err = -EINVAL;
				goto out_free;
			}
5710
			request->ssids[i].ssid_len = nla_len(attr);
5711 5712 5713 5714 5715 5716
			memcpy(request->ssids[i].ssid, nla_data(attr),
			       nla_len(attr));
			i++;
		}
	}

5717 5718 5719 5720 5721
	i = 0;
	if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
		nla_for_each_nested(attr,
				    info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
				    tmp) {
5722
			struct nlattr *ssid, *rssi;
5723

5724 5725 5726 5727 5728
			err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
					nla_data(attr), nla_len(attr),
					nl80211_match_policy);
			if (err)
				goto out_free;
5729
			ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
5730
			if (ssid) {
5731 5732 5733 5734 5735 5736 5737 5738 5739
				if (WARN_ON(i >= n_match_sets)) {
					/* this indicates a programming error,
					 * the loop above should have verified
					 * things properly
					 */
					err = -EINVAL;
					goto out_free;
				}

5740 5741 5742 5743 5744 5745 5746 5747
				if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
					err = -EINVAL;
					goto out_free;
				}
				memcpy(request->match_sets[i].ssid.ssid,
				       nla_data(ssid), nla_len(ssid));
				request->match_sets[i].ssid.ssid_len =
					nla_len(ssid);
5748 5749 5750 5751 5752 5753 5754
				/* special attribute - old implemenation w/a */
				request->match_sets[i].rssi_thold =
					default_match_rssi;
				rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
				if (rssi)
					request->match_sets[i].rssi_thold =
						nla_get_s32(rssi);
5755 5756 5757
			}
			i++;
		}
5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769

		/* there was no other matchset, so the RSSI one is alone */
		if (i == 0)
			request->match_sets[0].rssi_thold = default_match_rssi;

		request->min_rssi_thold = INT_MAX;
		for (i = 0; i < n_match_sets; i++)
			request->min_rssi_thold =
				min(request->match_sets[i].rssi_thold,
				    request->min_rssi_thold);
	} else {
		request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
5770 5771
	}

5772 5773
	if (ie_len) {
		request->ie_len = ie_len;
5774 5775 5776 5777 5778
		memcpy((void *)request->ie,
		       nla_data(info->attrs[NL80211_ATTR_IE]),
		       request->ie_len);
	}

5779
	if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
5780 5781
		request->flags = nla_get_u32(
			info->attrs[NL80211_ATTR_SCAN_FLAGS]);
5782 5783
		if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
		    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
5784 5785 5786 5787
			err = -EOPNOTSUPP;
			goto out_free;
		}
	}
5788

5789 5790
	request->dev = dev;
	request->wiphy = &rdev->wiphy;
5791
	request->interval = interval;
5792
	request->scan_start = jiffies;
5793

5794
	err = rdev_sched_scan_start(rdev, dev, request);
5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816
	if (!err) {
		rdev->sched_scan_req = request;
		nl80211_send_sched_scan(rdev, dev,
					NL80211_CMD_START_SCHED_SCAN);
		goto out;
	}

out_free:
	kfree(request);
out:
	return err;
}

static int nl80211_stop_sched_scan(struct sk_buff *skb,
				   struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];

	if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
	    !rdev->ops->sched_scan_stop)
		return -EOPNOTSUPP;

5817
	return __cfg80211_stop_sched_scan(rdev, false);
5818 5819
}

5820 5821 5822 5823 5824 5825 5826
static int nl80211_start_radar_detection(struct sk_buff *skb,
					 struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_chan_def chandef;
5827
	enum nl80211_dfs_regions dfs_region;
5828
	unsigned int cac_time_ms;
5829 5830
	int err;

5831 5832 5833 5834
	dfs_region = reg_get_dfs_region(wdev->wiphy);
	if (dfs_region == NL80211_DFS_UNSET)
		return -EINVAL;

5835 5836 5837 5838
	err = nl80211_parse_chandef(rdev, info, &chandef);
	if (err)
		return err;

5839 5840 5841
	if (netif_carrier_ok(dev))
		return -EBUSY;

5842 5843 5844
	if (wdev->cac_started)
		return -EBUSY;

5845
	err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
5846
					    wdev->iftype);
5847 5848 5849 5850 5851 5852
	if (err < 0)
		return err;

	if (err == 0)
		return -EINVAL;

5853
	if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
5854 5855 5856 5857 5858
		return -EINVAL;

	if (!rdev->ops->start_radar_detection)
		return -EOPNOTSUPP;

5859 5860 5861 5862 5863 5864
	cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
	if (WARN_ON(!cac_time_ms))
		cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;

	err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef,
					       cac_time_ms);
5865
	if (!err) {
5866
		wdev->chandef = chandef;
5867 5868
		wdev->cac_started = true;
		wdev->cac_start_time = jiffies;
5869
		wdev->cac_time_ms = cac_time_ms;
5870 5871 5872 5873
	}
	return err;
}

5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885
static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_csa_settings params;
	/* csa_attrs is defined static to avoid waste of stack size - this
	 * function is called under RTNL lock, so this should not be a problem.
	 */
	static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
	u8 radar_detect_width = 0;
	int err;
5886
	bool need_new_beacon = false;
5887
	int len, i;
5888 5889 5890 5891 5892

	if (!rdev->ops->channel_switch ||
	    !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
		return -EOPNOTSUPP;

5893 5894 5895 5896 5897 5898 5899
	switch (dev->ieee80211_ptr->iftype) {
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
		need_new_beacon = true;

		/* useless if AP is not running */
		if (!wdev->beacon_interval)
5900
			return -ENOTCONN;
5901 5902
		break;
	case NL80211_IFTYPE_ADHOC:
5903 5904 5905
		if (!wdev->ssid_len)
			return -ENOTCONN;
		break;
5906
	case NL80211_IFTYPE_MESH_POINT:
5907 5908
		if (!wdev->mesh_id_len)
			return -ENOTCONN;
5909 5910
		break;
	default:
5911
		return -EOPNOTSUPP;
5912
	}
5913 5914 5915 5916 5917 5918 5919 5920

	memset(&params, 0, sizeof(params));

	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
	    !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
		return -EINVAL;

	/* only important for AP, IBSS and mesh create IEs internally */
5921
	if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
5922 5923 5924 5925
		return -EINVAL;

	params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);

5926 5927 5928
	if (!need_new_beacon)
		goto skip_beacons;

5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945
	err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
	if (err)
		return err;

	err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
			       info->attrs[NL80211_ATTR_CSA_IES],
			       nl80211_policy);
	if (err)
		return err;

	err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
	if (err)
		return err;

	if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
		return -EINVAL;

5946 5947
	len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
	if (!len || (len % sizeof(u16)))
5948 5949
		return -EINVAL;

5950 5951 5952 5953
	params.n_counter_offsets_beacon = len / sizeof(u16);
	if (rdev->wiphy.max_num_csa_counters &&
	    (params.n_counter_offsets_beacon >
	     rdev->wiphy.max_num_csa_counters))
5954 5955
		return -EINVAL;

5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969
	params.counter_offsets_beacon =
		nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);

	/* sanity checks - counters should fit and be the same */
	for (i = 0; i < params.n_counter_offsets_beacon; i++) {
		u16 offset = params.counter_offsets_beacon[i];

		if (offset >= params.beacon_csa.tail_len)
			return -EINVAL;

		if (params.beacon_csa.tail[offset] != params.count)
			return -EINVAL;
	}

5970
	if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
5971 5972
		len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
		if (!len || (len % sizeof(u16)))
5973 5974
			return -EINVAL;

5975 5976 5977 5978
		params.n_counter_offsets_presp = len / sizeof(u16);
		if (rdev->wiphy.max_num_csa_counters &&
		    (params.n_counter_offsets_beacon >
		     rdev->wiphy.max_num_csa_counters))
5979
			return -EINVAL;
5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994

		params.counter_offsets_presp =
			nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);

		/* sanity checks - counters should fit and be the same */
		for (i = 0; i < params.n_counter_offsets_presp; i++) {
			u16 offset = params.counter_offsets_presp[i];

			if (offset >= params.beacon_csa.probe_resp_len)
				return -EINVAL;

			if (params.beacon_csa.probe_resp[offset] !=
			    params.count)
				return -EINVAL;
		}
5995 5996
	}

5997
skip_beacons:
5998 5999 6000 6001
	err = nl80211_parse_chandef(rdev, info, &params.chandef);
	if (err)
		return err;

6002 6003
	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
				     wdev->iftype))
6004 6005
		return -EINVAL;

6006 6007 6008 6009 6010 6011 6012 6013 6014
	err = cfg80211_chandef_dfs_required(wdev->wiphy,
					    &params.chandef,
					    wdev->iftype);
	if (err < 0)
		return err;

	if (err > 0) {
		radar_detect_width = BIT(params.chandef.width);
		params.radar_required = true;
6015 6016 6017 6018 6019
	}

	if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
		params.block_tx = true;

6020 6021 6022 6023 6024
	wdev_lock(wdev);
	err = rdev_channel_switch(rdev, dev, &params);
	wdev_unlock(wdev);

	return err;
6025 6026
}

6027 6028
static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
			    u32 seq, int flags,
6029
			    struct cfg80211_registered_device *rdev,
J
Johannes Berg 已提交
6030 6031
			    struct wireless_dev *wdev,
			    struct cfg80211_internal_bss *intbss)
6032
{
J
Johannes Berg 已提交
6033
	struct cfg80211_bss *res = &intbss->pub;
6034
	const struct cfg80211_bss_ies *ies;
6035 6036
	void *hdr;
	struct nlattr *bss;
J
Johannes Berg 已提交
6037
	bool tsf = false;
J
Johannes Berg 已提交
6038 6039

	ASSERT_WDEV_LOCK(wdev);
6040

6041
	hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
6042 6043 6044 6045
			     NL80211_CMD_NEW_SCAN_RESULTS);
	if (!hdr)
		return -1;

6046 6047
	genl_dump_check_consistent(cb, hdr, &nl80211_fam);

6048 6049 6050
	if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
		goto nla_put_failure;
	if (wdev->netdev &&
6051 6052
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
		goto nla_put_failure;
6053 6054
	if (nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
		goto nla_put_failure;
6055 6056 6057 6058

	bss = nla_nest_start(msg, NL80211_ATTR_BSS);
	if (!bss)
		goto nla_put_failure;
6059
	if ((!is_zero_ether_addr(res->bssid) &&
6060
	     nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
6061
		goto nla_put_failure;
6062 6063 6064

	rcu_read_lock();
	ies = rcu_dereference(res->ies);
J
Johannes Berg 已提交
6065 6066 6067 6068 6069 6070 6071
	if (ies) {
		if (nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
			goto fail_unlock_rcu;
		tsf = true;
		if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
					ies->len, ies->data))
			goto fail_unlock_rcu;
6072 6073
	}
	ies = rcu_dereference(res->beacon_ies);
J
Johannes Berg 已提交
6074 6075 6076 6077 6078 6079
	if (ies) {
		if (!tsf && nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
			goto fail_unlock_rcu;
		if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
					ies->len, ies->data))
			goto fail_unlock_rcu;
6080 6081 6082
	}
	rcu_read_unlock();

6083 6084 6085 6086 6087
	if (res->beacon_interval &&
	    nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
		goto nla_put_failure;
	if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
	    nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
6088
	    nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
6089 6090 6091
	    nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
			jiffies_to_msecs(jiffies - intbss->ts)))
		goto nla_put_failure;
6092

J
Johannes Berg 已提交
6093
	switch (rdev->wiphy.signal_type) {
6094
	case CFG80211_SIGNAL_TYPE_MBM:
6095 6096
		if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
			goto nla_put_failure;
6097 6098
		break;
	case CFG80211_SIGNAL_TYPE_UNSPEC:
6099 6100
		if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
			goto nla_put_failure;
6101 6102 6103 6104 6105
		break;
	default:
		break;
	}

J
Johannes Berg 已提交
6106
	switch (wdev->iftype) {
6107
	case NL80211_IFTYPE_P2P_CLIENT:
J
Johannes Berg 已提交
6108
	case NL80211_IFTYPE_STATION:
6109 6110 6111 6112
		if (intbss == wdev->current_bss &&
		    nla_put_u32(msg, NL80211_BSS_STATUS,
				NL80211_BSS_STATUS_ASSOCIATED))
			goto nla_put_failure;
J
Johannes Berg 已提交
6113 6114
		break;
	case NL80211_IFTYPE_ADHOC:
6115 6116 6117 6118
		if (intbss == wdev->current_bss &&
		    nla_put_u32(msg, NL80211_BSS_STATUS,
				NL80211_BSS_STATUS_IBSS_JOINED))
			goto nla_put_failure;
J
Johannes Berg 已提交
6119 6120 6121 6122 6123
		break;
	default:
		break;
	}

6124 6125 6126 6127
	nla_nest_end(msg, bss);

	return genlmsg_end(msg, hdr);

J
Johannes Berg 已提交
6128 6129
 fail_unlock_rcu:
	rcu_read_unlock();
6130 6131 6132 6133 6134
 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
}

6135
static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
6136
{
J
Johannes Berg 已提交
6137
	struct cfg80211_registered_device *rdev;
6138
	struct cfg80211_internal_bss *scan;
J
Johannes Berg 已提交
6139
	struct wireless_dev *wdev;
6140
	int start = cb->args[2], idx = 0;
6141 6142
	int err;

6143
	err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
6144 6145
	if (err)
		return err;
6146

J
Johannes Berg 已提交
6147 6148 6149 6150
	wdev_lock(wdev);
	spin_lock_bh(&rdev->bss_lock);
	cfg80211_bss_expire(rdev);

6151 6152
	cb->seq = rdev->bss_generation;

J
Johannes Berg 已提交
6153
	list_for_each_entry(scan, &rdev->bss_list, list) {
6154 6155
		if (++idx <= start)
			continue;
6156
		if (nl80211_send_bss(skb, cb,
6157
				cb->nlh->nlmsg_seq, NLM_F_MULTI,
J
Johannes Berg 已提交
6158
				rdev, wdev, scan) < 0) {
6159
			idx--;
6160
			break;
6161 6162 6163
		}
	}

J
Johannes Berg 已提交
6164 6165
	spin_unlock_bh(&rdev->bss_lock);
	wdev_unlock(wdev);
6166

6167 6168
	cb->args[2] = idx;
	nl80211_finish_wdev_dump(rdev);
6169

6170
	return skb->len;
6171 6172
}

6173
static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
6174 6175 6176 6177 6178 6179
				int flags, struct net_device *dev,
				struct survey_info *survey)
{
	void *hdr;
	struct nlattr *infoattr;

6180
	hdr = nl80211hdr_put(msg, portid, seq, flags,
6181 6182 6183 6184
			     NL80211_CMD_NEW_SURVEY_RESULTS);
	if (!hdr)
		return -ENOMEM;

6185 6186
	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
		goto nla_put_failure;
6187 6188 6189 6190 6191

	infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
	if (!infoattr)
		goto nla_put_failure;

6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221
	if (nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
			survey->channel->center_freq))
		goto nla_put_failure;

	if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
	    nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
		goto nla_put_failure;
	if ((survey->filled & SURVEY_INFO_IN_USE) &&
	    nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
		goto nla_put_failure;
	if ((survey->filled & SURVEY_INFO_CHANNEL_TIME) &&
	    nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME,
			survey->channel_time))
		goto nla_put_failure;
	if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) &&
	    nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
			survey->channel_time_busy))
		goto nla_put_failure;
	if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) &&
	    nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
			survey->channel_time_ext_busy))
		goto nla_put_failure;
	if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) &&
	    nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
			survey->channel_time_rx))
		goto nla_put_failure;
	if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) &&
	    nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
			survey->channel_time_tx))
		goto nla_put_failure;
6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235

	nla_nest_end(msg, infoattr);

	return genlmsg_end(msg, hdr);

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
}

static int nl80211_dump_survey(struct sk_buff *skb,
			struct netlink_callback *cb)
{
	struct survey_info survey;
6236
	struct cfg80211_registered_device *rdev;
6237 6238
	struct wireless_dev *wdev;
	int survey_idx = cb->args[2];
6239 6240
	int res;

6241
	res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
6242 6243
	if (res)
		return res;
6244

6245 6246 6247 6248 6249
	if (!wdev->netdev) {
		res = -EINVAL;
		goto out_err;
	}

6250
	if (!rdev->ops->dump_survey) {
6251 6252 6253 6254 6255
		res = -EOPNOTSUPP;
		goto out_err;
	}

	while (1) {
6256 6257
		struct ieee80211_channel *chan;

6258
		res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
6259 6260 6261 6262 6263
		if (res == -ENOENT)
			break;
		if (res)
			goto out_err;

6264 6265 6266 6267 6268 6269
		/* Survey without a channel doesn't make sense */
		if (!survey.channel) {
			res = -EINVAL;
			goto out;
		}

6270
		chan = ieee80211_get_channel(&rdev->wiphy,
6271 6272 6273 6274 6275 6276
					     survey.channel->center_freq);
		if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
			survey_idx++;
			continue;
		}

6277
		if (nl80211_send_survey(skb,
6278
				NETLINK_CB(cb->skb).portid,
6279
				cb->nlh->nlmsg_seq, NLM_F_MULTI,
6280
				wdev->netdev, &survey) < 0)
6281 6282 6283 6284 6285
			goto out;
		survey_idx++;
	}

 out:
6286
	cb->args[2] = survey_idx;
6287 6288
	res = skb->len;
 out_err:
6289
	nl80211_finish_wdev_dump(rdev);
6290 6291 6292
	return res;
}

S
Samuel Ortiz 已提交
6293 6294 6295 6296 6297 6298
static bool nl80211_valid_wpa_versions(u32 wpa_versions)
{
	return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
				  NL80211_WPA_VERSION_2));
}

6299 6300
static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
{
6301 6302
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
J
Johannes Berg 已提交
6303
	struct ieee80211_channel *chan;
6304 6305
	const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL;
	int err, ssid_len, ie_len = 0, sae_data_len = 0;
J
Johannes Berg 已提交
6306
	enum nl80211_auth_type auth_type;
J
Johannes Berg 已提交
6307
	struct key_parse key;
6308
	bool local_state_change;
6309

6310 6311 6312 6313 6314 6315
	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

6316 6317 6318
	if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
		return -EINVAL;

J
Johannes Berg 已提交
6319 6320 6321 6322 6323 6324
	if (!info->attrs[NL80211_ATTR_SSID])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
		return -EINVAL;

J
Johannes Berg 已提交
6325 6326 6327 6328 6329
	err = nl80211_parse_key(info, &key);
	if (err)
		return err;

	if (key.idx >= 0) {
6330 6331
		if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
			return -EINVAL;
J
Johannes Berg 已提交
6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345
		if (!key.p.key || !key.p.key_len)
			return -EINVAL;
		if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
		     key.p.key_len != WLAN_KEY_LEN_WEP40) &&
		    (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
		     key.p.key_len != WLAN_KEY_LEN_WEP104))
			return -EINVAL;
		if (key.idx > 4)
			return -EINVAL;
	} else {
		key.p.key_len = 0;
		key.p.key = NULL;
	}

6346 6347 6348 6349 6350 6351 6352 6353 6354
	if (key.idx >= 0) {
		int i;
		bool ok = false;
		for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
			if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
				ok = true;
				break;
			}
		}
6355 6356
		if (!ok)
			return -EINVAL;
6357 6358
	}

6359 6360
	if (!rdev->ops->auth)
		return -EOPNOTSUPP;
6361

6362
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
6363 6364
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
6365

J
Johannes Berg 已提交
6366
	bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
6367 6368 6369
	chan = nl80211_get_valid_chan(&rdev->wiphy,
				      info->attrs[NL80211_ATTR_WIPHY_FREQ]);
	if (!chan)
6370
		return -EINVAL;
6371

J
Johannes Berg 已提交
6372 6373
	ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
	ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
6374 6375

	if (info->attrs[NL80211_ATTR_IE]) {
J
Johannes Berg 已提交
6376 6377
		ie = nla_data(info->attrs[NL80211_ATTR_IE]);
		ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6378 6379
	}

J
Johannes Berg 已提交
6380
	auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
6381
	if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
6382
		return -EINVAL;
6383

6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397
	if (auth_type == NL80211_AUTHTYPE_SAE &&
	    !info->attrs[NL80211_ATTR_SAE_DATA])
		return -EINVAL;

	if (info->attrs[NL80211_ATTR_SAE_DATA]) {
		if (auth_type != NL80211_AUTHTYPE_SAE)
			return -EINVAL;
		sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]);
		sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]);
		/* need to include at least Auth Transaction and Status Code */
		if (sae_data_len < 4)
			return -EINVAL;
	}

6398 6399
	local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];

6400 6401 6402 6403 6404 6405 6406
	/*
	 * Since we no longer track auth state, ignore
	 * requests to only change local state.
	 */
	if (local_state_change)
		return 0;

6407 6408 6409 6410 6411 6412 6413
	wdev_lock(dev->ieee80211_ptr);
	err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
				 ssid, ssid_len, ie, ie_len,
				 key.p.key, key.p.key_len, key.idx,
				 sae_data, sae_data_len);
	wdev_unlock(dev->ieee80211_ptr);
	return err;
6414 6415
}

6416 6417
static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
				   struct genl_info *info,
6418 6419
				   struct cfg80211_crypto_settings *settings,
				   int cipher_limit)
S
Samuel Ortiz 已提交
6420
{
6421 6422
	memset(settings, 0, sizeof(*settings));

S
Samuel Ortiz 已提交
6423 6424
	settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];

6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437
	if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
		u16 proto;
		proto = nla_get_u16(
			info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
		settings->control_port_ethertype = cpu_to_be16(proto);
		if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
		    proto != ETH_P_PAE)
			return -EINVAL;
		if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
			settings->control_port_no_encrypt = true;
	} else
		settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);

S
Samuel Ortiz 已提交
6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448
	if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
		void *data;
		int len, i;

		data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
		len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
		settings->n_ciphers_pairwise = len / sizeof(u32);

		if (len % sizeof(u32))
			return -EINVAL;

6449
		if (settings->n_ciphers_pairwise > cipher_limit)
S
Samuel Ortiz 已提交
6450 6451 6452 6453 6454
			return -EINVAL;

		memcpy(settings->ciphers_pairwise, data, len);

		for (i = 0; i < settings->n_ciphers_pairwise; i++)
6455 6456
			if (!cfg80211_supported_cipher_suite(
					&rdev->wiphy,
S
Samuel Ortiz 已提交
6457 6458 6459 6460 6461 6462 6463
					settings->ciphers_pairwise[i]))
				return -EINVAL;
	}

	if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
		settings->cipher_group =
			nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
6464 6465
		if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
						     settings->cipher_group))
S
Samuel Ortiz 已提交
6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477
			return -EINVAL;
	}

	if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
		settings->wpa_versions =
			nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
		if (!nl80211_valid_wpa_versions(settings->wpa_versions))
			return -EINVAL;
	}

	if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
		void *data;
6478
		int len;
S
Samuel Ortiz 已提交
6479 6480 6481 6482 6483 6484 6485 6486

		data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
		len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
		settings->n_akm_suites = len / sizeof(u32);

		if (len % sizeof(u32))
			return -EINVAL;

6487 6488 6489
		if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
			return -EINVAL;

S
Samuel Ortiz 已提交
6490 6491 6492 6493 6494 6495
		memcpy(settings->akm_suites, data, len);
	}

	return 0;
}

6496 6497
static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
{
6498 6499
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
6500
	struct ieee80211_channel *chan;
6501 6502 6503
	struct cfg80211_assoc_request req = {};
	const u8 *bssid, *ssid;
	int err, ssid_len = 0;
6504

6505 6506 6507 6508
	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_MAC] ||
J
Johannes Berg 已提交
6509 6510
	    !info->attrs[NL80211_ATTR_SSID] ||
	    !info->attrs[NL80211_ATTR_WIPHY_FREQ])
6511 6512
		return -EINVAL;

6513 6514
	if (!rdev->ops->assoc)
		return -EOPNOTSUPP;
6515

6516
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
6517 6518
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
6519

J
Johannes Berg 已提交
6520
	bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
6521

6522 6523 6524
	chan = nl80211_get_valid_chan(&rdev->wiphy,
				      info->attrs[NL80211_ATTR_WIPHY_FREQ]);
	if (!chan)
6525
		return -EINVAL;
6526

J
Johannes Berg 已提交
6527 6528
	ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
	ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
6529 6530

	if (info->attrs[NL80211_ATTR_IE]) {
6531 6532
		req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
		req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6533 6534
	}

6535
	if (info->attrs[NL80211_ATTR_USE_MFP]) {
6536
		enum nl80211_mfp mfp =
6537
			nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
6538
		if (mfp == NL80211_MFP_REQUIRED)
6539
			req.use_mfp = true;
6540 6541
		else if (mfp != NL80211_MFP_NO)
			return -EINVAL;
6542 6543
	}

6544
	if (info->attrs[NL80211_ATTR_PREV_BSSID])
6545
		req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
6546

6547
	if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
6548
		req.flags |= ASSOC_REQ_DISABLE_HT;
6549 6550

	if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
6551 6552 6553
		memcpy(&req.ht_capa_mask,
		       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
		       sizeof(req.ht_capa_mask));
6554 6555

	if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
6556
		if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
6557
			return -EINVAL;
6558 6559 6560
		memcpy(&req.ht_capa,
		       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
		       sizeof(req.ht_capa));
6561 6562
	}

6563
	if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
6564
		req.flags |= ASSOC_REQ_DISABLE_VHT;
6565 6566

	if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
6567 6568 6569
		memcpy(&req.vht_capa_mask,
		       nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
		       sizeof(req.vht_capa_mask));
6570 6571

	if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
6572
		if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
6573
			return -EINVAL;
6574 6575 6576
		memcpy(&req.vht_capa,
		       nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
		       sizeof(req.vht_capa));
6577 6578
	}

6579
	err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
6580 6581
	if (!err) {
		wdev_lock(dev->ieee80211_ptr);
6582 6583
		err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
					  ssid, ssid_len, &req);
6584 6585
		wdev_unlock(dev->ieee80211_ptr);
	}
6586 6587 6588 6589 6590 6591

	return err;
}

static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
{
6592 6593
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
J
Johannes Berg 已提交
6594
	const u8 *ie = NULL, *bssid;
6595
	int ie_len = 0, err;
J
Johannes Berg 已提交
6596
	u16 reason_code;
6597
	bool local_state_change;
6598

6599 6600 6601 6602 6603 6604 6605 6606 6607
	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_REASON_CODE])
		return -EINVAL;

6608 6609
	if (!rdev->ops->deauth)
		return -EOPNOTSUPP;
6610

6611
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
6612 6613
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
6614

J
Johannes Berg 已提交
6615
	bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
6616

J
Johannes Berg 已提交
6617 6618
	reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
	if (reason_code == 0) {
6619
		/* Reason Code 0 is reserved */
6620
		return -EINVAL;
6621
	}
6622 6623

	if (info->attrs[NL80211_ATTR_IE]) {
J
Johannes Berg 已提交
6624 6625
		ie = nla_data(info->attrs[NL80211_ATTR_IE]);
		ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6626 6627
	}

6628 6629
	local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];

6630 6631 6632 6633 6634
	wdev_lock(dev->ieee80211_ptr);
	err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
				   local_state_change);
	wdev_unlock(dev->ieee80211_ptr);
	return err;
6635 6636 6637 6638
}

static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
{
6639 6640
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
J
Johannes Berg 已提交
6641
	const u8 *ie = NULL, *bssid;
6642
	int ie_len = 0, err;
J
Johannes Berg 已提交
6643
	u16 reason_code;
6644
	bool local_state_change;
6645

6646 6647 6648 6649 6650 6651 6652 6653 6654
	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_REASON_CODE])
		return -EINVAL;

6655 6656
	if (!rdev->ops->disassoc)
		return -EOPNOTSUPP;
6657

6658
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
6659 6660
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
6661

J
Johannes Berg 已提交
6662
	bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
6663

J
Johannes Berg 已提交
6664 6665
	reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
	if (reason_code == 0) {
6666
		/* Reason Code 0 is reserved */
6667
		return -EINVAL;
6668
	}
6669 6670

	if (info->attrs[NL80211_ATTR_IE]) {
J
Johannes Berg 已提交
6671 6672
		ie = nla_data(info->attrs[NL80211_ATTR_IE]);
		ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6673 6674
	}

6675 6676
	local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];

6677 6678 6679 6680 6681
	wdev_lock(dev->ieee80211_ptr);
	err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
				     local_state_change);
	wdev_unlock(dev->ieee80211_ptr);
	return err;
6682 6683
}

6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711
static bool
nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
			 int mcast_rate[IEEE80211_NUM_BANDS],
			 int rateval)
{
	struct wiphy *wiphy = &rdev->wiphy;
	bool found = false;
	int band, i;

	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
		struct ieee80211_supported_band *sband;

		sband = wiphy->bands[band];
		if (!sband)
			continue;

		for (i = 0; i < sband->n_bitrates; i++) {
			if (sband->bitrates[i].bitrate == rateval) {
				mcast_rate[band] = i + 1;
				found = true;
				break;
			}
		}
	}

	return found;
}

J
Johannes Berg 已提交
6712 6713
static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
{
6714 6715
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
J
Johannes Berg 已提交
6716 6717
	struct cfg80211_ibss_params ibss;
	struct wiphy *wiphy;
J
Johannes Berg 已提交
6718
	struct cfg80211_cached_keys *connkeys = NULL;
J
Johannes Berg 已提交
6719 6720
	int err;

6721 6722
	memset(&ibss, 0, sizeof(ibss));

J
Johannes Berg 已提交
6723 6724 6725
	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

6726
	if (!info->attrs[NL80211_ATTR_SSID] ||
J
Johannes Berg 已提交
6727 6728 6729
	    !nla_len(info->attrs[NL80211_ATTR_SSID]))
		return -EINVAL;

6730 6731 6732 6733 6734 6735 6736 6737 6738
	ibss.beacon_interval = 100;

	if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
		ibss.beacon_interval =
			nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
		if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)
			return -EINVAL;
	}

6739 6740
	if (!rdev->ops->join_ibss)
		return -EOPNOTSUPP;
J
Johannes Berg 已提交
6741

6742 6743
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
		return -EOPNOTSUPP;
J
Johannes Berg 已提交
6744

6745
	wiphy = &rdev->wiphy;
J
Johannes Berg 已提交
6746

J
Johannes Berg 已提交
6747
	if (info->attrs[NL80211_ATTR_MAC]) {
J
Johannes Berg 已提交
6748
		ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
J
Johannes Berg 已提交
6749 6750 6751 6752

		if (!is_valid_ether_addr(ibss.bssid))
			return -EINVAL;
	}
J
Johannes Berg 已提交
6753 6754 6755 6756 6757 6758 6759 6760
	ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
	ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);

	if (info->attrs[NL80211_ATTR_IE]) {
		ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
		ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
	}

6761 6762 6763
	err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
	if (err)
		return err;
J
Johannes Berg 已提交
6764

6765 6766
	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
				     NL80211_IFTYPE_ADHOC))
6767 6768
		return -EINVAL;

6769
	switch (ibss.chandef.width) {
6770 6771
	case NL80211_CHAN_WIDTH_5:
	case NL80211_CHAN_WIDTH_10:
6772 6773 6774 6775 6776 6777 6778
	case NL80211_CHAN_WIDTH_20_NOHT:
		break;
	case NL80211_CHAN_WIDTH_20:
	case NL80211_CHAN_WIDTH_40:
		if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)
			break;
	default:
6779
		return -EINVAL;
6780
	}
6781

J
Johannes Berg 已提交
6782
	ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
J
Johannes Berg 已提交
6783 6784
	ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];

6785 6786 6787 6788 6789 6790
	if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
		u8 *rates =
			nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
		int n_rates =
			nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
		struct ieee80211_supported_band *sband =
6791
			wiphy->bands[ibss.chandef.chan->band];
6792

6793 6794 6795 6796
		err = ieee80211_get_ratemask(sband, rates, n_rates,
					     &ibss.basic_rates);
		if (err)
			return err;
6797
	}
6798

6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811
	if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
		memcpy(&ibss.ht_capa_mask,
		       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
		       sizeof(ibss.ht_capa_mask));

	if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
		if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
			return -EINVAL;
		memcpy(&ibss.ht_capa,
		       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
		       sizeof(ibss.ht_capa));
	}

6812 6813 6814 6815
	if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
	    !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
			nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
		return -EINVAL;
6816

6817
	if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
6818 6819
		bool no_ht = false;

6820
		connkeys = nl80211_parse_connkeys(rdev,
6821 6822
					  info->attrs[NL80211_ATTR_KEYS],
					  &no_ht);
6823 6824
		if (IS_ERR(connkeys))
			return PTR_ERR(connkeys);
6825

6826 6827
		if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
		    no_ht) {
6828 6829 6830
			kfree(connkeys);
			return -EINVAL;
		}
6831
	}
J
Johannes Berg 已提交
6832

6833 6834 6835
	ibss.control_port =
		nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);

6836 6837 6838
	ibss.userspace_handles_dfs =
		nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);

6839
	err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
J
Johannes Berg 已提交
6840 6841
	if (err)
		kfree(connkeys);
J
Johannes Berg 已提交
6842 6843 6844 6845 6846
	return err;
}

static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
{
6847 6848
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
J
Johannes Berg 已提交
6849

6850 6851
	if (!rdev->ops->leave_ibss)
		return -EOPNOTSUPP;
J
Johannes Berg 已提交
6852

6853 6854
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
		return -EOPNOTSUPP;
J
Johannes Berg 已提交
6855

6856
	return cfg80211_leave_ibss(rdev, dev, false);
J
Johannes Berg 已提交
6857 6858
}

6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887
static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	int mcast_rate[IEEE80211_NUM_BANDS];
	u32 nla_rate;
	int err;

	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
		return -EOPNOTSUPP;

	if (!rdev->ops->set_mcast_rate)
		return -EOPNOTSUPP;

	memset(mcast_rate, 0, sizeof(mcast_rate));

	if (!info->attrs[NL80211_ATTR_MCAST_RATE])
		return -EINVAL;

	nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
	if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
		return -EINVAL;

	err = rdev->ops->set_mcast_rate(&rdev->wiphy, dev, mcast_rate);

	return err;
}

J
Johannes Berg 已提交
6888 6889 6890 6891
static struct sk_buff *
__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
			    int approxlen, u32 portid, u32 seq,
			    enum nl80211_commands cmd,
6892 6893 6894
			    enum nl80211_attrs attr,
			    const struct nl80211_vendor_cmd_info *info,
			    gfp_t gfp)
J
Johannes Berg 已提交
6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911
{
	struct sk_buff *skb;
	void *hdr;
	struct nlattr *data;

	skb = nlmsg_new(approxlen + 100, gfp);
	if (!skb)
		return NULL;

	hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
	if (!hdr) {
		kfree_skb(skb);
		return NULL;
	}

	if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
		goto nla_put_failure;
6912 6913 6914 6915 6916 6917 6918 6919 6920 6921

	if (info) {
		if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
				info->vendor_id))
			goto nla_put_failure;
		if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
				info->subcmd))
			goto nla_put_failure;
	}

J
Johannes Berg 已提交
6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933
	data = nla_nest_start(skb, attr);

	((void **)skb->cb)[0] = rdev;
	((void **)skb->cb)[1] = hdr;
	((void **)skb->cb)[2] = data;

	return skb;

 nla_put_failure:
	kfree_skb(skb);
	return NULL;
}
6934

6935 6936 6937 6938 6939 6940
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
					   enum nl80211_commands cmd,
					   enum nl80211_attrs attr,
					   int vendor_event_idx,
					   int approxlen, gfp_t gfp)
{
6941
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983
	const struct nl80211_vendor_cmd_info *info;

	switch (cmd) {
	case NL80211_CMD_TESTMODE:
		if (WARN_ON(vendor_event_idx != -1))
			return NULL;
		info = NULL;
		break;
	case NL80211_CMD_VENDOR:
		if (WARN_ON(vendor_event_idx < 0 ||
			    vendor_event_idx >= wiphy->n_vendor_events))
			return NULL;
		info = &wiphy->vendor_events[vendor_event_idx];
		break;
	default:
		WARN_ON(1);
		return NULL;
	}

	return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
					   cmd, attr, info, gfp);
}
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);

void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
{
	struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
	void *hdr = ((void **)skb->cb)[1];
	struct nlattr *data = ((void **)skb->cb)[2];
	enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;

	nla_nest_end(skb, data);
	genlmsg_end(skb, hdr);

	if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
		mcgrp = NL80211_MCGRP_VENDOR;

	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
				mcgrp, gfp);
}
EXPORT_SYMBOL(__cfg80211_send_event_skb);

6984 6985 6986
#ifdef CONFIG_NL80211_TESTMODE
static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
{
6987
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
6988 6989
	struct wireless_dev *wdev =
		__cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
6990 6991
	int err;

6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003
	if (!rdev->ops->testmode_cmd)
		return -EOPNOTSUPP;

	if (IS_ERR(wdev)) {
		err = PTR_ERR(wdev);
		if (err != -EINVAL)
			return err;
		wdev = NULL;
	} else if (wdev->wiphy != &rdev->wiphy) {
		return -EINVAL;
	}

7004 7005 7006
	if (!info->attrs[NL80211_ATTR_TESTDATA])
		return -EINVAL;

J
Johannes Berg 已提交
7007
	rdev->cur_cmd_info = info;
7008
	err = rdev_testmode_cmd(rdev, wdev,
7009 7010
				nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
				nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
J
Johannes Berg 已提交
7011
	rdev->cur_cmd_info = NULL;
7012 7013 7014 7015

	return err;
}

W
Wey-Yi Guy 已提交
7016 7017 7018
static int nl80211_testmode_dump(struct sk_buff *skb,
				 struct netlink_callback *cb)
{
7019
	struct cfg80211_registered_device *rdev;
W
Wey-Yi Guy 已提交
7020 7021 7022 7023 7024
	int err;
	long phy_idx;
	void *data = NULL;
	int data_len = 0;

7025 7026
	rtnl_lock();

W
Wey-Yi Guy 已提交
7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037
	if (cb->args[0]) {
		/*
		 * 0 is a valid index, but not valid for args[0],
		 * so we need to offset by 1.
		 */
		phy_idx = cb->args[0] - 1;
	} else {
		err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
				  nl80211_fam.attrbuf, nl80211_fam.maxattr,
				  nl80211_policy);
		if (err)
7038
			goto out_err;
7039

7040 7041 7042
		rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
						  nl80211_fam.attrbuf);
		if (IS_ERR(rdev)) {
7043 7044
			err = PTR_ERR(rdev);
			goto out_err;
7045
		}
7046 7047 7048
		phy_idx = rdev->wiphy_idx;
		rdev = NULL;

W
Wey-Yi Guy 已提交
7049 7050 7051 7052 7053 7054 7055 7056 7057 7058
		if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
			cb->args[1] =
				(long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
	}

	if (cb->args[1]) {
		data = nla_data((void *)cb->args[1]);
		data_len = nla_len((void *)cb->args[1]);
	}

7059 7060
	rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
	if (!rdev) {
7061 7062
		err = -ENOENT;
		goto out_err;
W
Wey-Yi Guy 已提交
7063 7064
	}

7065
	if (!rdev->ops->testmode_dump) {
W
Wey-Yi Guy 已提交
7066 7067 7068 7069 7070
		err = -EOPNOTSUPP;
		goto out_err;
	}

	while (1) {
7071
		void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
W
Wey-Yi Guy 已提交
7072 7073 7074 7075
					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
					   NL80211_CMD_TESTMODE);
		struct nlattr *tmdata;

7076 7077 7078
		if (!hdr)
			break;

7079
		if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
W
Wey-Yi Guy 已提交
7080 7081 7082 7083 7084 7085 7086 7087 7088
			genlmsg_cancel(skb, hdr);
			break;
		}

		tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
		if (!tmdata) {
			genlmsg_cancel(skb, hdr);
			break;
		}
7089
		err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
W
Wey-Yi Guy 已提交
7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106
		nla_nest_end(skb, tmdata);

		if (err == -ENOBUFS || err == -ENOENT) {
			genlmsg_cancel(skb, hdr);
			break;
		} else if (err) {
			genlmsg_cancel(skb, hdr);
			goto out_err;
		}

		genlmsg_end(skb, hdr);
	}

	err = skb->len;
	/* see above */
	cb->args[0] = phy_idx + 1;
 out_err:
7107
	rtnl_unlock();
W
Wey-Yi Guy 已提交
7108 7109
	return err;
}
7110 7111
#endif

S
Samuel Ortiz 已提交
7112 7113
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
{
7114 7115
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
S
Samuel Ortiz 已提交
7116 7117
	struct cfg80211_connect_params connect;
	struct wiphy *wiphy;
J
Johannes Berg 已提交
7118
	struct cfg80211_cached_keys *connkeys = NULL;
S
Samuel Ortiz 已提交
7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132
	int err;

	memset(&connect, 0, sizeof(connect));

	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_SSID] ||
	    !nla_len(info->attrs[NL80211_ATTR_SSID]))
		return -EINVAL;

	if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
		connect.auth_type =
			nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
7133 7134
		if (!nl80211_valid_auth_type(rdev, connect.auth_type,
					     NL80211_CMD_CONNECT))
S
Samuel Ortiz 已提交
7135 7136 7137 7138 7139 7140
			return -EINVAL;
	} else
		connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;

	connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];

7141
	err = nl80211_crypto_settings(rdev, info, &connect.crypto,
7142
				      NL80211_MAX_NR_CIPHER_SUITES);
S
Samuel Ortiz 已提交
7143 7144 7145
	if (err)
		return err;

7146
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
7147 7148
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
S
Samuel Ortiz 已提交
7149

7150
	wiphy = &rdev->wiphy;
S
Samuel Ortiz 已提交
7151

7152 7153 7154 7155 7156 7157 7158
	connect.bg_scan_period = -1;
	if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
		(wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
		connect.bg_scan_period =
			nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
	}

S
Samuel Ortiz 已提交
7159 7160
	if (info->attrs[NL80211_ATTR_MAC])
		connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
7161 7162 7163
	else if (info->attrs[NL80211_ATTR_MAC_HINT])
		connect.bssid_hint =
			nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
S
Samuel Ortiz 已提交
7164 7165 7166 7167 7168 7169 7170 7171
	connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
	connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);

	if (info->attrs[NL80211_ATTR_IE]) {
		connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
		connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
	}

7172 7173 7174 7175 7176 7177 7178 7179 7180
	if (info->attrs[NL80211_ATTR_USE_MFP]) {
		connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
		if (connect.mfp != NL80211_MFP_REQUIRED &&
		    connect.mfp != NL80211_MFP_NO)
			return -EINVAL;
	} else {
		connect.mfp = NL80211_MFP_NO;
	}

S
Samuel Ortiz 已提交
7181
	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
7182 7183 7184
		connect.channel = nl80211_get_valid_chan(
			wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
		if (!connect.channel)
7185 7186
			return -EINVAL;
	} else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
7187 7188 7189
		connect.channel_hint = nl80211_get_valid_chan(
			wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
		if (!connect.channel_hint)
7190
			return -EINVAL;
S
Samuel Ortiz 已提交
7191 7192
	}

J
Johannes Berg 已提交
7193 7194
	if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
		connkeys = nl80211_parse_connkeys(rdev,
7195
					  info->attrs[NL80211_ATTR_KEYS], NULL);
7196 7197
		if (IS_ERR(connkeys))
			return PTR_ERR(connkeys);
J
Johannes Berg 已提交
7198 7199
	}

7200 7201 7202 7203 7204 7205 7206 7207 7208
	if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
		connect.flags |= ASSOC_REQ_DISABLE_HT;

	if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
		memcpy(&connect.ht_capa_mask,
		       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
		       sizeof(connect.ht_capa_mask));

	if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
7209 7210
		if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
			kfree(connkeys);
7211
			return -EINVAL;
7212
		}
7213 7214 7215 7216 7217
		memcpy(&connect.ht_capa,
		       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
		       sizeof(connect.ht_capa));
	}

7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235
	if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
		connect.flags |= ASSOC_REQ_DISABLE_VHT;

	if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
		memcpy(&connect.vht_capa_mask,
		       nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
		       sizeof(connect.vht_capa_mask));

	if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
		if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
			kfree(connkeys);
			return -EINVAL;
		}
		memcpy(&connect.vht_capa,
		       nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
		       sizeof(connect.vht_capa));
	}

7236 7237 7238
	wdev_lock(dev->ieee80211_ptr);
	err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
	wdev_unlock(dev->ieee80211_ptr);
J
Johannes Berg 已提交
7239 7240
	if (err)
		kfree(connkeys);
S
Samuel Ortiz 已提交
7241 7242 7243 7244 7245
	return err;
}

static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
{
7246 7247
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
S
Samuel Ortiz 已提交
7248
	u16 reason;
7249
	int ret;
S
Samuel Ortiz 已提交
7250 7251 7252 7253 7254 7255 7256 7257 7258

	if (!info->attrs[NL80211_ATTR_REASON_CODE])
		reason = WLAN_REASON_DEAUTH_LEAVING;
	else
		reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);

	if (reason == 0)
		return -EINVAL;

7259
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
7260 7261
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
S
Samuel Ortiz 已提交
7262

7263 7264 7265 7266
	wdev_lock(dev->ieee80211_ptr);
	ret = cfg80211_disconnect(rdev, dev, reason, true);
	wdev_unlock(dev->ieee80211_ptr);
	return ret;
S
Samuel Ortiz 已提交
7267 7268
}

7269 7270
static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
{
7271
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
7272 7273 7274 7275 7276 7277 7278 7279 7280 7281
	struct net *net;
	int err;
	u32 pid;

	if (!info->attrs[NL80211_ATTR_PID])
		return -EINVAL;

	pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);

	net = get_net_ns_by_pid(pid);
7282 7283
	if (IS_ERR(net))
		return PTR_ERR(net);
7284 7285 7286 7287

	err = 0;

	/* check if anything to do */
7288 7289
	if (!net_eq(wiphy_net(&rdev->wiphy), net))
		err = cfg80211_switch_netns(rdev, net);
7290 7291 7292 7293 7294

	put_net(net);
	return err;
}

S
Samuel Ortiz 已提交
7295 7296
static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
{
7297
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
S
Samuel Ortiz 已提交
7298 7299
	int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
			struct cfg80211_pmksa *pmksa) = NULL;
7300
	struct net_device *dev = info->user_ptr[1];
S
Samuel Ortiz 已提交
7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313
	struct cfg80211_pmksa pmksa;

	memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	if (!info->attrs[NL80211_ATTR_PMKID])
		return -EINVAL;

	pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
	pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);

7314
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
7315 7316
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
S
Samuel Ortiz 已提交
7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329

	switch (info->genlhdr->cmd) {
	case NL80211_CMD_SET_PMKSA:
		rdev_ops = rdev->ops->set_pmksa;
		break;
	case NL80211_CMD_DEL_PMKSA:
		rdev_ops = rdev->ops->del_pmksa;
		break;
	default:
		WARN_ON(1);
		break;
	}

7330 7331
	if (!rdev_ops)
		return -EOPNOTSUPP;
S
Samuel Ortiz 已提交
7332

7333
	return rdev_ops(&rdev->wiphy, dev, &pmksa);
S
Samuel Ortiz 已提交
7334 7335 7336 7337
}

static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
{
7338 7339
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
S
Samuel Ortiz 已提交
7340

7341
	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
7342 7343
	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
S
Samuel Ortiz 已提交
7344

7345 7346
	if (!rdev->ops->flush_pmksa)
		return -EOPNOTSUPP;
S
Samuel Ortiz 已提交
7347

7348
	return rdev_flush_pmksa(rdev, dev);
S
Samuel Ortiz 已提交
7349 7350
}

7351 7352 7353 7354 7355
static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	u8 action_code, dialog_token;
7356
	u32 peer_capability = 0;
7357 7358
	u16 status_code;
	u8 *peer;
7359
	bool initiator;
7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375

	if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
	    !rdev->ops->tdls_mgmt)
		return -EOPNOTSUPP;

	if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
	    !info->attrs[NL80211_ATTR_STATUS_CODE] ||
	    !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
	    !info->attrs[NL80211_ATTR_IE] ||
	    !info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
	action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
	status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
	dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
7376
	initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
7377 7378 7379
	if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
		peer_capability =
			nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
7380

7381
	return rdev_tdls_mgmt(rdev, dev, peer, action_code,
7382
			      dialog_token, status_code, peer_capability,
7383
			      initiator,
7384 7385
			      nla_data(info->attrs[NL80211_ATTR_IE]),
			      nla_len(info->attrs[NL80211_ATTR_IE]));
7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405
}

static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	enum nl80211_tdls_operation operation;
	u8 *peer;

	if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
	    !rdev->ops->tdls_oper)
		return -EOPNOTSUPP;

	if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
	    !info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
	peer = nla_data(info->attrs[NL80211_ATTR_MAC]);

7406
	return rdev_tdls_oper(rdev, dev, peer, operation);
7407 7408
}

7409 7410 7411
static int nl80211_remain_on_channel(struct sk_buff *skb,
				     struct genl_info *info)
{
7412
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
7413
	struct wireless_dev *wdev = info->user_ptr[1];
7414
	struct cfg80211_chan_def chandef;
7415 7416 7417
	struct sk_buff *msg;
	void *hdr;
	u64 cookie;
7418
	u32 duration;
7419 7420 7421 7422 7423 7424 7425 7426
	int err;

	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
	    !info->attrs[NL80211_ATTR_DURATION])
		return -EINVAL;

	duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);

7427 7428 7429 7430
	if (!rdev->ops->remain_on_channel ||
	    !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
		return -EOPNOTSUPP;

7431
	/*
7432 7433
	 * We should be on that channel for at least a minimum amount of
	 * time (10ms) but no longer than the driver supports.
7434
	 */
7435
	if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
7436
	    duration > rdev->wiphy.max_remain_on_channel_duration)
7437 7438
		return -EINVAL;

7439 7440 7441
	err = nl80211_parse_chandef(rdev, info, &chandef);
	if (err)
		return err;
7442 7443

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7444 7445
	if (!msg)
		return -ENOMEM;
7446

7447
	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
7448
			     NL80211_CMD_REMAIN_ON_CHANNEL);
7449 7450
	if (!hdr) {
		err = -ENOBUFS;
7451 7452 7453
		goto free_msg;
	}

7454 7455
	err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
				     duration, &cookie);
7456 7457 7458 7459

	if (err)
		goto free_msg;

7460 7461
	if (nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
		goto nla_put_failure;
7462 7463

	genlmsg_end(msg, hdr);
7464 7465

	return genlmsg_reply(msg, info);
7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476

 nla_put_failure:
	err = -ENOBUFS;
 free_msg:
	nlmsg_free(msg);
	return err;
}

static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
					    struct genl_info *info)
{
7477
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
7478
	struct wireless_dev *wdev = info->user_ptr[1];
7479 7480 7481 7482 7483
	u64 cookie;

	if (!info->attrs[NL80211_ATTR_COOKIE])
		return -EINVAL;

7484 7485
	if (!rdev->ops->cancel_remain_on_channel)
		return -EOPNOTSUPP;
7486 7487 7488

	cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);

7489
	return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
7490 7491
}

7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515
static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
			   u8 *rates, u8 rates_len)
{
	u8 i;
	u32 mask = 0;

	for (i = 0; i < rates_len; i++) {
		int rate = (rates[i] & 0x7f) * 5;
		int ridx;
		for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
			struct ieee80211_rate *srate =
				&sband->bitrates[ridx];
			if (rate == srate->bitrate) {
				mask |= 1 << ridx;
				break;
			}
		}
		if (ridx == sband->n_bitrates)
			return 0; /* rate not found */
	}

	return mask;
}

7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530
static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
			       u8 *rates, u8 rates_len,
			       u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
{
	u8 i;

	memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);

	for (i = 0; i < rates_len; i++) {
		int ridx, rbit;

		ridx = rates[i] / 8;
		rbit = BIT(rates[i] % 8);

		/* check validity */
7531
		if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543
			return false;

		/* check availability */
		if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
			mcs[ridx] |= rbit;
		else
			return false;
	}

	return true;
}

7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603
static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
{
	u16 mcs_mask = 0;

	switch (vht_mcs_map) {
	case IEEE80211_VHT_MCS_NOT_SUPPORTED:
		break;
	case IEEE80211_VHT_MCS_SUPPORT_0_7:
		mcs_mask = 0x00FF;
		break;
	case IEEE80211_VHT_MCS_SUPPORT_0_8:
		mcs_mask = 0x01FF;
		break;
	case IEEE80211_VHT_MCS_SUPPORT_0_9:
		mcs_mask = 0x03FF;
		break;
	default:
		break;
	}

	return mcs_mask;
}

static void vht_build_mcs_mask(u16 vht_mcs_map,
			       u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
{
	u8 nss;

	for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
		vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
		vht_mcs_map >>= 2;
	}
}

static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
			     struct nl80211_txrate_vht *txrate,
			     u16 mcs[NL80211_VHT_NSS_MAX])
{
	u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
	u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
	u8 i;

	if (!sband->vht_cap.vht_supported)
		return false;

	memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);

	/* Build vht_mcs_mask from VHT capabilities */
	vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);

	for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
		if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
			mcs[i] = txrate->mcs[i];
		else
			return false;
	}

	return true;
}

A
Alexey Dobriyan 已提交
7604
static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
7605 7606
	[NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
				    .len = NL80211_MAX_SUPP_RATES },
7607 7608
	[NL80211_TXRATE_HT] = { .type = NLA_BINARY,
				.len = NL80211_MAX_SUPP_HT_RATES },
7609
	[NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
7610
	[NL80211_TXRATE_GI] = { .type = NLA_U8 },
7611 7612 7613 7614 7615 7616
};

static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
				       struct genl_info *info)
{
	struct nlattr *tb[NL80211_TXRATE_MAX + 1];
7617
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
7618
	struct cfg80211_bitrate_mask mask;
7619 7620
	int rem, i;
	struct net_device *dev = info->user_ptr[1];
7621 7622
	struct nlattr *tx_rates;
	struct ieee80211_supported_band *sband;
7623
	u16 vht_tx_mcs_map;
7624

7625 7626
	if (!rdev->ops->set_bitrate_mask)
		return -EOPNOTSUPP;
7627 7628 7629 7630 7631

	memset(&mask, 0, sizeof(mask));
	/* Default to all rates enabled */
	for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
		sband = rdev->wiphy.bands[i];
7632 7633 7634 7635 7636

		if (!sband)
			continue;

		mask.control[i].legacy = (1 << sband->n_bitrates) - 1;
7637
		memcpy(mask.control[i].ht_mcs,
7638
		       sband->ht_cap.mcs.rx_mask,
7639
		       sizeof(mask.control[i].ht_mcs));
7640 7641 7642 7643 7644 7645

		if (!sband->vht_cap.vht_supported)
			continue;

		vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
		vht_build_mcs_mask(vht_tx_mcs_map, mask.control[i].vht_mcs);
7646 7647
	}

7648 7649 7650 7651
	/* if no rates are given set it back to the defaults */
	if (!info->attrs[NL80211_ATTR_TX_RATES])
		goto out;

7652 7653 7654 7655
	/*
	 * The nested attribute uses enum nl80211_band as the index. This maps
	 * directly to the enum ieee80211_band values used in cfg80211.
	 */
7656
	BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
7657
	nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
7658
		enum ieee80211_band band = nla_type(tx_rates);
7659 7660
		int err;

7661 7662
		if (band < 0 || band >= IEEE80211_NUM_BANDS)
			return -EINVAL;
7663
		sband = rdev->wiphy.bands[band];
7664 7665
		if (sband == NULL)
			return -EINVAL;
7666 7667 7668 7669
		err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
				nla_len(tx_rates), nl80211_txattr_policy);
		if (err)
			return err;
7670 7671 7672 7673 7674
		if (tb[NL80211_TXRATE_LEGACY]) {
			mask.control[band].legacy = rateset_to_mask(
				sband,
				nla_data(tb[NL80211_TXRATE_LEGACY]),
				nla_len(tb[NL80211_TXRATE_LEGACY]));
7675 7676 7677
			if ((mask.control[band].legacy == 0) &&
			    nla_len(tb[NL80211_TXRATE_LEGACY]))
				return -EINVAL;
7678
		}
7679
		if (tb[NL80211_TXRATE_HT]) {
7680 7681
			if (!ht_rateset_to_mask(
					sband,
7682 7683 7684
					nla_data(tb[NL80211_TXRATE_HT]),
					nla_len(tb[NL80211_TXRATE_HT]),
					mask.control[band].ht_mcs))
7685 7686
				return -EINVAL;
		}
7687 7688 7689 7690 7691 7692 7693
		if (tb[NL80211_TXRATE_VHT]) {
			if (!vht_set_mcs_mask(
					sband,
					nla_data(tb[NL80211_TXRATE_VHT]),
					mask.control[band].vht_mcs))
				return -EINVAL;
		}
7694 7695 7696 7697 7698 7699
		if (tb[NL80211_TXRATE_GI]) {
			mask.control[band].gi =
				nla_get_u8(tb[NL80211_TXRATE_GI]);
			if (mask.control[band].gi > NL80211_TXRATE_FORCE_LGI)
				return -EINVAL;
		}
7700 7701

		if (mask.control[band].legacy == 0) {
7702 7703 7704 7705 7706
			/* don't allow empty legacy rates if HT or VHT
			 * are not even supported.
			 */
			if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
			      rdev->wiphy.bands[band]->vht_cap.vht_supported))
7707 7708 7709
				return -EINVAL;

			for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
7710
				if (mask.control[band].ht_mcs[i])
7711 7712 7713 7714 7715
					goto out;

			for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
				if (mask.control[band].vht_mcs[i])
					goto out;
7716 7717

			/* legacy and mcs rates may not be both empty */
7718
			return -EINVAL;
7719 7720 7721
		}
	}

7722
out:
7723
	return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
7724 7725
}

7726
static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
7727
{
7728
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
7729
	struct wireless_dev *wdev = info->user_ptr[1];
7730
	u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
7731 7732 7733 7734

	if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
		return -EINVAL;

7735 7736
	if (info->attrs[NL80211_ATTR_FRAME_TYPE])
		frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
7737

7738 7739 7740 7741 7742 7743 7744 7745
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
	case NL80211_IFTYPE_MESH_POINT:
	case NL80211_IFTYPE_P2P_GO:
7746
	case NL80211_IFTYPE_P2P_DEVICE:
7747 7748
		break;
	default:
7749
		return -EOPNOTSUPP;
7750
	}
7751 7752

	/* not much point in registering if we can't reply */
7753 7754
	if (!rdev->ops->mgmt_tx)
		return -EOPNOTSUPP;
7755

7756
	return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
7757 7758 7759 7760
			nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
			nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
}

7761
static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
7762
{
7763
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
7764
	struct wireless_dev *wdev = info->user_ptr[1];
7765
	struct cfg80211_chan_def chandef;
7766
	int err;
J
Johannes Berg 已提交
7767
	void *hdr = NULL;
7768
	u64 cookie;
7769
	struct sk_buff *msg = NULL;
7770 7771 7772 7773
	struct cfg80211_mgmt_tx_params params = {
		.dont_wait_for_ack =
			info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
	};
7774

7775
	if (!info->attrs[NL80211_ATTR_FRAME])
7776 7777
		return -EINVAL;

7778 7779
	if (!rdev->ops->mgmt_tx)
		return -EOPNOTSUPP;
7780

7781
	switch (wdev->iftype) {
7782 7783 7784
	case NL80211_IFTYPE_P2P_DEVICE:
		if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
			return -EINVAL;
7785 7786 7787 7788 7789 7790 7791 7792 7793
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
	case NL80211_IFTYPE_MESH_POINT:
	case NL80211_IFTYPE_P2P_GO:
		break;
	default:
7794
		return -EOPNOTSUPP;
7795
	}
7796

7797
	if (info->attrs[NL80211_ATTR_DURATION]) {
7798
		if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
7799
			return -EINVAL;
7800
		params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
7801 7802 7803 7804 7805

		/*
		 * We should wait on the channel for at least a minimum amount
		 * of time (10ms) but no longer than the driver supports.
		 */
7806 7807
		if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
		    params.wait > rdev->wiphy.max_remain_on_channel_duration)
7808 7809
			return -EINVAL;

7810 7811
	}

7812
	params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
7813

7814
	if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
7815 7816
		return -EINVAL;

7817
	params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
7818

7819 7820 7821 7822 7823 7824 7825 7826 7827 7828
	/* get the channel if any has been specified, otherwise pass NULL to
	 * the driver. The latter will use the current one
	 */
	chandef.chan = NULL;
	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
		err = nl80211_parse_chandef(rdev, info, &chandef);
		if (err)
			return err;
	}

7829
	if (!chandef.chan && params.offchan)
7830
		return -EINVAL;
7831

7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852
	params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
	params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);

	if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
		int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
		int i;

		if (len % sizeof(u16))
			return -EINVAL;

		params.n_csa_offsets = len / sizeof(u16);
		params.csa_offsets =
			nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);

		/* check that all the offsets fit the frame */
		for (i = 0; i < params.n_csa_offsets; i++) {
			if (params.csa_offsets[i] >= params.len)
				return -EINVAL;
		}
	}

7853
	if (!params.dont_wait_for_ack) {
7854 7855 7856
		msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
		if (!msg)
			return -ENOMEM;
7857

7858
		hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
7859
				     NL80211_CMD_FRAME);
7860 7861
		if (!hdr) {
			err = -ENOBUFS;
7862 7863
			goto free_msg;
		}
7864
	}
7865

7866 7867
	params.chan = chandef.chan;
	err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
7868 7869 7870
	if (err)
		goto free_msg;

7871
	if (msg) {
7872 7873
		if (nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
			goto nla_put_failure;
7874

7875 7876 7877 7878 7879
		genlmsg_end(msg, hdr);
		return genlmsg_reply(msg, info);
	}

	return 0;
7880 7881 7882 7883 7884 7885 7886 7887

 nla_put_failure:
	err = -ENOBUFS;
 free_msg:
	nlmsg_free(msg);
	return err;
}

7888 7889 7890
static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
7891
	struct wireless_dev *wdev = info->user_ptr[1];
7892 7893 7894 7895 7896 7897 7898 7899
	u64 cookie;

	if (!info->attrs[NL80211_ATTR_COOKIE])
		return -EINVAL;

	if (!rdev->ops->mgmt_tx_cancel_wait)
		return -EOPNOTSUPP;

7900 7901 7902 7903 7904 7905 7906
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
	case NL80211_IFTYPE_P2P_GO:
7907
	case NL80211_IFTYPE_P2P_DEVICE:
7908 7909
		break;
	default:
7910
		return -EOPNOTSUPP;
7911
	}
7912 7913 7914

	cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);

7915
	return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
7916 7917
}

K
Kalle Valo 已提交
7918 7919
static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
{
7920
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
K
Kalle Valo 已提交
7921
	struct wireless_dev *wdev;
7922
	struct net_device *dev = info->user_ptr[1];
K
Kalle Valo 已提交
7923 7924 7925 7926
	u8 ps_state;
	bool state;
	int err;

7927 7928
	if (!info->attrs[NL80211_ATTR_PS_STATE])
		return -EINVAL;
K
Kalle Valo 已提交
7929 7930 7931

	ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);

7932 7933
	if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
		return -EINVAL;
K
Kalle Valo 已提交
7934 7935 7936

	wdev = dev->ieee80211_ptr;

7937 7938
	if (!rdev->ops->set_power_mgmt)
		return -EOPNOTSUPP;
K
Kalle Valo 已提交
7939 7940 7941 7942

	state = (ps_state == NL80211_PS_ENABLED) ? true : false;

	if (state == wdev->ps)
7943
		return 0;
K
Kalle Valo 已提交
7944

7945
	err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
7946 7947
	if (!err)
		wdev->ps = state;
K
Kalle Valo 已提交
7948 7949 7950 7951 7952
	return err;
}

static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
{
7953
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
K
Kalle Valo 已提交
7954 7955
	enum nl80211_ps_state ps_state;
	struct wireless_dev *wdev;
7956
	struct net_device *dev = info->user_ptr[1];
K
Kalle Valo 已提交
7957 7958 7959 7960 7961 7962
	struct sk_buff *msg;
	void *hdr;
	int err;

	wdev = dev->ieee80211_ptr;

7963 7964
	if (!rdev->ops->set_power_mgmt)
		return -EOPNOTSUPP;
K
Kalle Valo 已提交
7965 7966

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7967 7968
	if (!msg)
		return -ENOMEM;
K
Kalle Valo 已提交
7969

7970
	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
K
Kalle Valo 已提交
7971 7972
			     NL80211_CMD_GET_POWER_SAVE);
	if (!hdr) {
7973
		err = -ENOBUFS;
K
Kalle Valo 已提交
7974 7975 7976 7977 7978 7979 7980 7981
		goto free_msg;
	}

	if (wdev->ps)
		ps_state = NL80211_PS_ENABLED;
	else
		ps_state = NL80211_PS_DISABLED;

7982 7983
	if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
		goto nla_put_failure;
K
Kalle Valo 已提交
7984 7985

	genlmsg_end(msg, hdr);
7986
	return genlmsg_reply(msg, info);
K
Kalle Valo 已提交
7987

7988
 nla_put_failure:
K
Kalle Valo 已提交
7989
	err = -ENOBUFS;
7990
 free_msg:
K
Kalle Valo 已提交
7991 7992 7993 7994
	nlmsg_free(msg);
	return err;
}

7995 7996
static const struct nla_policy
nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
7997 7998 7999
	[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
	[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
	[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
8000 8001 8002
	[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
	[NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
	[NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
8003 8004
};

8005
static int nl80211_set_cqm_txe(struct genl_info *info,
J
Johannes Berg 已提交
8006
			       u32 rate, u32 pkts, u32 intvl)
8007 8008 8009
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
8010
	struct wireless_dev *wdev = dev->ieee80211_ptr;
8011

J
Johannes Berg 已提交
8012
	if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
8013 8014 8015 8016 8017 8018 8019 8020 8021
		return -EINVAL;

	if (!rdev->ops->set_cqm_txe_config)
		return -EOPNOTSUPP;

	if (wdev->iftype != NL80211_IFTYPE_STATION &&
	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;

8022
	return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
8023 8024
}

8025 8026 8027
static int nl80211_set_cqm_rssi(struct genl_info *info,
				s32 threshold, u32 hysteresis)
{
8028 8029
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
8030
	struct wireless_dev *wdev = dev->ieee80211_ptr;
8031 8032 8033 8034

	if (threshold > 0)
		return -EINVAL;

8035 8036 8037
	/* disabling - hysteresis should also be zero then */
	if (threshold == 0)
		hysteresis = 0;
8038

8039 8040
	if (!rdev->ops->set_cqm_rssi_config)
		return -EOPNOTSUPP;
8041

8042
	if (wdev->iftype != NL80211_IFTYPE_STATION &&
8043 8044
	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;
8045

8046
	return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
8047 8048 8049 8050 8051 8052 8053 8054 8055
}

static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
{
	struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
	struct nlattr *cqm;
	int err;

	cqm = info->attrs[NL80211_ATTR_CQM];
8056 8057
	if (!cqm)
		return -EINVAL;
8058 8059 8060 8061

	err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
			       nl80211_attr_cqm_policy);
	if (err)
8062
		return err;
8063 8064 8065

	if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
	    attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
8066 8067
		s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
		u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
8068

8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082
		return nl80211_set_cqm_rssi(info, threshold, hysteresis);
	}

	if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
	    attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
	    attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
		u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
		u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
		u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);

		return nl80211_set_cqm_txe(info, rate, pkts, intvl);
	}

	return -EINVAL;
8083 8084
}

8085 8086 8087 8088 8089
static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct mesh_config cfg;
8090
	struct mesh_setup setup;
8091 8092 8093 8094
	int err;

	/* start with default */
	memcpy(&cfg, &default_mesh_config, sizeof(cfg));
8095
	memcpy(&setup, &default_mesh_setup, sizeof(setup));
8096

8097
	if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
8098
		/* and parse parameters if given */
8099
		err = nl80211_parse_mesh_config(info, &cfg, NULL);
8100 8101 8102 8103 8104 8105 8106 8107
		if (err)
			return err;
	}

	if (!info->attrs[NL80211_ATTR_MESH_ID] ||
	    !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
		return -EINVAL;

8108 8109 8110
	setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
	setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);

8111 8112 8113 8114 8115
	if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
	    !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
			    nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
			return -EINVAL;

8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130
	if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
		setup.beacon_interval =
			nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
		if (setup.beacon_interval < 10 ||
		    setup.beacon_interval > 10000)
			return -EINVAL;
	}

	if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
		setup.dtim_period =
			nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
		if (setup.dtim_period < 1 || setup.dtim_period > 100)
			return -EINVAL;
	}

8131 8132 8133 8134 8135 8136 8137
	if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
		/* parse additional setup parameters if given */
		err = nl80211_parse_mesh_setup(info, &setup);
		if (err)
			return err;
	}

8138 8139 8140
	if (setup.user_mpm)
		cfg.auto_open_plinks = false;

8141
	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
8142 8143 8144
		err = nl80211_parse_chandef(rdev, info, &setup.chandef);
		if (err)
			return err;
8145 8146
	} else {
		/* cfg80211_join_mesh() will sort it out */
8147
		setup.chandef.chan = NULL;
8148 8149
	}

8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166
	if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
		u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
		int n_rates =
			nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
		struct ieee80211_supported_band *sband;

		if (!setup.chandef.chan)
			return -EINVAL;

		sband = rdev->wiphy.bands[setup.chandef.chan->band];

		err = ieee80211_get_ratemask(sband, rates, n_rates,
					     &setup.basic_rates);
		if (err)
			return err;
	}

8167
	return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
8168 8169 8170 8171 8172 8173 8174 8175 8176 8177
}

static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];

	return cfg80211_leave_mesh(rdev, dev);
}

8178
#ifdef CONFIG_PM
8179 8180 8181
static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
					struct cfg80211_registered_device *rdev)
{
8182
	struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
8183 8184 8185
	struct nlattr *nl_pats, *nl_pat;
	int i, pat_len;

8186
	if (!wowlan->n_patterns)
8187 8188 8189 8190 8191 8192
		return 0;

	nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
	if (!nl_pats)
		return -ENOBUFS;

8193
	for (i = 0; i < wowlan->n_patterns; i++) {
8194 8195 8196
		nl_pat = nla_nest_start(msg, i + 1);
		if (!nl_pat)
			return -ENOBUFS;
8197
		pat_len = wowlan->patterns[i].pattern_len;
8198
		if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
8199
			    wowlan->patterns[i].mask) ||
8200 8201 8202
		    nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
			    wowlan->patterns[i].pattern) ||
		    nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
8203
				wowlan->patterns[i].pkt_offset))
8204 8205 8206 8207 8208 8209 8210 8211
			return -ENOBUFS;
		nla_nest_end(msg, nl_pat);
	}
	nla_nest_end(msg, nl_pats);

	return 0;
}

8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249
static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
				   struct cfg80211_wowlan_tcp *tcp)
{
	struct nlattr *nl_tcp;

	if (!tcp)
		return 0;

	nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
	if (!nl_tcp)
		return -ENOBUFS;

	if (nla_put_be32(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
	    nla_put_be32(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
	    nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
	    nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
	    nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
	    nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
		    tcp->payload_len, tcp->payload) ||
	    nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
			tcp->data_interval) ||
	    nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
		    tcp->wake_len, tcp->wake_data) ||
	    nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
		    DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
		return -ENOBUFS;

	if (tcp->payload_seq.len &&
	    nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
		    sizeof(tcp->payload_seq), &tcp->payload_seq))
		return -ENOBUFS;

	if (tcp->payload_tok.len &&
	    nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
		    sizeof(tcp->payload_tok) + tcp->tokens_size,
		    &tcp->payload_tok))
		return -ENOBUFS;

8250 8251
	nla_nest_end(msg, nl_tcp);

8252 8253 8254
	return 0;
}

J
Johannes Berg 已提交
8255 8256 8257 8258 8259
static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct sk_buff *msg;
	void *hdr;
8260
	u32 size = NLMSG_DEFAULT_SIZE;
J
Johannes Berg 已提交
8261

8262
	if (!rdev->wiphy.wowlan)
J
Johannes Berg 已提交
8263 8264
		return -EOPNOTSUPP;

8265
	if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
8266
		/* adjust size to have room for all the data */
8267 8268 8269 8270
		size += rdev->wiphy.wowlan_config->tcp->tokens_size +
			rdev->wiphy.wowlan_config->tcp->payload_len +
			rdev->wiphy.wowlan_config->tcp->wake_len +
			rdev->wiphy.wowlan_config->tcp->wake_len / 8;
8271 8272 8273
	}

	msg = nlmsg_new(size, GFP_KERNEL);
J
Johannes Berg 已提交
8274 8275 8276
	if (!msg)
		return -ENOMEM;

8277
	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
J
Johannes Berg 已提交
8278 8279 8280 8281
			     NL80211_CMD_GET_WOWLAN);
	if (!hdr)
		goto nla_put_failure;

8282
	if (rdev->wiphy.wowlan_config) {
J
Johannes Berg 已提交
8283 8284 8285 8286 8287 8288
		struct nlattr *nl_wowlan;

		nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
		if (!nl_wowlan)
			goto nla_put_failure;

8289
		if ((rdev->wiphy.wowlan_config->any &&
8290
		     nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
8291
		    (rdev->wiphy.wowlan_config->disconnect &&
8292
		     nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
8293
		    (rdev->wiphy.wowlan_config->magic_pkt &&
8294
		     nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
8295
		    (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
8296
		     nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
8297
		    (rdev->wiphy.wowlan_config->eap_identity_req &&
8298
		     nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
8299
		    (rdev->wiphy.wowlan_config->four_way_handshake &&
8300
		     nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
8301
		    (rdev->wiphy.wowlan_config->rfkill_release &&
8302 8303
		     nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
			goto nla_put_failure;
8304

8305 8306
		if (nl80211_send_wowlan_patterns(msg, rdev))
			goto nla_put_failure;
8307

8308 8309
		if (nl80211_send_wowlan_tcp(msg,
					    rdev->wiphy.wowlan_config->tcp))
8310 8311
			goto nla_put_failure;

J
Johannes Berg 已提交
8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322
		nla_nest_end(msg, nl_wowlan);
	}

	genlmsg_end(msg, hdr);
	return genlmsg_reply(msg, info);

nla_put_failure:
	nlmsg_free(msg);
	return -ENOBUFS;
}

8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334
static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
				    struct nlattr *attr,
				    struct cfg80211_wowlan *trig)
{
	struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
	struct cfg80211_wowlan_tcp *cfg;
	struct nl80211_wowlan_tcp_data_token *tok = NULL;
	struct nl80211_wowlan_tcp_data_seq *seq = NULL;
	u32 size;
	u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
	int err, port;

8335
	if (!rdev->wiphy.wowlan->tcp)
8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354
		return -EINVAL;

	err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP,
			nla_data(attr), nla_len(attr),
			nl80211_wowlan_tcp_policy);
	if (err)
		return err;

	if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
	    !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
	    !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
	    !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
	    !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
	    !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
	    !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
	    !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
		return -EINVAL;

	data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
8355
	if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
8356 8357 8358
		return -EINVAL;

	if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
8359
			rdev->wiphy.wowlan->tcp->data_interval_max ||
8360
	    nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
8361 8362 8363
		return -EINVAL;

	wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
8364
	if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378
		return -EINVAL;

	wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
	if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
		return -EINVAL;

	if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
		u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);

		tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
		tokens_size = tokln - sizeof(*tok);

		if (!tok->len || tokens_size % tok->len)
			return -EINVAL;
8379
		if (!rdev->wiphy.wowlan->tcp->tok)
8380
			return -EINVAL;
8381
		if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
8382
			return -EINVAL;
8383
		if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
8384
			return -EINVAL;
8385
		if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
8386 8387 8388 8389 8390 8391 8392
			return -EINVAL;
		if (tok->offset + tok->len > data_size)
			return -EINVAL;
	}

	if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
		seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
8393
		if (!rdev->wiphy.wowlan->tcp->seq)
8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467
			return -EINVAL;
		if (seq->len == 0 || seq->len > 4)
			return -EINVAL;
		if (seq->len + seq->offset > data_size)
			return -EINVAL;
	}

	size = sizeof(*cfg);
	size += data_size;
	size += wake_size + wake_mask_size;
	size += tokens_size;

	cfg = kzalloc(size, GFP_KERNEL);
	if (!cfg)
		return -ENOMEM;
	cfg->src = nla_get_be32(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
	cfg->dst = nla_get_be32(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
	memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
	       ETH_ALEN);
	if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
		port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
	else
		port = 0;
#ifdef CONFIG_INET
	/* allocate a socket and port for it and use it */
	err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
			    IPPROTO_TCP, &cfg->sock, 1);
	if (err) {
		kfree(cfg);
		return err;
	}
	if (inet_csk_get_port(cfg->sock->sk, port)) {
		sock_release(cfg->sock);
		kfree(cfg);
		return -EADDRINUSE;
	}
	cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
#else
	if (!port) {
		kfree(cfg);
		return -EINVAL;
	}
	cfg->src_port = port;
#endif

	cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
	cfg->payload_len = data_size;
	cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
	memcpy((void *)cfg->payload,
	       nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
	       data_size);
	if (seq)
		cfg->payload_seq = *seq;
	cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
	cfg->wake_len = wake_size;
	cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
	memcpy((void *)cfg->wake_data,
	       nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
	       wake_size);
	cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
			 data_size + wake_size;
	memcpy((void *)cfg->wake_mask,
	       nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
	       wake_mask_size);
	if (tok) {
		cfg->tokens_size = tokens_size;
		memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
	}

	trig->tcp = cfg;

	return 0;
}

J
Johannes Berg 已提交
8468 8469 8470 8471 8472
static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
	struct cfg80211_wowlan new_triggers = {};
8473
	struct cfg80211_wowlan *ntrig;
8474
	const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
J
Johannes Berg 已提交
8475
	int err, i;
8476
	bool prev_enabled = rdev->wiphy.wowlan_config;
J
Johannes Berg 已提交
8477

8478
	if (!wowlan)
J
Johannes Berg 已提交
8479 8480
		return -EOPNOTSUPP;

8481 8482
	if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
		cfg80211_rdev_free_wowlan(rdev);
8483
		rdev->wiphy.wowlan_config = NULL;
8484 8485
		goto set_wakeup;
	}
J
Johannes Berg 已提交
8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511

	err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
			nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
			nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
			nl80211_wowlan_policy);
	if (err)
		return err;

	if (tb[NL80211_WOWLAN_TRIG_ANY]) {
		if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
			return -EINVAL;
		new_triggers.any = true;
	}

	if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
		if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
			return -EINVAL;
		new_triggers.disconnect = true;
	}

	if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
		if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
			return -EINVAL;
		new_triggers.magic_pkt = true;
	}

8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538
	if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
		return -EINVAL;

	if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
		if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
			return -EINVAL;
		new_triggers.gtk_rekey_failure = true;
	}

	if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
		if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
			return -EINVAL;
		new_triggers.eap_identity_req = true;
	}

	if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
		if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
			return -EINVAL;
		new_triggers.four_way_handshake = true;
	}

	if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
		if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
			return -EINVAL;
		new_triggers.rfkill_release = true;
	}

J
Johannes Berg 已提交
8539 8540 8541
	if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
		struct nlattr *pat;
		int n_patterns = 0;
8542
		int rem, pat_len, mask_len, pkt_offset;
8543
		struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
J
Johannes Berg 已提交
8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561

		nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
				    rem)
			n_patterns++;
		if (n_patterns > wowlan->n_patterns)
			return -EINVAL;

		new_triggers.patterns = kcalloc(n_patterns,
						sizeof(new_triggers.patterns[0]),
						GFP_KERNEL);
		if (!new_triggers.patterns)
			return -ENOMEM;

		new_triggers.n_patterns = n_patterns;
		i = 0;

		nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
				    rem) {
8562 8563
			u8 *mask_pat;

8564 8565
			nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
				  nla_len(pat), NULL);
J
Johannes Berg 已提交
8566
			err = -EINVAL;
8567 8568
			if (!pat_tb[NL80211_PKTPAT_MASK] ||
			    !pat_tb[NL80211_PKTPAT_PATTERN])
J
Johannes Berg 已提交
8569
				goto error;
8570
			pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
J
Johannes Berg 已提交
8571
			mask_len = DIV_ROUND_UP(pat_len, 8);
8572
			if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
J
Johannes Berg 已提交
8573 8574 8575 8576 8577
				goto error;
			if (pat_len > wowlan->pattern_max_len ||
			    pat_len < wowlan->pattern_min_len)
				goto error;

8578
			if (!pat_tb[NL80211_PKTPAT_OFFSET])
8579 8580 8581
				pkt_offset = 0;
			else
				pkt_offset = nla_get_u32(
8582
					pat_tb[NL80211_PKTPAT_OFFSET]);
8583 8584 8585 8586
			if (pkt_offset > wowlan->max_pkt_offset)
				goto error;
			new_triggers.patterns[i].pkt_offset = pkt_offset;

8587 8588
			mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
			if (!mask_pat) {
J
Johannes Berg 已提交
8589 8590 8591
				err = -ENOMEM;
				goto error;
			}
8592 8593
			new_triggers.patterns[i].mask = mask_pat;
			memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
J
Johannes Berg 已提交
8594
			       mask_len);
8595 8596
			mask_pat += mask_len;
			new_triggers.patterns[i].pattern = mask_pat;
J
Johannes Berg 已提交
8597
			new_triggers.patterns[i].pattern_len = pat_len;
8598
			memcpy(mask_pat,
8599
			       nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
J
Johannes Berg 已提交
8600 8601 8602 8603 8604
			       pat_len);
			i++;
		}
	}

8605 8606 8607 8608 8609 8610 8611 8612
	if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
		err = nl80211_parse_wowlan_tcp(
			rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
			&new_triggers);
		if (err)
			goto error;
	}

8613 8614 8615 8616
	ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
	if (!ntrig) {
		err = -ENOMEM;
		goto error;
J
Johannes Berg 已提交
8617
	}
8618
	cfg80211_rdev_free_wowlan(rdev);
8619
	rdev->wiphy.wowlan_config = ntrig;
J
Johannes Berg 已提交
8620

8621
 set_wakeup:
8622 8623 8624
	if (rdev->ops->set_wakeup &&
	    prev_enabled != !!rdev->wiphy.wowlan_config)
		rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
8625

J
Johannes Berg 已提交
8626 8627 8628 8629 8630
	return 0;
 error:
	for (i = 0; i < new_triggers.n_patterns; i++)
		kfree(new_triggers.patterns[i].mask);
	kfree(new_triggers.patterns);
8631 8632 8633
	if (new_triggers.tcp && new_triggers.tcp->sock)
		sock_release(new_triggers.tcp->sock);
	kfree(new_triggers.tcp);
J
Johannes Berg 已提交
8634 8635
	return err;
}
8636
#endif
J
Johannes Berg 已提交
8637

8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789
static int nl80211_send_coalesce_rules(struct sk_buff *msg,
				       struct cfg80211_registered_device *rdev)
{
	struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
	int i, j, pat_len;
	struct cfg80211_coalesce_rules *rule;

	if (!rdev->coalesce->n_rules)
		return 0;

	nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
	if (!nl_rules)
		return -ENOBUFS;

	for (i = 0; i < rdev->coalesce->n_rules; i++) {
		nl_rule = nla_nest_start(msg, i + 1);
		if (!nl_rule)
			return -ENOBUFS;

		rule = &rdev->coalesce->rules[i];
		if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
				rule->delay))
			return -ENOBUFS;

		if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
				rule->condition))
			return -ENOBUFS;

		nl_pats = nla_nest_start(msg,
				NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
		if (!nl_pats)
			return -ENOBUFS;

		for (j = 0; j < rule->n_patterns; j++) {
			nl_pat = nla_nest_start(msg, j + 1);
			if (!nl_pat)
				return -ENOBUFS;
			pat_len = rule->patterns[j].pattern_len;
			if (nla_put(msg, NL80211_PKTPAT_MASK,
				    DIV_ROUND_UP(pat_len, 8),
				    rule->patterns[j].mask) ||
			    nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
				    rule->patterns[j].pattern) ||
			    nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
					rule->patterns[j].pkt_offset))
				return -ENOBUFS;
			nla_nest_end(msg, nl_pat);
		}
		nla_nest_end(msg, nl_pats);
		nla_nest_end(msg, nl_rule);
	}
	nla_nest_end(msg, nl_rules);

	return 0;
}

static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct sk_buff *msg;
	void *hdr;

	if (!rdev->wiphy.coalesce)
		return -EOPNOTSUPP;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return -ENOMEM;

	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
			     NL80211_CMD_GET_COALESCE);
	if (!hdr)
		goto nla_put_failure;

	if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
		goto nla_put_failure;

	genlmsg_end(msg, hdr);
	return genlmsg_reply(msg, info);

nla_put_failure:
	nlmsg_free(msg);
	return -ENOBUFS;
}

void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
{
	struct cfg80211_coalesce *coalesce = rdev->coalesce;
	int i, j;
	struct cfg80211_coalesce_rules *rule;

	if (!coalesce)
		return;

	for (i = 0; i < coalesce->n_rules; i++) {
		rule = &coalesce->rules[i];
		for (j = 0; j < rule->n_patterns; j++)
			kfree(rule->patterns[j].mask);
		kfree(rule->patterns);
	}
	kfree(coalesce->rules);
	kfree(coalesce);
	rdev->coalesce = NULL;
}

static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
				       struct nlattr *rule,
				       struct cfg80211_coalesce_rules *new_rule)
{
	int err, i;
	const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
	struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
	int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
	struct nlattr *pat_tb[NUM_NL80211_PKTPAT];

	err = nla_parse(tb, NL80211_ATTR_COALESCE_RULE_MAX, nla_data(rule),
			nla_len(rule), nl80211_coalesce_policy);
	if (err)
		return err;

	if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
		new_rule->delay =
			nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
	if (new_rule->delay > coalesce->max_delay)
		return -EINVAL;

	if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
		new_rule->condition =
			nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
	if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
	    new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
		return -EINVAL;

	if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
		return -EINVAL;

	nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
			    rem)
		n_patterns++;
	if (n_patterns > coalesce->n_patterns)
		return -EINVAL;

	new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
				     GFP_KERNEL);
	if (!new_rule->patterns)
		return -ENOMEM;

	new_rule->n_patterns = n_patterns;
	i = 0;

	nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
			    rem) {
8790 8791
		u8 *mask_pat;

8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812
		nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
			  nla_len(pat), NULL);
		if (!pat_tb[NL80211_PKTPAT_MASK] ||
		    !pat_tb[NL80211_PKTPAT_PATTERN])
			return -EINVAL;
		pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
		mask_len = DIV_ROUND_UP(pat_len, 8);
		if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
			return -EINVAL;
		if (pat_len > coalesce->pattern_max_len ||
		    pat_len < coalesce->pattern_min_len)
			return -EINVAL;

		if (!pat_tb[NL80211_PKTPAT_OFFSET])
			pkt_offset = 0;
		else
			pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
		if (pkt_offset > coalesce->max_pkt_offset)
			return -EINVAL;
		new_rule->patterns[i].pkt_offset = pkt_offset;

8813 8814
		mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
		if (!mask_pat)
8815
			return -ENOMEM;
8816 8817 8818 8819 8820 8821 8822

		new_rule->patterns[i].mask = mask_pat;
		memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
		       mask_len);

		mask_pat += mask_len;
		new_rule->patterns[i].pattern = mask_pat;
8823
		new_rule->patterns[i].pattern_len = pat_len;
8824 8825
		memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
		       pat_len);
8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899
		i++;
	}

	return 0;
}

static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
	struct cfg80211_coalesce new_coalesce = {};
	struct cfg80211_coalesce *n_coalesce;
	int err, rem_rule, n_rules = 0, i, j;
	struct nlattr *rule;
	struct cfg80211_coalesce_rules *tmp_rule;

	if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
		return -EOPNOTSUPP;

	if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
		cfg80211_rdev_free_coalesce(rdev);
		rdev->ops->set_coalesce(&rdev->wiphy, NULL);
		return 0;
	}

	nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
			    rem_rule)
		n_rules++;
	if (n_rules > coalesce->n_rules)
		return -EINVAL;

	new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
				     GFP_KERNEL);
	if (!new_coalesce.rules)
		return -ENOMEM;

	new_coalesce.n_rules = n_rules;
	i = 0;

	nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
			    rem_rule) {
		err = nl80211_parse_coalesce_rule(rdev, rule,
						  &new_coalesce.rules[i]);
		if (err)
			goto error;

		i++;
	}

	err = rdev->ops->set_coalesce(&rdev->wiphy, &new_coalesce);
	if (err)
		goto error;

	n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
	if (!n_coalesce) {
		err = -ENOMEM;
		goto error;
	}
	cfg80211_rdev_free_coalesce(rdev);
	rdev->coalesce = n_coalesce;

	return 0;
error:
	for (i = 0; i < new_coalesce.n_rules; i++) {
		tmp_rule = &new_coalesce.rules[i];
		for (j = 0; j < tmp_rule->n_patterns; j++)
			kfree(tmp_rule->patterns[j].mask);
		kfree(tmp_rule->patterns);
	}
	kfree(new_coalesce.rules);

	return err;
}

8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944
static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct nlattr *tb[NUM_NL80211_REKEY_DATA];
	struct cfg80211_gtk_rekey_data rekey_data;
	int err;

	if (!info->attrs[NL80211_ATTR_REKEY_DATA])
		return -EINVAL;

	err = nla_parse(tb, MAX_NL80211_REKEY_DATA,
			nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]),
			nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]),
			nl80211_rekey_policy);
	if (err)
		return err;

	if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
		return -ERANGE;
	if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
		return -ERANGE;
	if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
		return -ERANGE;

	memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]),
	       NL80211_KEK_LEN);
	memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]),
	       NL80211_KCK_LEN);
	memcpy(rekey_data.replay_ctr,
	       nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]),
	       NL80211_REPLAY_CTR_LEN);

	wdev_lock(wdev);
	if (!wdev->current_bss) {
		err = -ENOTCONN;
		goto out;
	}

	if (!rdev->ops->set_rekey_data) {
		err = -EOPNOTSUPP;
		goto out;
	}

8945
	err = rdev_set_rekey_data(rdev, dev, &rekey_data);
8946 8947 8948 8949 8950
 out:
	wdev_unlock(wdev);
	return err;
}

8951 8952 8953 8954 8955 8956 8957 8958 8959 8960
static int nl80211_register_unexpected_frame(struct sk_buff *skb,
					     struct genl_info *info)
{
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;

	if (wdev->iftype != NL80211_IFTYPE_AP &&
	    wdev->iftype != NL80211_IFTYPE_P2P_GO)
		return -EINVAL;

8961
	if (wdev->ap_unexpected_nlportid)
8962 8963
		return -EBUSY;

8964
	wdev->ap_unexpected_nlportid = info->snd_portid;
8965 8966 8967
	return 0;
}

J
Johannes Berg 已提交
8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993
static int nl80211_probe_client(struct sk_buff *skb,
				struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct sk_buff *msg;
	void *hdr;
	const u8 *addr;
	u64 cookie;
	int err;

	if (wdev->iftype != NL80211_IFTYPE_AP &&
	    wdev->iftype != NL80211_IFTYPE_P2P_GO)
		return -EOPNOTSUPP;

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	if (!rdev->ops->probe_client)
		return -EOPNOTSUPP;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return -ENOMEM;

8994
	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
J
Johannes Berg 已提交
8995
			     NL80211_CMD_PROBE_CLIENT);
8996 8997
	if (!hdr) {
		err = -ENOBUFS;
J
Johannes Berg 已提交
8998 8999 9000 9001 9002
		goto free_msg;
	}

	addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

9003
	err = rdev_probe_client(rdev, dev, addr, &cookie);
J
Johannes Berg 已提交
9004 9005 9006
	if (err)
		goto free_msg;

9007 9008
	if (nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
		goto nla_put_failure;
J
Johannes Berg 已提交
9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020

	genlmsg_end(msg, hdr);

	return genlmsg_reply(msg, info);

 nla_put_failure:
	err = -ENOBUFS;
 free_msg:
	nlmsg_free(msg);
	return err;
}

9021 9022 9023
static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
9024 9025
	struct cfg80211_beacon_registration *reg, *nreg;
	int rv;
9026 9027 9028 9029

	if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
		return -EOPNOTSUPP;

9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044
	nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
	if (!nreg)
		return -ENOMEM;

	/* First, check if already registered. */
	spin_lock_bh(&rdev->beacon_registrations_lock);
	list_for_each_entry(reg, &rdev->beacon_registrations, list) {
		if (reg->nlportid == info->snd_portid) {
			rv = -EALREADY;
			goto out_err;
		}
	}
	/* Add it to the list */
	nreg->nlportid = info->snd_portid;
	list_add(&nreg->list, &rdev->beacon_registrations);
9045

9046
	spin_unlock_bh(&rdev->beacon_registrations_lock);
9047 9048

	return 0;
9049 9050 9051 9052
out_err:
	spin_unlock_bh(&rdev->beacon_registrations_lock);
	kfree(nreg);
	return rv;
9053 9054
}

9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069
static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct wireless_dev *wdev = info->user_ptr[1];
	int err;

	if (!rdev->ops->start_p2p_device)
		return -EOPNOTSUPP;

	if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
		return -EOPNOTSUPP;

	if (wdev->p2p_started)
		return 0;

9070 9071
	if (rfkill_blocked(rdev->rfkill))
		return -ERFKILL;
9072

9073
	err = rdev_start_p2p_device(rdev, wdev);
9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093
	if (err)
		return err;

	wdev->p2p_started = true;
	rdev->opencount++;

	return 0;
}

static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct wireless_dev *wdev = info->user_ptr[1];

	if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
		return -EOPNOTSUPP;

	if (!rdev->ops->stop_p2p_device)
		return -EOPNOTSUPP;

9094
	cfg80211_stop_p2p_device(rdev, wdev);
9095 9096 9097 9098

	return 0;
}

9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125
static int nl80211_get_protocol_features(struct sk_buff *skb,
					 struct genl_info *info)
{
	void *hdr;
	struct sk_buff *msg;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return -ENOMEM;

	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
			     NL80211_CMD_GET_PROTOCOL_FEATURES);
	if (!hdr)
		goto nla_put_failure;

	if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
			NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
		goto nla_put_failure;

	genlmsg_end(msg, hdr);
	return genlmsg_reply(msg, info);

 nla_put_failure:
	kfree_skb(msg);
	return -ENOBUFS;
}

9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146
static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct cfg80211_update_ft_ies_params ft_params;
	struct net_device *dev = info->user_ptr[1];

	if (!rdev->ops->update_ft_ies)
		return -EOPNOTSUPP;

	if (!info->attrs[NL80211_ATTR_MDID] ||
	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;

	memset(&ft_params, 0, sizeof(ft_params));
	ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
	ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
	ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);

	return rdev_update_ft_ies(rdev, dev, &ft_params);
}

9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204
static int nl80211_crit_protocol_start(struct sk_buff *skb,
				       struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct wireless_dev *wdev = info->user_ptr[1];
	enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
	u16 duration;
	int ret;

	if (!rdev->ops->crit_proto_start)
		return -EOPNOTSUPP;

	if (WARN_ON(!rdev->ops->crit_proto_stop))
		return -EINVAL;

	if (rdev->crit_proto_nlportid)
		return -EBUSY;

	/* determine protocol if provided */
	if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
		proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);

	if (proto >= NUM_NL80211_CRIT_PROTO)
		return -EINVAL;

	/* timeout must be provided */
	if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
		return -EINVAL;

	duration =
		nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);

	if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
		return -ERANGE;

	ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
	if (!ret)
		rdev->crit_proto_nlportid = info->snd_portid;

	return ret;
}

static int nl80211_crit_protocol_stop(struct sk_buff *skb,
				      struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct wireless_dev *wdev = info->user_ptr[1];

	if (!rdev->ops->crit_proto_stop)
		return -EOPNOTSUPP;

	if (rdev->crit_proto_nlportid) {
		rdev->crit_proto_nlportid = 0;
		rdev_crit_proto_stop(rdev, wdev);
	}
	return 0;
}

J
Johannes Berg 已提交
9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279
static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct wireless_dev *wdev =
		__cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
	int i, err;
	u32 vid, subcmd;

	if (!rdev->wiphy.vendor_commands)
		return -EOPNOTSUPP;

	if (IS_ERR(wdev)) {
		err = PTR_ERR(wdev);
		if (err != -EINVAL)
			return err;
		wdev = NULL;
	} else if (wdev->wiphy != &rdev->wiphy) {
		return -EINVAL;
	}

	if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
	    !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
		return -EINVAL;

	vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
	subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
	for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
		const struct wiphy_vendor_command *vcmd;
		void *data = NULL;
		int len = 0;

		vcmd = &rdev->wiphy.vendor_commands[i];

		if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
			continue;

		if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
				   WIPHY_VENDOR_CMD_NEED_NETDEV)) {
			if (!wdev)
				return -EINVAL;
			if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
			    !wdev->netdev)
				return -EINVAL;

			if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
				if (wdev->netdev &&
				    !netif_running(wdev->netdev))
					return -ENETDOWN;
				if (!wdev->netdev && !wdev->p2p_started)
					return -ENETDOWN;
			}
		} else {
			wdev = NULL;
		}

		if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
			data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
			len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
		}

		rdev->cur_cmd_info = info;
		err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
							  data, len);
		rdev->cur_cmd_info = NULL;
		return err;
	}

	return -EOPNOTSUPP;
}

struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
					   enum nl80211_commands cmd,
					   enum nl80211_attrs attr,
					   int approxlen)
{
9280
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
J
Johannes Berg 已提交
9281 9282 9283 9284 9285 9286 9287

	if (WARN_ON(!rdev->cur_cmd_info))
		return NULL;

	return __cfg80211_alloc_vendor_skb(rdev, approxlen,
					   rdev->cur_cmd_info->snd_portid,
					   rdev->cur_cmd_info->snd_seq,
9288
					   cmd, attr, NULL, GFP_KERNEL);
J
Johannes Berg 已提交
9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309
}
EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);

int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
{
	struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
	void *hdr = ((void **)skb->cb)[1];
	struct nlattr *data = ((void **)skb->cb)[2];

	if (WARN_ON(!rdev->cur_cmd_info)) {
		kfree_skb(skb);
		return -EINVAL;
	}

	nla_nest_end(skb, data);
	genlmsg_end(skb, hdr);
	return genlmsg_reply(skb, rdev->cur_cmd_info);
}
EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);


9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360
static int nl80211_set_qos_map(struct sk_buff *skb,
			       struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct cfg80211_qos_map *qos_map = NULL;
	struct net_device *dev = info->user_ptr[1];
	u8 *pos, len, num_des, des_len, des;
	int ret;

	if (!rdev->ops->set_qos_map)
		return -EOPNOTSUPP;

	if (info->attrs[NL80211_ATTR_QOS_MAP]) {
		pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
		len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);

		if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
		    len > IEEE80211_QOS_MAP_LEN_MAX)
			return -EINVAL;

		qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
		if (!qos_map)
			return -ENOMEM;

		num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
		if (num_des) {
			des_len = num_des *
				sizeof(struct cfg80211_dscp_exception);
			memcpy(qos_map->dscp_exception, pos, des_len);
			qos_map->num_des = num_des;
			for (des = 0; des < num_des; des++) {
				if (qos_map->dscp_exception[des].up > 7) {
					kfree(qos_map);
					return -EINVAL;
				}
			}
			pos += des_len;
		}
		memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
	}

	wdev_lock(dev->ieee80211_ptr);
	ret = nl80211_key_allowed(dev->ieee80211_ptr);
	if (!ret)
		ret = rdev_set_qos_map(rdev, dev, qos_map);
	wdev_unlock(dev->ieee80211_ptr);

	kfree(qos_map);
	return ret;
}

9361 9362 9363
#define NL80211_FLAG_NEED_WIPHY		0x01
#define NL80211_FLAG_NEED_NETDEV	0x02
#define NL80211_FLAG_NEED_RTNL		0x04
9364 9365 9366
#define NL80211_FLAG_CHECK_NETDEV_UP	0x08
#define NL80211_FLAG_NEED_NETDEV_UP	(NL80211_FLAG_NEED_NETDEV |\
					 NL80211_FLAG_CHECK_NETDEV_UP)
9367
#define NL80211_FLAG_NEED_WDEV		0x10
9368
/* If a netdev is associated, it must be UP, P2P must be started */
9369 9370
#define NL80211_FLAG_NEED_WDEV_UP	(NL80211_FLAG_NEED_WDEV |\
					 NL80211_FLAG_CHECK_NETDEV_UP)
9371

J
Johannes Berg 已提交
9372
static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
9373 9374 9375
			    struct genl_info *info)
{
	struct cfg80211_registered_device *rdev;
9376
	struct wireless_dev *wdev;
9377 9378 9379 9380 9381 9382 9383
	struct net_device *dev;
	bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;

	if (rtnl)
		rtnl_lock();

	if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
J
Johannes Berg 已提交
9384
		rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
9385 9386 9387 9388 9389 9390
		if (IS_ERR(rdev)) {
			if (rtnl)
				rtnl_unlock();
			return PTR_ERR(rdev);
		}
		info->user_ptr[0] = rdev;
9391 9392
	} else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
		   ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
9393 9394
		ASSERT_RTNL();

9395 9396 9397
		wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
						  info->attrs);
		if (IS_ERR(wdev)) {
9398 9399
			if (rtnl)
				rtnl_unlock();
9400
			return PTR_ERR(wdev);
9401
		}
9402 9403

		dev = wdev->netdev;
9404
		rdev = wiphy_to_rdev(wdev->wiphy);
9405

9406 9407 9408 9409 9410 9411 9412 9413 9414 9415
		if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
			if (!dev) {
				if (rtnl)
					rtnl_unlock();
				return -EINVAL;
			}

			info->user_ptr[1] = dev;
		} else {
			info->user_ptr[1] = wdev;
9416
		}
9417 9418 9419 9420 9421 9422 9423 9424 9425 9426

		if (dev) {
			if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
			    !netif_running(dev)) {
				if (rtnl)
					rtnl_unlock();
				return -ENETDOWN;
			}

			dev_hold(dev);
9427 9428 9429 9430 9431 9432
		} else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
			if (!wdev->p2p_started) {
				if (rtnl)
					rtnl_unlock();
				return -ENETDOWN;
			}
9433
		}
9434

9435 9436 9437 9438 9439 9440
		info->user_ptr[0] = rdev;
	}

	return 0;
}

J
Johannes Berg 已提交
9441
static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
9442 9443
			      struct genl_info *info)
{
9444 9445 9446 9447 9448 9449 9450 9451 9452 9453
	if (info->user_ptr[1]) {
		if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
			struct wireless_dev *wdev = info->user_ptr[1];

			if (wdev->netdev)
				dev_put(wdev->netdev);
		} else {
			dev_put(info->user_ptr[1]);
		}
	}
9454 9455 9456 9457
	if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
		rtnl_unlock();
}

9458
static const struct genl_ops nl80211_ops[] = {
9459 9460 9461 9462
	{
		.cmd = NL80211_CMD_GET_WIPHY,
		.doit = nl80211_get_wiphy,
		.dumpit = nl80211_dump_wiphy,
9463
		.done = nl80211_dump_wiphy_done,
9464 9465
		.policy = nl80211_policy,
		/* can be retrieved by unprivileged users */
9466 9467
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
9468 9469 9470 9471 9472 9473
	},
	{
		.cmd = NL80211_CMD_SET_WIPHY,
		.doit = nl80211_set_wiphy,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9474
		.internal_flags = NL80211_FLAG_NEED_RTNL,
9475 9476 9477 9478 9479 9480 9481
	},
	{
		.cmd = NL80211_CMD_GET_INTERFACE,
		.doit = nl80211_get_interface,
		.dumpit = nl80211_dump_interface,
		.policy = nl80211_policy,
		/* can be retrieved by unprivileged users */
9482 9483
		.internal_flags = NL80211_FLAG_NEED_WDEV |
				  NL80211_FLAG_NEED_RTNL,
9484 9485 9486 9487 9488 9489
	},
	{
		.cmd = NL80211_CMD_SET_INTERFACE,
		.doit = nl80211_set_interface,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9490 9491
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
9492 9493 9494 9495 9496 9497
	},
	{
		.cmd = NL80211_CMD_NEW_INTERFACE,
		.doit = nl80211_new_interface,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9498 9499
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
9500 9501 9502 9503 9504
	},
	{
		.cmd = NL80211_CMD_DEL_INTERFACE,
		.doit = nl80211_del_interface,
		.policy = nl80211_policy,
9505
		.flags = GENL_ADMIN_PERM,
9506
		.internal_flags = NL80211_FLAG_NEED_WDEV |
9507
				  NL80211_FLAG_NEED_RTNL,
9508 9509 9510 9511 9512 9513
	},
	{
		.cmd = NL80211_CMD_GET_KEY,
		.doit = nl80211_get_key,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9514
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9515
				  NL80211_FLAG_NEED_RTNL,
9516 9517 9518 9519 9520 9521
	},
	{
		.cmd = NL80211_CMD_SET_KEY,
		.doit = nl80211_set_key,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9522
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9523
				  NL80211_FLAG_NEED_RTNL,
9524 9525 9526 9527 9528 9529
	},
	{
		.cmd = NL80211_CMD_NEW_KEY,
		.doit = nl80211_new_key,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9530
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9531
				  NL80211_FLAG_NEED_RTNL,
9532 9533 9534 9535 9536
	},
	{
		.cmd = NL80211_CMD_DEL_KEY,
		.doit = nl80211_del_key,
		.policy = nl80211_policy,
9537
		.flags = GENL_ADMIN_PERM,
9538
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9539
				  NL80211_FLAG_NEED_RTNL,
9540
	},
9541 9542 9543 9544
	{
		.cmd = NL80211_CMD_SET_BEACON,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9545
		.doit = nl80211_set_beacon,
9546
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9547
				  NL80211_FLAG_NEED_RTNL,
9548 9549
	},
	{
9550
		.cmd = NL80211_CMD_START_AP,
9551 9552
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9553
		.doit = nl80211_start_ap,
9554
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9555
				  NL80211_FLAG_NEED_RTNL,
9556 9557
	},
	{
9558
		.cmd = NL80211_CMD_STOP_AP,
9559 9560
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9561
		.doit = nl80211_stop_ap,
9562
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9563
				  NL80211_FLAG_NEED_RTNL,
9564
	},
9565 9566 9567
	{
		.cmd = NL80211_CMD_GET_STATION,
		.doit = nl80211_get_station,
9568
		.dumpit = nl80211_dump_station,
9569
		.policy = nl80211_policy,
9570 9571
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
9572 9573 9574 9575 9576 9577
	},
	{
		.cmd = NL80211_CMD_SET_STATION,
		.doit = nl80211_set_station,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9578
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9579
				  NL80211_FLAG_NEED_RTNL,
9580 9581 9582 9583 9584 9585
	},
	{
		.cmd = NL80211_CMD_NEW_STATION,
		.doit = nl80211_new_station,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9586
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9587
				  NL80211_FLAG_NEED_RTNL,
9588 9589 9590 9591 9592
	},
	{
		.cmd = NL80211_CMD_DEL_STATION,
		.doit = nl80211_del_station,
		.policy = nl80211_policy,
9593
		.flags = GENL_ADMIN_PERM,
9594
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9595
				  NL80211_FLAG_NEED_RTNL,
9596 9597 9598 9599 9600 9601 9602
	},
	{
		.cmd = NL80211_CMD_GET_MPATH,
		.doit = nl80211_get_mpath,
		.dumpit = nl80211_dump_mpath,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9603
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9604
				  NL80211_FLAG_NEED_RTNL,
9605 9606 9607 9608 9609 9610
	},
	{
		.cmd = NL80211_CMD_SET_MPATH,
		.doit = nl80211_set_mpath,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9611
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9612
				  NL80211_FLAG_NEED_RTNL,
9613 9614 9615 9616 9617 9618
	},
	{
		.cmd = NL80211_CMD_NEW_MPATH,
		.doit = nl80211_new_mpath,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9619
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9620
				  NL80211_FLAG_NEED_RTNL,
9621 9622 9623 9624 9625
	},
	{
		.cmd = NL80211_CMD_DEL_MPATH,
		.doit = nl80211_del_mpath,
		.policy = nl80211_policy,
9626
		.flags = GENL_ADMIN_PERM,
9627
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9628
				  NL80211_FLAG_NEED_RTNL,
9629 9630 9631 9632 9633
	},
	{
		.cmd = NL80211_CMD_SET_BSS,
		.doit = nl80211_set_bss,
		.policy = nl80211_policy,
9634
		.flags = GENL_ADMIN_PERM,
9635
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9636
				  NL80211_FLAG_NEED_RTNL,
9637
	},
9638 9639 9640 9641
	{
		.cmd = NL80211_CMD_GET_REG,
		.doit = nl80211_get_reg,
		.policy = nl80211_policy,
9642
		.internal_flags = NL80211_FLAG_NEED_RTNL,
9643 9644
		/* can be retrieved by unprivileged users */
	},
9645 9646 9647 9648 9649
	{
		.cmd = NL80211_CMD_SET_REG,
		.doit = nl80211_set_reg,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9650
		.internal_flags = NL80211_FLAG_NEED_RTNL,
9651 9652 9653 9654 9655
	},
	{
		.cmd = NL80211_CMD_REQ_SET_REG,
		.doit = nl80211_req_set_reg,
		.policy = nl80211_policy,
9656 9657 9658
		.flags = GENL_ADMIN_PERM,
	},
	{
9659 9660
		.cmd = NL80211_CMD_GET_MESH_CONFIG,
		.doit = nl80211_get_mesh_config,
9661 9662
		.policy = nl80211_policy,
		/* can be retrieved by unprivileged users */
9663
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9664
				  NL80211_FLAG_NEED_RTNL,
9665 9666
	},
	{
9667 9668
		.cmd = NL80211_CMD_SET_MESH_CONFIG,
		.doit = nl80211_update_mesh_config,
9669
		.policy = nl80211_policy,
9670
		.flags = GENL_ADMIN_PERM,
9671
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9672
				  NL80211_FLAG_NEED_RTNL,
9673
	},
9674 9675 9676 9677 9678
	{
		.cmd = NL80211_CMD_TRIGGER_SCAN,
		.doit = nl80211_trigger_scan,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
J
Johannes Berg 已提交
9679
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
9680
				  NL80211_FLAG_NEED_RTNL,
9681 9682 9683 9684 9685 9686
	},
	{
		.cmd = NL80211_CMD_GET_SCAN,
		.policy = nl80211_policy,
		.dumpit = nl80211_dump_scan,
	},
9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702
	{
		.cmd = NL80211_CMD_START_SCHED_SCAN,
		.doit = nl80211_start_sched_scan,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_STOP_SCHED_SCAN,
		.doit = nl80211_stop_sched_scan,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
9703 9704 9705 9706 9707
	{
		.cmd = NL80211_CMD_AUTHENTICATE,
		.doit = nl80211_authenticate,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9708
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9709
				  NL80211_FLAG_NEED_RTNL,
9710 9711 9712 9713 9714 9715
	},
	{
		.cmd = NL80211_CMD_ASSOCIATE,
		.doit = nl80211_associate,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9716
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9717
				  NL80211_FLAG_NEED_RTNL,
9718 9719 9720 9721 9722 9723
	},
	{
		.cmd = NL80211_CMD_DEAUTHENTICATE,
		.doit = nl80211_deauthenticate,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9724
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9725
				  NL80211_FLAG_NEED_RTNL,
9726 9727 9728 9729 9730 9731
	},
	{
		.cmd = NL80211_CMD_DISASSOCIATE,
		.doit = nl80211_disassociate,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9732
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9733
				  NL80211_FLAG_NEED_RTNL,
9734
	},
J
Johannes Berg 已提交
9735 9736 9737 9738 9739
	{
		.cmd = NL80211_CMD_JOIN_IBSS,
		.doit = nl80211_join_ibss,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9740
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9741
				  NL80211_FLAG_NEED_RTNL,
J
Johannes Berg 已提交
9742 9743 9744 9745 9746 9747
	},
	{
		.cmd = NL80211_CMD_LEAVE_IBSS,
		.doit = nl80211_leave_ibss,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9748
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9749
				  NL80211_FLAG_NEED_RTNL,
J
Johannes Berg 已提交
9750
	},
9751 9752 9753 9754
#ifdef CONFIG_NL80211_TESTMODE
	{
		.cmd = NL80211_CMD_TESTMODE,
		.doit = nl80211_testmode_do,
W
Wey-Yi Guy 已提交
9755
		.dumpit = nl80211_testmode_dump,
9756 9757
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9758 9759
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
9760 9761
	},
#endif
S
Samuel Ortiz 已提交
9762 9763 9764 9765 9766
	{
		.cmd = NL80211_CMD_CONNECT,
		.doit = nl80211_connect,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9767
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9768
				  NL80211_FLAG_NEED_RTNL,
S
Samuel Ortiz 已提交
9769 9770 9771 9772 9773 9774
	},
	{
		.cmd = NL80211_CMD_DISCONNECT,
		.doit = nl80211_disconnect,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9775
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9776
				  NL80211_FLAG_NEED_RTNL,
S
Samuel Ortiz 已提交
9777
	},
9778 9779 9780 9781 9782
	{
		.cmd = NL80211_CMD_SET_WIPHY_NETNS,
		.doit = nl80211_wiphy_netns,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9783 9784
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
9785
	},
9786 9787 9788 9789 9790
	{
		.cmd = NL80211_CMD_GET_SURVEY,
		.policy = nl80211_policy,
		.dumpit = nl80211_dump_survey,
	},
S
Samuel Ortiz 已提交
9791 9792 9793 9794 9795
	{
		.cmd = NL80211_CMD_SET_PMKSA,
		.doit = nl80211_setdel_pmksa,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9796
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9797
				  NL80211_FLAG_NEED_RTNL,
S
Samuel Ortiz 已提交
9798 9799 9800 9801 9802 9803
	},
	{
		.cmd = NL80211_CMD_DEL_PMKSA,
		.doit = nl80211_setdel_pmksa,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9804
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9805
				  NL80211_FLAG_NEED_RTNL,
S
Samuel Ortiz 已提交
9806 9807 9808 9809 9810 9811
	},
	{
		.cmd = NL80211_CMD_FLUSH_PMKSA,
		.doit = nl80211_flush_pmksa,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9812
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9813
				  NL80211_FLAG_NEED_RTNL,
S
Samuel Ortiz 已提交
9814
	},
9815 9816 9817 9818 9819
	{
		.cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
		.doit = nl80211_remain_on_channel,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9820
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
9821
				  NL80211_FLAG_NEED_RTNL,
9822 9823 9824 9825 9826 9827
	},
	{
		.cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
		.doit = nl80211_cancel_remain_on_channel,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9828
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
9829
				  NL80211_FLAG_NEED_RTNL,
9830
	},
9831 9832 9833 9834 9835
	{
		.cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
		.doit = nl80211_set_tx_bitrate_mask,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9836 9837
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
9838
	},
9839
	{
9840 9841
		.cmd = NL80211_CMD_REGISTER_FRAME,
		.doit = nl80211_register_mgmt,
9842 9843
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9844
		.internal_flags = NL80211_FLAG_NEED_WDEV |
9845
				  NL80211_FLAG_NEED_RTNL,
9846 9847
	},
	{
9848 9849
		.cmd = NL80211_CMD_FRAME,
		.doit = nl80211_tx_mgmt,
9850
		.policy = nl80211_policy,
9851
		.flags = GENL_ADMIN_PERM,
9852
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
9853 9854 9855 9856 9857 9858
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
		.doit = nl80211_tx_mgmt_cancel_wait,
		.policy = nl80211_policy,
9859
		.flags = GENL_ADMIN_PERM,
9860
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
9861
				  NL80211_FLAG_NEED_RTNL,
9862
	},
K
Kalle Valo 已提交
9863 9864 9865 9866 9867
	{
		.cmd = NL80211_CMD_SET_POWER_SAVE,
		.doit = nl80211_set_power_save,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9868 9869
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
K
Kalle Valo 已提交
9870 9871 9872 9873 9874 9875
	},
	{
		.cmd = NL80211_CMD_GET_POWER_SAVE,
		.doit = nl80211_get_power_save,
		.policy = nl80211_policy,
		/* can be retrieved by unprivileged users */
9876 9877
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
K
Kalle Valo 已提交
9878
	},
9879 9880 9881 9882 9883
	{
		.cmd = NL80211_CMD_SET_CQM,
		.doit = nl80211_set_cqm,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9884 9885
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
9886
	},
9887 9888 9889 9890 9891
	{
		.cmd = NL80211_CMD_SET_CHANNEL,
		.doit = nl80211_set_channel,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9892 9893
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
9894
	},
9895 9896 9897 9898 9899
	{
		.cmd = NL80211_CMD_SET_WDS_PEER,
		.doit = nl80211_set_wds_peer,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9900 9901
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
9902
	},
9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918
	{
		.cmd = NL80211_CMD_JOIN_MESH,
		.doit = nl80211_join_mesh,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_LEAVE_MESH,
		.doit = nl80211_leave_mesh,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
9919
#ifdef CONFIG_PM
J
Johannes Berg 已提交
9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935
	{
		.cmd = NL80211_CMD_GET_WOWLAN,
		.doit = nl80211_get_wowlan,
		.policy = nl80211_policy,
		/* can be retrieved by unprivileged users */
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_SET_WOWLAN,
		.doit = nl80211_set_wowlan,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
	},
9936
#endif
9937 9938 9939 9940 9941 9942 9943 9944
	{
		.cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
		.doit = nl80211_set_rekey_data,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960
	{
		.cmd = NL80211_CMD_TDLS_MGMT,
		.doit = nl80211_tdls_mgmt,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_TDLS_OPER,
		.doit = nl80211_tdls_oper,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
9961 9962 9963 9964 9965 9966 9967 9968
	{
		.cmd = NL80211_CMD_UNEXPECTED_FRAME,
		.doit = nl80211_register_unexpected_frame,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
	},
J
Johannes Berg 已提交
9969 9970 9971 9972 9973
	{
		.cmd = NL80211_CMD_PROBE_CLIENT,
		.doit = nl80211_probe_client,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
9974
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
J
Johannes Berg 已提交
9975 9976
				  NL80211_FLAG_NEED_RTNL,
	},
9977 9978 9979 9980 9981 9982 9983 9984
	{
		.cmd = NL80211_CMD_REGISTER_BEACONS,
		.doit = nl80211_register_beacons,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
	},
9985 9986 9987 9988 9989 9990 9991 9992
	{
		.cmd = NL80211_CMD_SET_NOACK_MAP,
		.doit = nl80211_set_noack_map,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
	},
9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008
	{
		.cmd = NL80211_CMD_START_P2P_DEVICE,
		.doit = nl80211_start_p2p_device,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WDEV |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_STOP_P2P_DEVICE,
		.doit = nl80211_stop_p2p_device,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
10009 10010 10011
	{
		.cmd = NL80211_CMD_SET_MCAST_RATE,
		.doit = nl80211_set_mcast_rate,
10012 10013 10014 10015 10016 10017 10018 10019
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_SET_MAC_ACL,
		.doit = nl80211_set_mac_acl,
10020 10021 10022 10023 10024
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
	},
10025 10026 10027 10028 10029 10030 10031 10032
	{
		.cmd = NL80211_CMD_RADAR_DETECT,
		.doit = nl80211_start_radar_detection,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
10033 10034 10035 10036 10037
	{
		.cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
		.doit = nl80211_get_protocol_features,
		.policy = nl80211_policy,
	},
10038 10039 10040 10041 10042 10043 10044 10045
	{
		.cmd = NL80211_CMD_UPDATE_FT_IES,
		.doit = nl80211_update_ft_ies,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060
	{
		.cmd = NL80211_CMD_CRIT_PROTOCOL_START,
		.doit = nl80211_crit_protocol_start,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
		.doit = nl80211_crit_protocol_stop,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075
	},
	{
		.cmd = NL80211_CMD_GET_COALESCE,
		.doit = nl80211_get_coalesce,
		.policy = nl80211_policy,
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_SET_COALESCE,
		.doit = nl80211_set_coalesce,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
10076 10077 10078 10079 10080 10081 10082 10083 10084
	},
	{
		.cmd = NL80211_CMD_CHANNEL_SWITCH,
		.doit = nl80211_channel_switch,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
J
Johannes Berg 已提交
10085 10086 10087 10088 10089 10090 10091 10092
	{
		.cmd = NL80211_CMD_VENDOR,
		.doit = nl80211_vendor_cmd,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
	},
10093 10094 10095 10096 10097 10098 10099 10100
	{
		.cmd = NL80211_CMD_SET_QOS_MAP,
		.doit = nl80211_set_qos_map,
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
10101
};
10102

10103 10104
/* notification functions */

10105 10106
void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
			  enum nl80211_commands cmd)
10107 10108
{
	struct sk_buff *msg;
10109
	struct nl80211_dump_wiphy_state state = {};
10110

10111 10112 10113
	WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
		cmd != NL80211_CMD_DEL_WIPHY);

10114
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10115 10116 10117
	if (!msg)
		return;

10118
	if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
10119 10120 10121 10122
		nlmsg_free(msg);
		return;
	}

10123
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10124
				NL80211_MCGRP_CONFIG, GFP_KERNEL);
10125 10126
}

10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139
static int nl80211_add_scan_req(struct sk_buff *msg,
				struct cfg80211_registered_device *rdev)
{
	struct cfg80211_scan_request *req = rdev->scan_req;
	struct nlattr *nest;
	int i;

	if (WARN_ON(!req))
		return 0;

	nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
	if (!nest)
		goto nla_put_failure;
10140 10141 10142 10143
	for (i = 0; i < req->n_ssids; i++) {
		if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
			goto nla_put_failure;
	}
10144 10145 10146 10147 10148
	nla_nest_end(msg, nest);

	nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
	if (!nest)
		goto nla_put_failure;
10149 10150 10151 10152
	for (i = 0; i < req->n_channels; i++) {
		if (nla_put_u32(msg, i, req->channels[i]->center_freq))
			goto nla_put_failure;
	}
10153 10154
	nla_nest_end(msg, nest);

10155 10156 10157
	if (req->ie &&
	    nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
		goto nla_put_failure;
10158

10159 10160 10161
	if (req->flags &&
	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
		goto nla_put_failure;
10162

10163 10164 10165 10166 10167
	return 0;
 nla_put_failure:
	return -ENOBUFS;
}

10168 10169
static int nl80211_send_scan_msg(struct sk_buff *msg,
				 struct cfg80211_registered_device *rdev,
J
Johannes Berg 已提交
10170
				 struct wireless_dev *wdev,
10171
				 u32 portid, u32 seq, int flags,
10172
				 u32 cmd)
10173 10174 10175
{
	void *hdr;

10176
	hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
10177 10178 10179
	if (!hdr)
		return -1;

10180
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
J
Johannes Berg 已提交
10181 10182 10183
	    (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
					 wdev->netdev->ifindex)) ||
	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
10184
		goto nla_put_failure;
10185

10186 10187
	/* ignore errors and send incomplete event anyway */
	nl80211_add_scan_req(msg, rdev);
10188 10189 10190 10191 10192 10193 10194 10195

	return genlmsg_end(msg, hdr);

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
}

10196 10197 10198 10199
static int
nl80211_send_sched_scan_msg(struct sk_buff *msg,
			    struct cfg80211_registered_device *rdev,
			    struct net_device *netdev,
10200
			    u32 portid, u32 seq, int flags, u32 cmd)
10201 10202 10203
{
	void *hdr;

10204
	hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
10205 10206 10207
	if (!hdr)
		return -1;

10208 10209 10210
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
		goto nla_put_failure;
10211 10212 10213 10214 10215 10216 10217 10218

	return genlmsg_end(msg, hdr);

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
}

10219
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
J
Johannes Berg 已提交
10220
			     struct wireless_dev *wdev)
10221 10222 10223
{
	struct sk_buff *msg;

10224
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10225 10226 10227
	if (!msg)
		return;

J
Johannes Berg 已提交
10228
	if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
10229 10230 10231 10232 10233
				  NL80211_CMD_TRIGGER_SCAN) < 0) {
		nlmsg_free(msg);
		return;
	}

10234
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10235
				NL80211_MCGRP_SCAN, GFP_KERNEL);
10236 10237
}

10238 10239
struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
				       struct wireless_dev *wdev, bool aborted)
10240 10241 10242
{
	struct sk_buff *msg;

10243
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10244
	if (!msg)
10245
		return NULL;
10246

J
Johannes Berg 已提交
10247
	if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
10248 10249
				  aborted ? NL80211_CMD_SCAN_ABORTED :
					    NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
10250
		nlmsg_free(msg);
10251
		return NULL;
10252 10253
	}

10254
	return msg;
10255 10256
}

10257 10258
void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
			      struct sk_buff *msg)
10259 10260 10261 10262
{
	if (!msg)
		return;

10263
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10264
				NL80211_MCGRP_SCAN, GFP_KERNEL);
10265 10266
}

10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
				     struct net_device *netdev)
{
	struct sk_buff *msg;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return;

	if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
					NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
		nlmsg_free(msg);
		return;
	}

10282
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10283
				NL80211_MCGRP_SCAN, GFP_KERNEL);
10284 10285 10286 10287 10288 10289 10290
}

void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
			     struct net_device *netdev, u32 cmd)
{
	struct sk_buff *msg;

10291
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10292 10293 10294 10295 10296 10297 10298 10299
	if (!msg)
		return;

	if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
		nlmsg_free(msg);
		return;
	}

10300
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10301
				NL80211_MCGRP_SCAN, GFP_KERNEL);
10302 10303
}

10304 10305 10306 10307 10308 10309 10310 10311 10312
/*
 * This can happen on global regulatory changes or device specific settings
 * based on custom world regulatory domains.
 */
void nl80211_send_reg_change_event(struct regulatory_request *request)
{
	struct sk_buff *msg;
	void *hdr;

10313
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10314 10315 10316 10317 10318 10319 10320 10321 10322 10323
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

	/* Userspace can always count this one always being set */
10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347
	if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
		goto nla_put_failure;

	if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
		if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
			       NL80211_REGDOM_TYPE_WORLD))
			goto nla_put_failure;
	} else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
		if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
			       NL80211_REGDOM_TYPE_CUSTOM_WORLD))
			goto nla_put_failure;
	} else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
		   request->intersect) {
		if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
			       NL80211_REGDOM_TYPE_INTERSECTION))
			goto nla_put_failure;
	} else {
		if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
			       NL80211_REGDOM_TYPE_COUNTRY) ||
		    nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
				   request->alpha2))
			goto nla_put_failure;
	}

J
Johannes Berg 已提交
10348
	if (request->wiphy_idx != WIPHY_IDX_INVALID &&
10349 10350
	    nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
		goto nla_put_failure;
10351

J
Johannes Berg 已提交
10352
	genlmsg_end(msg, hdr);
10353

10354
	rcu_read_lock();
10355
	genlmsg_multicast_allns(&nl80211_fam, msg, 0,
10356
				NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
10357
	rcu_read_unlock();
10358 10359 10360 10361 10362 10363 10364 10365

	return;

nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

10366 10367 10368
static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
				    struct net_device *netdev,
				    const u8 *buf, size_t len,
10369
				    enum nl80211_commands cmd, gfp_t gfp)
10370 10371 10372 10373
{
	struct sk_buff *msg;
	void *hdr;

10374
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
10375 10376 10377 10378 10379 10380 10381 10382 10383
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10384 10385 10386 10387
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_FRAME, len, buf))
		goto nla_put_failure;
10388

J
Johannes Berg 已提交
10389
	genlmsg_end(msg, hdr);
10390

10391
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10392
				NL80211_MCGRP_MLME, gfp);
10393 10394 10395 10396 10397 10398 10399 10400
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
10401 10402
			  struct net_device *netdev, const u8 *buf,
			  size_t len, gfp_t gfp)
10403 10404
{
	nl80211_send_mlme_event(rdev, netdev, buf, len,
10405
				NL80211_CMD_AUTHENTICATE, gfp);
10406 10407 10408 10409
}

void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
			   struct net_device *netdev, const u8 *buf,
10410
			   size_t len, gfp_t gfp)
10411
{
10412 10413
	nl80211_send_mlme_event(rdev, netdev, buf, len,
				NL80211_CMD_ASSOCIATE, gfp);
10414 10415
}

10416
void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
10417 10418
			 struct net_device *netdev, const u8 *buf,
			 size_t len, gfp_t gfp)
10419 10420
{
	nl80211_send_mlme_event(rdev, netdev, buf, len,
10421
				NL80211_CMD_DEAUTHENTICATE, gfp);
10422 10423
}

10424 10425
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
			   struct net_device *netdev, const u8 *buf,
10426
			   size_t len, gfp_t gfp)
10427 10428
{
	nl80211_send_mlme_event(rdev, netdev, buf, len,
10429
				NL80211_CMD_DISASSOCIATE, gfp);
10430 10431
}

10432 10433
void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
				  size_t len)
10434
{
10435 10436
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
10437
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
10438 10439
	const struct ieee80211_mgmt *mgmt = (void *)buf;
	u32 cmd;
10440

10441 10442
	if (WARN_ON(len < 2))
		return;
10443

10444 10445 10446 10447
	if (ieee80211_is_deauth(mgmt->frame_control))
		cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
	else
		cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
10448

10449 10450
	trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
	nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC);
10451
}
10452
EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
10453

10454 10455
static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
				      struct net_device *netdev, int cmd,
10456
				      const u8 *addr, gfp_t gfp)
10457 10458 10459 10460
{
	struct sk_buff *msg;
	void *hdr;

10461
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
10462 10463 10464 10465 10466 10467 10468 10469 10470
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10471 10472 10473 10474 10475
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
		goto nla_put_failure;
10476

J
Johannes Berg 已提交
10477
	genlmsg_end(msg, hdr);
10478

10479
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10480
				NL80211_MCGRP_MLME, gfp);
10481 10482 10483 10484 10485 10486 10487 10488
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
10489 10490
			       struct net_device *netdev, const u8 *addr,
			       gfp_t gfp)
10491 10492
{
	nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
10493
				  addr, gfp);
10494 10495 10496
}

void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
10497 10498
				struct net_device *netdev, const u8 *addr,
				gfp_t gfp)
10499
{
10500 10501
	nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
				  addr, gfp);
10502 10503
}

S
Samuel Ortiz 已提交
10504 10505 10506 10507 10508 10509 10510 10511 10512
void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
				 struct net_device *netdev, const u8 *bssid,
				 const u8 *req_ie, size_t req_ie_len,
				 const u8 *resp_ie, size_t resp_ie_len,
				 u16 status, gfp_t gfp)
{
	struct sk_buff *msg;
	void *hdr;

10513
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
S
Samuel Ortiz 已提交
10514 10515 10516 10517 10518 10519 10520 10521 10522
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10523 10524 10525 10526 10527 10528 10529 10530 10531
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
	    nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status) ||
	    (req_ie &&
	     nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
	    (resp_ie &&
	     nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
		goto nla_put_failure;
S
Samuel Ortiz 已提交
10532

J
Johannes Berg 已提交
10533
	genlmsg_end(msg, hdr);
S
Samuel Ortiz 已提交
10534

10535
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10536
				NL80211_MCGRP_MLME, gfp);
S
Samuel Ortiz 已提交
10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);

}

void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
			 struct net_device *netdev, const u8 *bssid,
			 const u8 *req_ie, size_t req_ie_len,
			 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
{
	struct sk_buff *msg;
	void *hdr;

10553
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
S
Samuel Ortiz 已提交
10554 10555 10556 10557 10558 10559 10560 10561 10562
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10563 10564 10565 10566 10567 10568 10569 10570
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
	    (req_ie &&
	     nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
	    (resp_ie &&
	     nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
		goto nla_put_failure;
S
Samuel Ortiz 已提交
10571

J
Johannes Berg 已提交
10572
	genlmsg_end(msg, hdr);
S
Samuel Ortiz 已提交
10573

10574
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10575
				NL80211_MCGRP_MLME, gfp);
S
Samuel Ortiz 已提交
10576 10577 10578 10579 10580 10581 10582 10583 10584 10585
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);

}

void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
			       struct net_device *netdev, u16 reason,
J
Johannes Berg 已提交
10586
			       const u8 *ie, size_t ie_len, bool from_ap)
S
Samuel Ortiz 已提交
10587 10588 10589 10590
{
	struct sk_buff *msg;
	void *hdr;

10591
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
S
Samuel Ortiz 已提交
10592 10593 10594 10595 10596 10597 10598 10599 10600
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10601 10602 10603 10604 10605 10606 10607 10608
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    (from_ap && reason &&
	     nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
	    (from_ap &&
	     nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
	    (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
		goto nla_put_failure;
S
Samuel Ortiz 已提交
10609

J
Johannes Berg 已提交
10610
	genlmsg_end(msg, hdr);
S
Samuel Ortiz 已提交
10611

10612
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10613
				NL80211_MCGRP_MLME, GFP_KERNEL);
S
Samuel Ortiz 已提交
10614 10615 10616 10617 10618 10619 10620 10621
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);

}

J
Johannes Berg 已提交
10622 10623 10624 10625 10626 10627 10628
void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
			     struct net_device *netdev, const u8 *bssid,
			     gfp_t gfp)
{
	struct sk_buff *msg;
	void *hdr;

10629
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
J
Johannes Berg 已提交
10630 10631 10632 10633 10634 10635 10636 10637 10638
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10639 10640 10641 10642
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
		goto nla_put_failure;
J
Johannes Berg 已提交
10643

J
Johannes Berg 已提交
10644
	genlmsg_end(msg, hdr);
J
Johannes Berg 已提交
10645

10646
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10647
				NL80211_MCGRP_MLME, gfp);
J
Johannes Berg 已提交
10648 10649 10650 10651 10652 10653 10654
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

10655 10656
void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
					const u8* ie, u8 ie_len, gfp_t gfp)
10657
{
10658
	struct wireless_dev *wdev = dev->ieee80211_ptr;
10659
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
10660 10661 10662
	struct sk_buff *msg;
	void *hdr;

10663 10664 10665 10666 10667
	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
		return;

	trace_cfg80211_notify_new_peer_candidate(dev, addr);

10668 10669 10670 10671 10672 10673 10674 10675 10676 10677
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10678
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
10679 10680
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
10681 10682 10683
	    (ie_len && ie &&
	     nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
		goto nla_put_failure;
10684

J
Johannes Berg 已提交
10685
	genlmsg_end(msg, hdr);
10686

10687
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10688
				NL80211_MCGRP_MLME, gfp);
10689 10690 10691 10692 10693 10694
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
10695
EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
10696

10697 10698 10699
void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
				 struct net_device *netdev, const u8 *addr,
				 enum nl80211_key_type key_type, int key_id,
10700
				 const u8 *tsc, gfp_t gfp)
10701 10702 10703 10704
{
	struct sk_buff *msg;
	void *hdr;

10705
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
10706 10707 10708 10709 10710 10711 10712 10713 10714
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10715 10716 10717 10718 10719 10720 10721 10722
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
	    nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
	    (key_id != -1 &&
	     nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
	    (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
		goto nla_put_failure;
10723

J
Johannes Berg 已提交
10724
	genlmsg_end(msg, hdr);
10725

10726
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10727
				NL80211_MCGRP_MLME, gfp);
10728 10729 10730 10731 10732 10733 10734
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

10735 10736 10737 10738 10739 10740 10741 10742
void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
				    struct ieee80211_channel *channel_before,
				    struct ieee80211_channel *channel_after)
{
	struct sk_buff *msg;
	void *hdr;
	struct nlattr *nl_freq;

10743
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

	/*
	 * Since we are applying the beacon hint to a wiphy we know its
	 * wiphy_idx is valid
	 */
10757 10758
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
		goto nla_put_failure;
10759 10760 10761 10762 10763

	/* Before */
	nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
	if (!nl_freq)
		goto nla_put_failure;
10764
	if (nl80211_msg_put_channel(msg, channel_before, false))
10765 10766 10767 10768 10769 10770 10771
		goto nla_put_failure;
	nla_nest_end(msg, nl_freq);

	/* After */
	nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
	if (!nl_freq)
		goto nla_put_failure;
10772
	if (nl80211_msg_put_channel(msg, channel_after, false))
10773 10774 10775
		goto nla_put_failure;
	nla_nest_end(msg, nl_freq);

J
Johannes Berg 已提交
10776
	genlmsg_end(msg, hdr);
10777

10778
	rcu_read_lock();
10779
	genlmsg_multicast_allns(&nl80211_fam, msg, 0,
10780
				NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
10781
	rcu_read_unlock();
10782 10783 10784 10785 10786 10787 10788 10789

	return;

nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

10790 10791
static void nl80211_send_remain_on_chan_event(
	int cmd, struct cfg80211_registered_device *rdev,
10792
	struct wireless_dev *wdev, u64 cookie,
10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808
	struct ieee80211_channel *chan,
	unsigned int duration, gfp_t gfp)
{
	struct sk_buff *msg;
	void *hdr;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10809
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
10810 10811
	    (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
					 wdev->netdev->ifindex)) ||
10812
	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
10813
	    nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
10814 10815
	    nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
			NL80211_CHAN_NO_HT) ||
10816 10817
	    nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
		goto nla_put_failure;
10818

10819 10820 10821
	if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
	    nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
		goto nla_put_failure;
10822

J
Johannes Berg 已提交
10823
	genlmsg_end(msg, hdr);
10824

10825
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10826
				NL80211_MCGRP_MLME, gfp);
10827 10828 10829 10830 10831 10832 10833
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

10834 10835 10836
void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
			       struct ieee80211_channel *chan,
			       unsigned int duration, gfp_t gfp)
10837
{
10838
	struct wiphy *wiphy = wdev->wiphy;
10839
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
10840 10841

	trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
10842
	nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
10843
					  rdev, wdev, cookie, chan,
10844
					  duration, gfp);
10845
}
10846
EXPORT_SYMBOL(cfg80211_ready_on_channel);
10847

10848 10849 10850
void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
					struct ieee80211_channel *chan,
					gfp_t gfp)
10851
{
10852
	struct wiphy *wiphy = wdev->wiphy;
10853
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
10854 10855

	trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
10856
	nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
10857
					  rdev, wdev, cookie, chan, 0, gfp);
10858
}
10859
EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
10860

10861 10862
void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
		      struct station_info *sinfo, gfp_t gfp)
10863
{
10864
	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
10865
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
10866 10867
	struct sk_buff *msg;

10868 10869
	trace_cfg80211_new_sta(dev, mac_addr, sinfo);

10870
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
10871 10872 10873
	if (!msg)
		return;

10874 10875
	if (nl80211_send_station(msg, 0, 0, 0,
				 rdev, dev, mac_addr, sinfo) < 0) {
10876 10877 10878 10879
		nlmsg_free(msg);
		return;
	}

10880
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10881
				NL80211_MCGRP_MLME, gfp);
10882
}
10883
EXPORT_SYMBOL(cfg80211_new_sta);
10884

10885
void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
10886
{
10887
	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
10888
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
10889 10890 10891
	struct sk_buff *msg;
	void *hdr;

10892 10893
	trace_cfg80211_del_sta(dev, mac_addr);

10894
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
10895 10896 10897 10898 10899 10900 10901 10902 10903
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

10904 10905 10906
	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
		goto nla_put_failure;
10907

J
Johannes Berg 已提交
10908
	genlmsg_end(msg, hdr);
10909

10910
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10911
				NL80211_MCGRP_MLME, gfp);
10912 10913 10914 10915 10916 10917
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
10918
EXPORT_SYMBOL(cfg80211_del_sta);
10919

10920 10921 10922
void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
			  enum nl80211_connect_failed_reason reason,
			  gfp_t gfp)
10923
{
10924
	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
10925
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945
	struct sk_buff *msg;
	void *hdr;

	msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
	    nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
		goto nla_put_failure;

	genlmsg_end(msg, hdr);

10946
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
10947
				NL80211_MCGRP_MLME, gfp);
10948 10949 10950 10951 10952 10953
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
10954
EXPORT_SYMBOL(cfg80211_conn_failed);
10955

10956 10957
static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
				       const u8 *addr, gfp_t gfp)
10958 10959
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
10960
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
10961 10962
	struct sk_buff *msg;
	void *hdr;
10963
	u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
10964

10965
	if (!nlportid)
10966 10967 10968 10969 10970 10971
		return false;

	msg = nlmsg_new(100, gfp);
	if (!msg)
		return true;

10972
	hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
10973 10974 10975 10976 10977
	if (!hdr) {
		nlmsg_free(msg);
		return true;
	}

10978 10979 10980 10981
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
		goto nla_put_failure;
10982

10983
	genlmsg_end(msg, hdr);
10984
	genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
10985 10986 10987 10988 10989 10990 10991 10992
	return true;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
	return true;
}

10993 10994
bool cfg80211_rx_spurious_frame(struct net_device *dev,
				const u8 *addr, gfp_t gfp)
10995
{
10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	bool ret;

	trace_cfg80211_rx_spurious_frame(dev, addr);

	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
		    wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
		trace_cfg80211_return_bool(false);
		return false;
	}
	ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
					 addr, gfp);
	trace_cfg80211_return_bool(ret);
	return ret;
11010
}
11011
EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
11012

11013 11014
bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
					const u8 *addr, gfp_t gfp)
11015
{
11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	bool ret;

	trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);

	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
		    wdev->iftype != NL80211_IFTYPE_P2P_GO &&
		    wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
		trace_cfg80211_return_bool(false);
		return false;
	}
	ret = __nl80211_unexpected_frame(dev,
					 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
					 addr, gfp);
	trace_cfg80211_return_bool(ret);
	return ret;
11032
}
11033
EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
11034

11035
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
11036
		      struct wireless_dev *wdev, u32 nlportid,
11037
		      int freq, int sig_dbm,
11038
		      const u8 *buf, size_t len, u32 flags, gfp_t gfp)
11039
{
11040
	struct net_device *netdev = wdev->netdev;
11041 11042 11043 11044 11045 11046 11047
	struct sk_buff *msg;
	void *hdr;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
	if (!msg)
		return -ENOMEM;

11048
	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
11049 11050 11051 11052 11053
	if (!hdr) {
		nlmsg_free(msg);
		return -ENOMEM;
	}

11054
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11055 11056
	    (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
					netdev->ifindex)) ||
11057
	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
11058 11059 11060
	    nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
	    (sig_dbm &&
	     nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
11061 11062 11063
	    nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
	    (flags &&
	     nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
11064
		goto nla_put_failure;
11065

J
Johannes Berg 已提交
11066
	genlmsg_end(msg, hdr);
11067

11068
	return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
11069 11070 11071 11072 11073 11074 11075

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
	return -ENOBUFS;
}

11076 11077
void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
			     const u8 *buf, size_t len, bool ack, gfp_t gfp)
11078
{
11079
	struct wiphy *wiphy = wdev->wiphy;
11080
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11081
	struct net_device *netdev = wdev->netdev;
11082 11083 11084
	struct sk_buff *msg;
	void *hdr;

11085 11086
	trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);

11087 11088 11089 11090
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
	if (!msg)
		return;

11091
	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
11092 11093 11094 11095 11096
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

11097
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11098 11099
	    (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
				   netdev->ifindex)) ||
11100
	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
11101 11102 11103 11104
	    nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
	    nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) ||
	    (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
		goto nla_put_failure;
11105

J
Johannes Berg 已提交
11106
	genlmsg_end(msg, hdr);
11107

11108
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11109
				NL80211_MCGRP_MLME, gfp);
11110 11111 11112 11113 11114 11115
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
11116
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
11117

11118 11119 11120
void cfg80211_cqm_rssi_notify(struct net_device *dev,
			      enum nl80211_cqm_rssi_threshold_event rssi_event,
			      gfp_t gfp)
11121
{
11122 11123
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
11124
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11125 11126 11127 11128
	struct sk_buff *msg;
	struct nlattr *pinfoattr;
	void *hdr;

11129 11130
	trace_cfg80211_cqm_rssi_notify(dev, rssi_event);

11131
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11132 11133 11134 11135 11136 11137 11138 11139 11140
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

11141
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11142
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
11143
		goto nla_put_failure;
11144 11145 11146 11147 11148

	pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
	if (!pinfoattr)
		goto nla_put_failure;

11149 11150 11151
	if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
			rssi_event))
		goto nla_put_failure;
11152 11153 11154

	nla_nest_end(msg, pinfoattr);

J
Johannes Berg 已提交
11155
	genlmsg_end(msg, hdr);
11156

11157
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11158
				NL80211_MCGRP_MLME, gfp);
11159 11160 11161 11162 11163 11164
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
11165
EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
11166

11167 11168 11169
static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
				     struct net_device *netdev, const u8 *bssid,
				     const u8 *replay_ctr, gfp_t gfp)
11170 11171 11172 11173 11174
{
	struct sk_buff *msg;
	struct nlattr *rekey_attr;
	void *hdr;

11175
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11176 11177 11178 11179 11180 11181 11182 11183 11184
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

11185 11186 11187 11188
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
		goto nla_put_failure;
11189 11190 11191 11192 11193

	rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
	if (!rekey_attr)
		goto nla_put_failure;

11194 11195 11196
	if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
		    NL80211_REPLAY_CTR_LEN, replay_ctr))
		goto nla_put_failure;
11197 11198 11199

	nla_nest_end(msg, rekey_attr);

J
Johannes Berg 已提交
11200
	genlmsg_end(msg, hdr);
11201

11202
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11203
				NL80211_MCGRP_MLME, gfp);
11204 11205 11206 11207 11208 11209 11210
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

11211 11212 11213 11214 11215
void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
			       const u8 *replay_ctr, gfp_t gfp)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
11216
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11217 11218 11219 11220 11221 11222 11223 11224 11225 11226

	trace_cfg80211_gtk_rekey_notify(dev, bssid);
	nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
}
EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);

static void
nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
			       struct net_device *netdev, int index,
			       const u8 *bssid, bool preauth, gfp_t gfp)
11227 11228 11229 11230 11231
{
	struct sk_buff *msg;
	struct nlattr *attr;
	void *hdr;

11232
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11233 11234 11235 11236 11237 11238 11239 11240 11241
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

11242 11243 11244
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
		goto nla_put_failure;
11245 11246 11247 11248 11249

	attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
	if (!attr)
		goto nla_put_failure;

11250 11251 11252 11253 11254
	if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
	    nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
	    (preauth &&
	     nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
		goto nla_put_failure;
11255 11256 11257

	nla_nest_end(msg, attr);

J
Johannes Berg 已提交
11258
	genlmsg_end(msg, hdr);
11259

11260
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11261
				NL80211_MCGRP_MLME, gfp);
11262 11263 11264 11265 11266 11267 11268
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

11269 11270 11271 11272 11273
void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
				     const u8 *bssid, bool preauth, gfp_t gfp)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
11274
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11275 11276 11277 11278 11279 11280 11281 11282 11283 11284

	trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
	nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
}
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);

static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
				     struct net_device *netdev,
				     struct cfg80211_chan_def *chandef,
				     gfp_t gfp)
11285 11286 11287 11288
{
	struct sk_buff *msg;
	void *hdr;

11289
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11290 11291 11292 11293 11294 11295 11296 11297 11298
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CH_SWITCH_NOTIFY);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

11299 11300 11301 11302
	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
		goto nla_put_failure;

	if (nl80211_send_chandef(msg, chandef))
11303
		goto nla_put_failure;
11304 11305 11306

	genlmsg_end(msg, hdr);

11307
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11308
				NL80211_MCGRP_MLME, gfp);
11309 11310 11311 11312 11313 11314 11315
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

11316 11317
void cfg80211_ch_switch_notify(struct net_device *dev,
			       struct cfg80211_chan_def *chandef)
11318
{
11319 11320
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
11321
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11322

11323
	ASSERT_WDEV_LOCK(wdev);
11324

11325
	trace_cfg80211_ch_switch_notify(dev, chandef);
11326 11327

	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
11328
		    wdev->iftype != NL80211_IFTYPE_P2P_GO &&
11329 11330
		    wdev->iftype != NL80211_IFTYPE_ADHOC &&
		    wdev->iftype != NL80211_IFTYPE_MESH_POINT))
11331
		return;
11332

11333
	wdev->chandef = *chandef;
11334
	wdev->preset_chandef = *chandef;
11335 11336 11337 11338 11339 11340 11341 11342 11343 11344
	nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
}
EXPORT_SYMBOL(cfg80211_ch_switch_notify);

void cfg80211_cqm_txe_notify(struct net_device *dev,
			     const u8 *peer, u32 num_packets,
			     u32 rate, u32 intvl, gfp_t gfp)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
11345
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360
	struct sk_buff *msg;
	struct nlattr *pinfoattr;
	void *hdr;

	msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11361
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
		goto nla_put_failure;

	pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
	if (!pinfoattr)
		goto nla_put_failure;

	if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
		goto nla_put_failure;

	if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
		goto nla_put_failure;

	if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
		goto nla_put_failure;

	nla_nest_end(msg, pinfoattr);

	genlmsg_end(msg, hdr);

11382
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11383
				NL80211_MCGRP_MLME, gfp);
11384 11385 11386 11387 11388 11389
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
11390
EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
11391

11392 11393
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
11394
		     const struct cfg80211_chan_def *chandef,
11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428
		     enum nl80211_radar_event event,
		     struct net_device *netdev, gfp_t gfp)
{
	struct sk_buff *msg;
	void *hdr;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
		goto nla_put_failure;

	/* NOP and radar events don't need a netdev parameter */
	if (netdev) {
		struct wireless_dev *wdev = netdev->ieee80211_ptr;

		if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
		    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
			goto nla_put_failure;
	}

	if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
		goto nla_put_failure;

	if (nl80211_send_chandef(msg, chandef))
		goto nla_put_failure;

11429
	genlmsg_end(msg, hdr);
11430

11431
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11432
				NL80211_MCGRP_MLME, gfp);
11433 11434 11435 11436 11437 11438 11439
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}

11440 11441
void cfg80211_cqm_pktloss_notify(struct net_device *dev,
				 const u8 *peer, u32 num_packets, gfp_t gfp)
11442
{
11443 11444
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
11445
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11446 11447 11448 11449
	struct sk_buff *msg;
	struct nlattr *pinfoattr;
	void *hdr;

11450 11451
	trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);

11452
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11453 11454 11455 11456 11457 11458 11459 11460 11461
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

11462
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11463
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
11464 11465
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
		goto nla_put_failure;
11466 11467 11468 11469 11470

	pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
	if (!pinfoattr)
		goto nla_put_failure;

11471 11472
	if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
		goto nla_put_failure;
11473 11474 11475

	nla_nest_end(msg, pinfoattr);

J
Johannes Berg 已提交
11476
	genlmsg_end(msg, hdr);
11477

11478
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11479
				NL80211_MCGRP_MLME, gfp);
11480 11481 11482 11483 11484 11485
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
11486
EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
11487

J
Johannes Berg 已提交
11488 11489 11490 11491
void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
			   u64 cookie, bool acked, gfp_t gfp)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
11492
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
J
Johannes Berg 已提交
11493 11494 11495
	struct sk_buff *msg;
	void *hdr;

11496 11497
	trace_cfg80211_probe_status(dev, addr, cookie, acked);

11498
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11499

J
Johannes Berg 已提交
11500 11501 11502 11503 11504 11505 11506 11507 11508
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

11509 11510 11511 11512 11513 11514
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
	    nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) ||
	    (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
		goto nla_put_failure;
J
Johannes Berg 已提交
11515

11516
	genlmsg_end(msg, hdr);
J
Johannes Berg 已提交
11517

11518
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11519
				NL80211_MCGRP_MLME, gfp);
J
Johannes Berg 已提交
11520 11521 11522 11523 11524 11525 11526 11527
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_probe_status);

11528 11529
void cfg80211_report_obss_beacon(struct wiphy *wiphy,
				 const u8 *frame, size_t len,
11530
				 int freq, int sig_dbm)
11531
{
11532
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11533 11534
	struct sk_buff *msg;
	void *hdr;
11535
	struct cfg80211_beacon_registration *reg;
11536

11537 11538
	trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);

11539 11540 11541 11542 11543 11544 11545
	spin_lock_bh(&rdev->beacon_registrations_lock);
	list_for_each_entry(reg, &rdev->beacon_registrations, list) {
		msg = nlmsg_new(len + 100, GFP_ATOMIC);
		if (!msg) {
			spin_unlock_bh(&rdev->beacon_registrations_lock);
			return;
		}
11546

11547 11548 11549
		hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
		if (!hdr)
			goto nla_put_failure;
11550

11551 11552 11553 11554 11555 11556 11557
		if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
		    (freq &&
		     nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
		    (sig_dbm &&
		     nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
		    nla_put(msg, NL80211_ATTR_FRAME, len, frame))
			goto nla_put_failure;
11558

11559
		genlmsg_end(msg, hdr);
11560

11561 11562 11563
		genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
	}
	spin_unlock_bh(&rdev->beacon_registrations_lock);
11564 11565 11566
	return;

 nla_put_failure:
11567 11568 11569
	spin_unlock_bh(&rdev->beacon_registrations_lock);
	if (hdr)
		genlmsg_cancel(msg, hdr);
11570 11571 11572 11573
	nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_report_obss_beacon);

11574 11575 11576 11577 11578
#ifdef CONFIG_PM
void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
				   struct cfg80211_wowlan_wakeup *wakeup,
				   gfp_t gfp)
{
11579
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
11580 11581
	struct sk_buff *msg;
	void *hdr;
11582
	int size = 200;
11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608

	trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);

	if (wakeup)
		size += wakeup->packet_present_len;

	msg = nlmsg_new(size, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
	if (!hdr)
		goto free_msg;

	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
		goto free_msg;

	if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
					wdev->netdev->ifindex))
		goto free_msg;

	if (wakeup) {
		struct nlattr *reasons;

		reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
11609 11610
		if (!reasons)
			goto free_msg;
11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635

		if (wakeup->disconnect &&
		    nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
			goto free_msg;
		if (wakeup->magic_pkt &&
		    nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
			goto free_msg;
		if (wakeup->gtk_rekey_failure &&
		    nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
			goto free_msg;
		if (wakeup->eap_identity_req &&
		    nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
			goto free_msg;
		if (wakeup->four_way_handshake &&
		    nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
			goto free_msg;
		if (wakeup->rfkill_release &&
		    nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
			goto free_msg;

		if (wakeup->pattern_idx >= 0 &&
		    nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
				wakeup->pattern_idx))
			goto free_msg;

11636 11637 11638
		if (wakeup->tcp_match &&
		    nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
			goto free_msg;
11639

11640 11641 11642
		if (wakeup->tcp_connlost &&
		    nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
			goto free_msg;
11643

11644 11645 11646 11647
		if (wakeup->tcp_nomoretokens &&
		    nla_put_flag(msg,
				 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
			goto free_msg;
11648

11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671
		if (wakeup->packet) {
			u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
			u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;

			if (!wakeup->packet_80211) {
				pkt_attr =
					NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
				len_attr =
					NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
			}

			if (wakeup->packet_len &&
			    nla_put_u32(msg, len_attr, wakeup->packet_len))
				goto free_msg;

			if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
				    wakeup->packet))
				goto free_msg;
		}

		nla_nest_end(msg, reasons);
	}

11672
	genlmsg_end(msg, hdr);
11673

11674
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11675
				NL80211_MCGRP_MLME, gfp);
11676 11677 11678 11679 11680 11681 11682 11683
	return;

 free_msg:
	nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
#endif

11684 11685 11686 11687 11688
void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
				enum nl80211_tdls_operation oper,
				u16 reason_code, gfp_t gfp)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
11689
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713
	struct sk_buff *msg;
	void *hdr;

	trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
					 reason_code);

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}

	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
	    nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
	    (reason_code > 0 &&
	     nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
		goto nla_put_failure;

11714
	genlmsg_end(msg, hdr);
11715

11716
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11717
				NL80211_MCGRP_MLME, gfp);
11718 11719 11720 11721 11722 11723 11724 11725
	return;

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_tdls_oper_request);

11726 11727 11728 11729 11730 11731 11732
static int nl80211_netlink_notify(struct notifier_block * nb,
				  unsigned long state,
				  void *_notify)
{
	struct netlink_notify *notify = _notify;
	struct cfg80211_registered_device *rdev;
	struct wireless_dev *wdev;
11733
	struct cfg80211_beacon_registration *reg, *tmp;
11734 11735 11736 11737 11738 11739

	if (state != NETLINK_URELEASE)
		return NOTIFY_DONE;

	rcu_read_lock();

11740
	list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
11741 11742 11743
		bool schedule_destroy_work = false;

		list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
11744
			cfg80211_mlme_unregister_socket(wdev, notify->portid);
11745

11746 11747 11748 11749
			if (wdev->owner_nlportid == notify->portid)
				schedule_destroy_work = true;
		}

11750 11751 11752 11753 11754 11755 11756 11757 11758 11759
		spin_lock_bh(&rdev->beacon_registrations_lock);
		list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
					 list) {
			if (reg->nlportid == notify->portid) {
				list_del(&reg->list);
				kfree(reg);
				break;
			}
		}
		spin_unlock_bh(&rdev->beacon_registrations_lock);
11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772

		if (schedule_destroy_work) {
			struct cfg80211_iface_destroy *destroy;

			destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC);
			if (destroy) {
				destroy->nlportid = notify->portid;
				spin_lock(&rdev->destroy_list_lock);
				list_add(&destroy->list, &rdev->destroy_list);
				spin_unlock(&rdev->destroy_list_lock);
				schedule_work(&rdev->destroy_work);
			}
		}
11773
	}
11774 11775 11776

	rcu_read_unlock();

11777
	return NOTIFY_OK;
11778 11779 11780 11781 11782 11783
}

static struct notifier_block nl80211_netlink_notifier = {
	.notifier_call = nl80211_netlink_notify,
};

11784 11785 11786 11787
void cfg80211_ft_event(struct net_device *netdev,
		       struct cfg80211_ft_event_params *ft_event)
{
	struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
11788
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801
	struct sk_buff *msg;
	void *hdr;

	trace_cfg80211_ft_event(wiphy, netdev, ft_event);

	if (!ft_event->target_ap)
		return;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
11802 11803
	if (!hdr)
		goto out;
11804

11805 11806 11807 11808
	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
		goto out;
11809

11810 11811 11812 11813 11814 11815 11816
	if (ft_event->ies &&
	    nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
		goto out;
	if (ft_event->ric_ies &&
	    nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
		    ft_event->ric_ies))
		goto out;
11817

11818
	genlmsg_end(msg, hdr);
11819

11820
	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
11821
				NL80211_MCGRP_MLME, GFP_KERNEL);
11822 11823 11824
	return;
 out:
	nlmsg_free(msg);
11825 11826 11827
}
EXPORT_SYMBOL(cfg80211_ft_event);

11828 11829 11830 11831 11832 11833 11834
void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
{
	struct cfg80211_registered_device *rdev;
	struct sk_buff *msg;
	void *hdr;
	u32 nlportid;

11835
	rdev = wiphy_to_rdev(wdev->wiphy);
11836 11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866
	if (!rdev->crit_proto_nlportid)
		return;

	nlportid = rdev->crit_proto_nlportid;
	rdev->crit_proto_nlportid = 0;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
	if (!hdr)
		goto nla_put_failure;

	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
		goto nla_put_failure;

	genlmsg_end(msg, hdr);

	genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
	return;

 nla_put_failure:
	if (hdr)
		genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);

}
EXPORT_SYMBOL(cfg80211_crit_proto_stopped);

11867 11868 11869
void nl80211_send_ap_stopped(struct wireless_dev *wdev)
{
	struct wiphy *wiphy = wdev->wiphy;
11870
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895
	struct sk_buff *msg;
	void *hdr;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
	if (!hdr)
		goto out;

	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
		goto out;

	genlmsg_end(msg, hdr);

	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
				NL80211_MCGRP_MLME, GFP_KERNEL);
	return;
 out:
	nlmsg_free(msg);
}

11896 11897 11898 11899
/* initialisation/exit functions */

int nl80211_init(void)
{
11900
	int err;
11901

11902 11903
	err = genl_register_family_with_ops_groups(&nl80211_fam, nl80211_ops,
						   nl80211_mcgrps);
11904 11905 11906
	if (err)
		return err;

11907 11908 11909 11910
	err = netlink_register_notifier(&nl80211_netlink_notifier);
	if (err)
		goto err_out;

11911 11912 11913 11914 11915 11916 11917 11918
	return 0;
 err_out:
	genl_unregister_family(&nl80211_fam);
	return err;
}

void nl80211_exit(void)
{
11919
	netlink_unregister_notifier(&nl80211_netlink_notifier);
11920 11921
	genl_unregister_family(&nl80211_fam);
}