mlme.c 24.2 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 * cfg80211 MLME SAP interface
 *
 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
 */

#include <linux/kernel.h>
#include <linux/module.h>
9
#include <linux/etherdevice.h>
10 11
#include <linux/netdevice.h>
#include <linux/nl80211.h>
12
#include <linux/slab.h>
13
#include <linux/wireless.h>
14
#include <net/cfg80211.h>
15
#include <net/iw_handler.h>
16 17
#include "core.h"
#include "nl80211.h"
18 19
#include "rdev-ops.h"

20

21
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
22
{
J
Johannes Berg 已提交
23 24
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
25
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
J
Johannes Berg 已提交
26

27
	trace_cfg80211_send_rx_auth(dev);
J
Johannes Berg 已提交
28
	wdev_lock(wdev);
29

30 31
	nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
	cfg80211_sme_rx_auth(dev, buf, len);
J
Johannes Berg 已提交
32 33

	wdev_unlock(wdev);
34 35 36
}
EXPORT_SYMBOL(cfg80211_send_rx_auth);

37 38
void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
			    const u8 *buf, size_t len)
39
{
40 41 42
	u16 status_code;
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
43
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
44 45
	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
	u8 *ie = mgmt->u.assoc_resp.variable;
46
	int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
47

48
	trace_cfg80211_send_rx_assoc(dev, bss);
J
Johannes Berg 已提交
49
	wdev_lock(wdev);
50

51 52
	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);

53 54 55 56 57 58 59
	/*
	 * This is a bit of a hack, we don't notify userspace of
	 * a (re-)association reply if we tried to send a reassoc
	 * and got a reject -- we only try again with an assoc
	 * frame instead of reassoc.
	 */
	if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
60
	    cfg80211_sme_failed_reassoc(wdev)) {
61
		cfg80211_put_bss(wiphy, bss);
62
		goto out;
63
	}
64

65
	nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
66

67
	if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) {
68 69 70 71 72
		cfg80211_sme_failed_assoc(wdev);
		/*
		 * do not call connect_result() now because the
		 * sme will schedule work that does it later.
		 */
73
		cfg80211_put_bss(wiphy, bss);
74
		goto out;
75 76
	}

77 78 79 80 81 82 83 84 85
	if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
		/*
		 * This is for the userspace SME, the CONNECTING
		 * state will be changed to CONNECTED by
		 * __cfg80211_connect_result() below.
		 */
		wdev->sme_state = CFG80211_SME_CONNECTING;
	}

86
	/* this consumes the bss reference */
87 88
	__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
				  status_code,
89
				  status_code == WLAN_STATUS_SUCCESS, bss);
90
 out:
J
Johannes Berg 已提交
91
	wdev_unlock(wdev);
92 93 94
}
EXPORT_SYMBOL(cfg80211_send_rx_assoc);

95
void __cfg80211_send_deauth(struct net_device *dev,
J
Johannes Berg 已提交
96
				   const u8 *buf, size_t len)
97
{
98 99
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
100
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
101
	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
J
Johannes Berg 已提交
102
	const u8 *bssid = mgmt->bssid;
103
	bool was_current = false;
104

105
	trace___cfg80211_send_deauth(dev);
J
Johannes Berg 已提交
106
	ASSERT_WDEV_LOCK(wdev);
107

J
Johannes Berg 已提交
108
	if (wdev->current_bss &&
109
	    ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
J
Johannes Berg 已提交
110
		cfg80211_unhold_bss(wdev->current_bss);
111
		cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
J
Johannes Berg 已提交
112
		wdev->current_bss = NULL;
113
		was_current = true;
J
Johannes Berg 已提交
114 115
	}

116 117
	nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);

118
	if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) {
119 120 121 122 123
		u16 reason_code;
		bool from_ap;

		reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);

124
		from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
J
Johannes Berg 已提交
125
		__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
126
	} else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
J
Johannes Berg 已提交
127 128
		__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
					  WLAN_STATUS_UNSPECIFIED_FAILURE,
129
					  false, NULL);
J
Johannes Berg 已提交
130 131
	}
}
132
EXPORT_SYMBOL(__cfg80211_send_deauth);
J
Johannes Berg 已提交
133

134
void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
J
Johannes Berg 已提交
135 136 137
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;

138 139 140
	wdev_lock(wdev);
	__cfg80211_send_deauth(dev, buf, len);
	wdev_unlock(wdev);
141
}
142
EXPORT_SYMBOL(cfg80211_send_deauth);
143

144
void __cfg80211_send_disassoc(struct net_device *dev,
J
Johannes Berg 已提交
145
				     const u8 *buf, size_t len)
146
{
147 148
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
149
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
150
	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
J
Johannes Berg 已提交
151 152 153
	const u8 *bssid = mgmt->bssid;
	u16 reason_code;
	bool from_ap;
154

155
	trace___cfg80211_send_disassoc(dev);
156
	ASSERT_WDEV_LOCK(wdev);
157 158

	nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
159

160 161
	if (wdev->sme_state != CFG80211_SME_CONNECTED)
		return;
162

J
Johannes Berg 已提交
163
	if (wdev->current_bss &&
164
	    ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
165 166
		cfg80211_sme_disassoc(dev, wdev->current_bss);
		cfg80211_unhold_bss(wdev->current_bss);
167
		cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
168
		wdev->current_bss = NULL;
J
Johannes Berg 已提交
169 170
	} else
		WARN_ON(1);
171 172


J
Johannes Berg 已提交
173 174
	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);

175
	from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
J
Johannes Berg 已提交
176 177
	__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
}
178
EXPORT_SYMBOL(__cfg80211_send_disassoc);
J
Johannes Berg 已提交
179

180
void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
J
Johannes Berg 已提交
181 182 183
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;

184 185 186
	wdev_lock(wdev);
	__cfg80211_send_disassoc(dev, buf, len);
	wdev_unlock(wdev);
187
}
188
EXPORT_SYMBOL(cfg80211_send_disassoc);
189

190 191 192 193 194 195
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);

196
	trace_cfg80211_send_auth_timeout(dev, addr);
197 198 199 200 201 202 203 204
	wdev_lock(wdev);

	nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
	if (wdev->sme_state == CFG80211_SME_CONNECTING)
		__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
					  WLAN_STATUS_UNSPECIFIED_FAILURE,
					  false, NULL);

J
Johannes Berg 已提交
205
	wdev_unlock(wdev);
206 207 208
}
EXPORT_SYMBOL(cfg80211_send_auth_timeout);

209
void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
210
{
211 212
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
213
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
J
Johannes Berg 已提交
214

215
	trace_cfg80211_send_assoc_timeout(dev, addr);
J
Johannes Berg 已提交
216
	wdev_lock(wdev);
217 218

	nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
219
	if (wdev->sme_state == CFG80211_SME_CONNECTING)
J
Johannes Berg 已提交
220 221
		__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
					  WLAN_STATUS_UNSPECIFIED_FAILURE,
222
					  false, NULL);
J
Johannes Berg 已提交
223

J
Johannes Berg 已提交
224
	wdev_unlock(wdev);
225 226 227
}
EXPORT_SYMBOL(cfg80211_send_assoc_timeout);

228 229
void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
				  enum nl80211_key_type key_type, int key_id,
230
				  const u8 *tsc, gfp_t gfp)
231 232 233
{
	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
J
Johannes Berg 已提交
234
#ifdef CONFIG_CFG80211_WEXT
235
	union iwreq_data wrqu;
236
	char *buf = kmalloc(128, gfp);
237 238 239 240 241 242 243 244 245 246 247 248 249

	if (buf) {
		sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
			"keyid=%d %scast addr=%pM)", key_id,
			key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
			addr);
		memset(&wrqu, 0, sizeof(wrqu));
		wrqu.data.length = strlen(buf);
		wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
		kfree(buf);
	}
#endif

250
	trace_cfg80211_michael_mic_failure(dev, addr, key_type, key_id, tsc);
251
	nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
252 253
}
EXPORT_SYMBOL(cfg80211_michael_mic_failure);
J
Johannes Berg 已提交
254 255

/* some MLME handling for userspace SME */
J
Johannes Berg 已提交
256 257 258 259 260 261
int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
			 struct net_device *dev,
			 struct ieee80211_channel *chan,
			 enum nl80211_auth_type auth_type,
			 const u8 *bssid,
			 const u8 *ssid, int ssid_len,
J
Johannes Berg 已提交
262
			 const u8 *ie, int ie_len,
263 264
			 const u8 *key, int key_len, int key_idx,
			 const u8 *sae_data, int sae_data_len)
J
Johannes Berg 已提交
265 266
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
267 268 269 270 271 272 273 274 275 276
	struct cfg80211_auth_request req = {
		.ie = ie,
		.ie_len = ie_len,
		.sae_data = sae_data,
		.sae_data_len = sae_data_len,
		.auth_type = auth_type,
		.key = key,
		.key_len = key_len,
		.key_idx = key_idx,
	};
277
	int err;
J
Johannes Berg 已提交
278

J
Johannes Berg 已提交
279 280
	ASSERT_WDEV_LOCK(wdev);

J
Johannes Berg 已提交
281 282 283 284
	if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
		if (!key || !key_len || key_idx < 0 || key_idx > 4)
			return -EINVAL;

285
	if (wdev->current_bss &&
286
	    ether_addr_equal(bssid, wdev->current_bss->pub.bssid))
287 288
		return -EALREADY;

J
Johannes Berg 已提交
289 290 291 292 293
	req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
				   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
	if (!req.bss)
		return -ENOENT;

294 295 296 297 298
	err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
				    CHAN_MODE_SHARED);
	if (err)
		goto out;

299
	err = rdev_auth(rdev, dev, &req);
J
Johannes Berg 已提交
300

301
out:
302
	cfg80211_put_bss(&rdev->wiphy, req.bss);
J
Johannes Berg 已提交
303 304 305
	return err;
}

J
Johannes Berg 已提交
306 307 308 309
int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
		       struct net_device *dev, struct ieee80211_channel *chan,
		       enum nl80211_auth_type auth_type, const u8 *bssid,
		       const u8 *ssid, int ssid_len,
J
Johannes Berg 已提交
310
		       const u8 *ie, int ie_len,
311 312
		       const u8 *key, int key_len, int key_idx,
		       const u8 *sae_data, int sae_data_len)
J
Johannes Berg 已提交
313 314 315
{
	int err;

316
	mutex_lock(&rdev->devlist_mtx);
J
Johannes Berg 已提交
317 318
	wdev_lock(dev->ieee80211_ptr);
	err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
J
Johannes Berg 已提交
319
				   ssid, ssid_len, ie, ie_len,
320 321
				   key, key_len, key_idx,
				   sae_data, sae_data_len);
J
Johannes Berg 已提交
322
	wdev_unlock(dev->ieee80211_ptr);
323
	mutex_unlock(&rdev->devlist_mtx);
J
Johannes Berg 已提交
324 325 326 327

	return err;
}

328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
/*  Do a logical ht_capa &= ht_capa_mask.  */
void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
			       const struct ieee80211_ht_cap *ht_capa_mask)
{
	int i;
	u8 *p1, *p2;
	if (!ht_capa_mask) {
		memset(ht_capa, 0, sizeof(*ht_capa));
		return;
	}

	p1 = (u8*)(ht_capa);
	p2 = (u8*)(ht_capa_mask);
	for (i = 0; i<sizeof(*ht_capa); i++)
		p1[i] &= p2[i];
}

345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
/*  Do a logical ht_capa &= ht_capa_mask.  */
void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
				const struct ieee80211_vht_cap *vht_capa_mask)
{
	int i;
	u8 *p1, *p2;
	if (!vht_capa_mask) {
		memset(vht_capa, 0, sizeof(*vht_capa));
		return;
	}

	p1 = (u8*)(vht_capa);
	p2 = (u8*)(vht_capa_mask);
	for (i = 0; i < sizeof(*vht_capa); i++)
		p1[i] &= p2[i];
}

J
Johannes Berg 已提交
362 363 364
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
			  struct net_device *dev,
			  struct ieee80211_channel *chan,
365
			  const u8 *bssid,
J
Johannes Berg 已提交
366
			  const u8 *ssid, int ssid_len,
367
			  struct cfg80211_assoc_request *req)
J
Johannes Berg 已提交
368 369
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
370
	int err;
371
	bool was_connected = false;
J
Johannes Berg 已提交
372

J
Johannes Berg 已提交
373 374
	ASSERT_WDEV_LOCK(wdev);

375 376
	if (wdev->current_bss && req->prev_bssid &&
	    ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) {
377 378 379 380 381 382 383 384 385
		/*
		 * Trying to reassociate: Allow this to proceed and let the old
		 * association to be dropped when the new one is completed.
		 */
		if (wdev->sme_state == CFG80211_SME_CONNECTED) {
			was_connected = true;
			wdev->sme_state = CFG80211_SME_CONNECTING;
		}
	} else if (wdev->current_bss)
J
Johannes Berg 已提交
386 387
		return -EALREADY;

388
	cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
389
				  rdev->wiphy.ht_capa_mod_mask);
390
	cfg80211_oper_and_vht_capa(&req->vht_capa_mask,
391
				   rdev->wiphy.vht_capa_mod_mask);
392

393 394 395
	req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
				    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
	if (!req->bss) {
396 397
		if (was_connected)
			wdev->sme_state = CFG80211_SME_CONNECTED;
J
Johannes Berg 已提交
398
		return -ENOENT;
399
	}
J
Johannes Berg 已提交
400

401
	err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
402 403 404
	if (err)
		goto out;

405
	err = rdev_assoc(rdev, dev, req);
J
Johannes Berg 已提交
406

407
out:
408 409 410
	if (err) {
		if (was_connected)
			wdev->sme_state = CFG80211_SME_CONNECTED;
411
		cfg80211_put_bss(&rdev->wiphy, req->bss);
J
Johannes Berg 已提交
412 413 414 415 416
	}

	return err;
}

J
Johannes Berg 已提交
417 418 419
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
			struct net_device *dev,
			struct ieee80211_channel *chan,
420
			const u8 *bssid,
J
Johannes Berg 已提交
421
			const u8 *ssid, int ssid_len,
422
			struct cfg80211_assoc_request *req)
J
Johannes Berg 已提交
423 424 425 426
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

427
	mutex_lock(&rdev->devlist_mtx);
J
Johannes Berg 已提交
428
	wdev_lock(wdev);
429 430
	err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid,
				    ssid, ssid_len, req);
J
Johannes Berg 已提交
431
	wdev_unlock(wdev);
432
	mutex_unlock(&rdev->devlist_mtx);
J
Johannes Berg 已提交
433 434 435 436 437 438

	return err;
}

int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
			   struct net_device *dev, const u8 *bssid,
439 440
			   const u8 *ie, int ie_len, u16 reason,
			   bool local_state_change)
J
Johannes Berg 已提交
441 442
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
443 444 445 446 447
	struct cfg80211_deauth_request req = {
		.bssid = bssid,
		.reason_code = reason,
		.ie = ie,
		.ie_len = ie_len,
448
		.local_state_change = local_state_change,
449
	};
J
Johannes Berg 已提交
450

J
Johannes Berg 已提交
451 452
	ASSERT_WDEV_LOCK(wdev);

453 454
	if (local_state_change && (!wdev->current_bss ||
	    !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
455
		return 0;
J
Johannes Berg 已提交
456

457
	return rdev_deauth(rdev, dev, &req);
J
Johannes Berg 已提交
458 459
}

J
Johannes Berg 已提交
460 461
int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
			 struct net_device *dev, const u8 *bssid,
462 463
			 const u8 *ie, int ie_len, u16 reason,
			 bool local_state_change)
J
Johannes Berg 已提交
464 465 466 467 468
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

	wdev_lock(wdev);
469 470
	err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason,
				     local_state_change);
J
Johannes Berg 已提交
471 472 473 474 475 476 477
	wdev_unlock(wdev);

	return err;
}

static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
				    struct net_device *dev, const u8 *bssid,
478 479
				    const u8 *ie, int ie_len, u16 reason,
				    bool local_state_change)
J
Johannes Berg 已提交
480 481
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
482 483 484 485 486 487
	struct cfg80211_disassoc_request req = {
		.reason_code = reason,
		.local_state_change = local_state_change,
		.ie = ie,
		.ie_len = ie_len,
	};
J
Johannes Berg 已提交
488

J
Johannes Berg 已提交
489 490
	ASSERT_WDEV_LOCK(wdev);

491 492 493
	if (wdev->sme_state != CFG80211_SME_CONNECTED)
		return -ENOTCONN;

494
	if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state))
495 496
		return -ENOTCONN;

497
	if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
J
Johannes Berg 已提交
498 499 500 501
		req.bss = &wdev->current_bss->pub;
	else
		return -ENOTCONN;

502
	return rdev_disassoc(rdev, dev, &req);
J
Johannes Berg 已提交
503 504 505 506
}

int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
			   struct net_device *dev, const u8 *bssid,
507 508
			   const u8 *ie, int ie_len, u16 reason,
			   bool local_state_change)
J
Johannes Berg 已提交
509 510 511 512 513
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

	wdev_lock(wdev);
514 515
	err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason,
				       local_state_change);
J
Johannes Berg 已提交
516 517 518
	wdev_unlock(wdev);

	return err;
J
Johannes Berg 已提交
519 520 521 522 523 524
}

void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
			struct net_device *dev)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
525
	u8 bssid[ETH_ALEN];
526 527 528 529
	struct cfg80211_deauth_request req = {
		.reason_code = WLAN_REASON_DEAUTH_LEAVING,
		.bssid = bssid,
	};
J
Johannes Berg 已提交
530

J
Johannes Berg 已提交
531 532
	ASSERT_WDEV_LOCK(wdev);

J
Johannes Berg 已提交
533 534 535
	if (!rdev->ops->deauth)
		return;

536 537
	if (!wdev->current_bss)
		return;
J
Johannes Berg 已提交
538

539
	memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
540
	rdev_deauth(rdev, dev, &req);
541 542 543

	if (wdev->current_bss) {
		cfg80211_unhold_bss(wdev->current_bss);
544
		cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub);
545
		wdev->current_bss = NULL;
J
Johannes Berg 已提交
546 547
	}
}
548

549
struct cfg80211_mgmt_registration {
550 551
	struct list_head list;

552
	u32 nlportid;
553 554 555

	int match_len;

556 557
	__le16 frame_type;

558 559 560
	u8 match[];
};

561
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
562 563
				u16 frame_type, const u8 *match_data,
				int match_len)
564
{
565 566
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
567
	struct cfg80211_mgmt_registration *reg, *nreg;
568
	int err = 0;
569 570 571 572 573 574 575 576 577 578 579 580 581 582
	u16 mgmt_type;

	if (!wdev->wiphy->mgmt_stypes)
		return -EOPNOTSUPP;

	if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
		return -EINVAL;

	if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
		return -EINVAL;

	mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
	if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type)))
		return -EINVAL;
583 584 585 586 587

	nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
	if (!nreg)
		return -ENOMEM;

588
	spin_lock_bh(&wdev->mgmt_registrations_lock);
589

590
	list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
591 592
		int mlen = min(match_len, reg->match_len);

593 594 595
		if (frame_type != le16_to_cpu(reg->frame_type))
			continue;

596 597 598 599 600 601 602 603 604 605 606 607 608
		if (memcmp(reg->match, match_data, mlen) == 0) {
			err = -EALREADY;
			break;
		}
	}

	if (err) {
		kfree(nreg);
		goto out;
	}

	memcpy(nreg->match, match_data, match_len);
	nreg->match_len = match_len;
609
	nreg->nlportid = snd_portid;
610 611
	nreg->frame_type = cpu_to_le16(frame_type);
	list_add(&nreg->list, &wdev->mgmt_registrations);
612

613
	if (rdev->ops->mgmt_frame_register)
614
		rdev_mgmt_frame_register(rdev, wdev, frame_type, true);
615

616
 out:
617
	spin_unlock_bh(&wdev->mgmt_registrations_lock);
618

619 620 621
	return err;
}

622
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
623
{
624 625
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
626
	struct cfg80211_mgmt_registration *reg, *tmp;
627

628
	spin_lock_bh(&wdev->mgmt_registrations_lock);
629

630
	list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
631
		if (reg->nlportid != nlportid)
632 633 634 635 636
			continue;

		if (rdev->ops->mgmt_frame_register) {
			u16 frame_type = le16_to_cpu(reg->frame_type);

637 638
			rdev_mgmt_frame_register(rdev, wdev,
						 frame_type, false);
639
		}
640 641 642

		list_del(&reg->list);
		kfree(reg);
643 644
	}

645
	spin_unlock_bh(&wdev->mgmt_registrations_lock);
646

647 648 649 650 651
	if (nlportid && rdev->crit_proto_nlportid == nlportid) {
		rdev->crit_proto_nlportid = 0;
		rdev_crit_proto_stop(rdev, wdev);
	}

652 653
	if (nlportid == wdev->ap_unexpected_nlportid)
		wdev->ap_unexpected_nlportid = 0;
654 655
}

656
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
657
{
658
	struct cfg80211_mgmt_registration *reg, *tmp;
659

660
	spin_lock_bh(&wdev->mgmt_registrations_lock);
661

662
	list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
663 664 665 666
		list_del(&reg->list);
		kfree(reg);
	}

667
	spin_unlock_bh(&wdev->mgmt_registrations_lock);
668 669
}

670
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
671
			  struct wireless_dev *wdev,
672
			  struct ieee80211_channel *chan, bool offchan,
673 674
			  unsigned int wait, const u8 *buf, size_t len,
			  bool no_cck, bool dont_wait_for_ack, u64 *cookie)
675 676
{
	const struct ieee80211_mgmt *mgmt;
677 678 679 680
	u16 stype;

	if (!wdev->wiphy->mgmt_stypes)
		return -EOPNOTSUPP;
681

682
	if (!rdev->ops->mgmt_tx)
683
		return -EOPNOTSUPP;
684

685 686 687 688
	if (len < 24 + 1)
		return -EINVAL;

	mgmt = (const struct ieee80211_mgmt *) buf;
689 690

	if (!ieee80211_is_mgmt(mgmt->frame_control))
691
		return -EINVAL;
692 693 694 695 696 697 698

	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
	if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4)))
		return -EINVAL;

	if (ieee80211_is_action(mgmt->frame_control) &&
	    mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
699 700
		int err = 0;

701 702
		wdev_lock(wdev);

703 704 705 706 707 708 709 710 711
		switch (wdev->iftype) {
		case NL80211_IFTYPE_ADHOC:
		case NL80211_IFTYPE_STATION:
		case NL80211_IFTYPE_P2P_CLIENT:
			if (!wdev->current_bss) {
				err = -ENOTCONN;
				break;
			}

712 713
			if (!ether_addr_equal(wdev->current_bss->pub.bssid,
					      mgmt->bssid)) {
714 715 716 717 718 719 720 721 722 723
				err = -ENOTCONN;
				break;
			}

			/*
			 * check for IBSS DA must be done by driver as
			 * cfg80211 doesn't track the stations
			 */
			if (wdev->iftype == NL80211_IFTYPE_ADHOC)
				break;
724

725
			/* for station, check that DA is the AP */
726 727
			if (!ether_addr_equal(wdev->current_bss->pub.bssid,
					      mgmt->da)) {
728 729 730 731 732 733 734
				err = -ENOTCONN;
				break;
			}
			break;
		case NL80211_IFTYPE_AP:
		case NL80211_IFTYPE_P2P_GO:
		case NL80211_IFTYPE_AP_VLAN:
735
			if (!ether_addr_equal(mgmt->bssid, wdev_address(wdev)))
736 737
				err = -EINVAL;
			break;
738
		case NL80211_IFTYPE_MESH_POINT:
739
			if (!ether_addr_equal(mgmt->sa, mgmt->bssid)) {
740 741 742 743 744 745 746 747
				err = -EINVAL;
				break;
			}
			/*
			 * check for mesh DA must be done by driver as
			 * cfg80211 doesn't track the stations
			 */
			break;
748 749 750 751 752
		case NL80211_IFTYPE_P2P_DEVICE:
			/*
			 * fall through, P2P device only supports
			 * public action frames
			 */
753 754 755 756
		default:
			err = -EOPNOTSUPP;
			break;
		}
757
		wdev_unlock(wdev);
758 759 760

		if (err)
			return err;
761 762
	}

763
	if (!ether_addr_equal(mgmt->sa, wdev_address(wdev)))
764 765 766
		return -EINVAL;

	/* Transmit the Action frame as requested by user space */
767 768 769
	return rdev_mgmt_tx(rdev, wdev, chan, offchan,
			    wait, buf, len, no_cck, dont_wait_for_ack,
			    cookie);
770 771
}

772
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
773
		      const u8 *buf, size_t len, gfp_t gfp)
774 775 776
{
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
777 778 779 780 781 782
	struct cfg80211_mgmt_registration *reg;
	const struct ieee80211_txrx_stypes *stypes =
		&wiphy->mgmt_stypes[wdev->iftype];
	struct ieee80211_mgmt *mgmt = (void *)buf;
	const u8 *data;
	int data_len;
783
	bool result = false;
784 785 786
	__le16 ftype = mgmt->frame_control &
		cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
	u16 stype;
787

788
	trace_cfg80211_rx_mgmt(wdev, freq, sig_mbm);
789
	stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
790

791 792
	if (!(stypes->rx & BIT(stype))) {
		trace_cfg80211_return_bool(false);
793
		return false;
794
	}
795

796 797 798 799 800 801 802 803
	data = buf + ieee80211_hdrlen(mgmt->frame_control);
	data_len = len - ieee80211_hdrlen(mgmt->frame_control);

	spin_lock_bh(&wdev->mgmt_registrations_lock);

	list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
		if (reg->frame_type != ftype)
			continue;
804

805
		if (reg->match_len > data_len)
806 807
			continue;

808
		if (memcmp(reg->match, data, reg->match_len))
809 810 811 812 813
			continue;

		/* found match! */

		/* Indicate the received Action frame to user space */
814
		if (nl80211_send_mgmt(rdev, wdev, reg->nlportid,
815
				      freq, sig_mbm,
816
				      buf, len, gfp))
817 818 819 820 821 822
			continue;

		result = true;
		break;
	}

823
	spin_unlock_bh(&wdev->mgmt_registrations_lock);
824

825
	trace_cfg80211_return_bool(result);
826 827
	return result;
}
828
EXPORT_SYMBOL(cfg80211_rx_mgmt);
829

830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
void cfg80211_dfs_channels_update_work(struct work_struct *work)
{
	struct delayed_work *delayed_work;
	struct cfg80211_registered_device *rdev;
	struct cfg80211_chan_def chandef;
	struct ieee80211_supported_band *sband;
	struct ieee80211_channel *c;
	struct wiphy *wiphy;
	bool check_again = false;
	unsigned long timeout, next_time = 0;
	int bandid, i;

	delayed_work = container_of(work, struct delayed_work, work);
	rdev = container_of(delayed_work, struct cfg80211_registered_device,
			    dfs_update_channels_wk);
	wiphy = &rdev->wiphy;

	mutex_lock(&cfg80211_mutex);
	for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) {
		sband = wiphy->bands[bandid];
		if (!sband)
			continue;

		for (i = 0; i < sband->n_channels; i++) {
			c = &sband->channels[i];

			if (c->dfs_state != NL80211_DFS_UNAVAILABLE)
				continue;

			timeout = c->dfs_state_entered +
				  IEEE80211_DFS_MIN_NOP_TIME_MS;

			if (time_after_eq(jiffies, timeout)) {
				c->dfs_state = NL80211_DFS_USABLE;
				cfg80211_chandef_create(&chandef, c,
							NL80211_CHAN_NO_HT);

				nl80211_radar_notify(rdev, &chandef,
						     NL80211_RADAR_NOP_FINISHED,
						     NULL, GFP_ATOMIC);
				continue;
			}

			if (!check_again)
				next_time = timeout - jiffies;
			else
				next_time = min(next_time, timeout - jiffies);
			check_again = true;
		}
	}
	mutex_unlock(&cfg80211_mutex);

	/* reschedule if there are other channels waiting to be cleared again */
	if (check_again)
		queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
				   next_time);
}


void cfg80211_radar_event(struct wiphy *wiphy,
			  struct cfg80211_chan_def *chandef,
			  gfp_t gfp)
{
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
	unsigned long timeout;

	trace_cfg80211_radar_event(wiphy, chandef);

	/* only set the chandef supplied channel to unavailable, in
	 * case the radar is detected on only one of multiple channels
	 * spanned by the chandef.
	 */
	cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);

	timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS);
	queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
			   timeout);

	nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
}
EXPORT_SYMBOL(cfg80211_radar_event);

void cfg80211_cac_event(struct net_device *netdev,
			enum nl80211_radar_event event, gfp_t gfp)
{
	struct wireless_dev *wdev = netdev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
	struct cfg80211_chan_def chandef;
	unsigned long timeout;

	trace_cfg80211_cac_event(netdev, event);

	if (WARN_ON(!wdev->cac_started))
		return;

	if (WARN_ON(!wdev->channel))
		return;

	cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT);

	switch (event) {
	case NL80211_RADAR_CAC_FINISHED:
		timeout = wdev->cac_start_time +
			  msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
		WARN_ON(!time_after_eq(jiffies, timeout));
		cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE);
		break;
	case NL80211_RADAR_CAC_ABORTED:
		break;
	default:
		WARN_ON(1);
		return;
	}
	wdev->cac_started = false;

	nl80211_radar_notify(rdev, &chandef, event, netdev, gfp);
}
EXPORT_SYMBOL(cfg80211_cac_event);