mlme.c 24.3 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 267
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_auth_request req;
268
	int err;
J
Johannes Berg 已提交
269

J
Johannes Berg 已提交
270 271
	ASSERT_WDEV_LOCK(wdev);

J
Johannes Berg 已提交
272 273 274 275
	if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
		if (!key || !key_len || key_idx < 0 || key_idx > 4)
			return -EINVAL;

276
	if (wdev->current_bss &&
277
	    ether_addr_equal(bssid, wdev->current_bss->pub.bssid))
278 279
		return -EALREADY;

J
Johannes Berg 已提交
280 281 282 283
	memset(&req, 0, sizeof(req));

	req.ie = ie;
	req.ie_len = ie_len;
284 285
	req.sae_data = sae_data;
	req.sae_data_len = sae_data_len;
J
Johannes Berg 已提交
286 287 288
	req.auth_type = auth_type;
	req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
				   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
J
Johannes Berg 已提交
289 290 291
	req.key = key;
	req.key_len = key_len;
	req.key_idx = key_idx;
J
Johannes Berg 已提交
292 293 294
	if (!req.bss)
		return -ENOENT;

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

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

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

J
Johannes Berg 已提交
307 308 309 310
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 已提交
311
		       const u8 *ie, int ie_len,
312 313
		       const u8 *key, int key_len, int key_idx,
		       const u8 *sae_data, int sae_data_len)
J
Johannes Berg 已提交
314 315 316
{
	int err;

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

	return err;
}

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
/*  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];
}

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
/*  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 已提交
363 364 365
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
			  struct net_device *dev,
			  struct ieee80211_channel *chan,
366
			  const u8 *bssid,
J
Johannes Berg 已提交
367
			  const u8 *ssid, int ssid_len,
368
			  struct cfg80211_assoc_request *req)
J
Johannes Berg 已提交
369 370
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
371
	int err;
372
	bool was_connected = false;
J
Johannes Berg 已提交
373

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

376 377
	if (wdev->current_bss && req->prev_bssid &&
	    ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) {
378 379 380 381 382 383 384 385 386
		/*
		 * 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 已提交
387 388
		return -EALREADY;

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

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

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

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

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

	return err;
}

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

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

	return err;
}

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

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

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

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

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

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

	return err;
}

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

J
Johannes Berg 已提交
485 486
	ASSERT_WDEV_LOCK(wdev);

487 488 489
	if (wdev->sme_state != CFG80211_SME_CONNECTED)
		return -ENOTCONN;

490
	if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state))
491 492
		return -ENOTCONN;

J
Johannes Berg 已提交
493 494
	memset(&req, 0, sizeof(req));
	req.reason_code = reason;
495
	req.local_state_change = local_state_change;
J
Johannes Berg 已提交
496 497
	req.ie = ie;
	req.ie_len = ie_len;
498
	if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
J
Johannes Berg 已提交
499 500 501 502
		req.bss = &wdev->current_bss->pub;
	else
		return -ENOTCONN;

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

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

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

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

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

J
Johannes Berg 已提交
529 530
	ASSERT_WDEV_LOCK(wdev);

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

	memset(&req, 0, sizeof(req));
	req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
	req.ie = NULL;
	req.ie_len = 0;

539 540
	if (!wdev->current_bss)
		return;
J
Johannes Berg 已提交
541

542 543
	memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
	req.bssid = bssid;
544
	rdev_deauth(rdev, dev, &req);
545 546 547

	if (wdev->current_bss) {
		cfg80211_unhold_bss(wdev->current_bss);
548
		cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub);
549
		wdev->current_bss = NULL;
J
Johannes Berg 已提交
550 551
	}
}
552

553
struct cfg80211_mgmt_registration {
554 555
	struct list_head list;

556
	u32 nlportid;
557 558 559

	int match_len;

560 561
	__le16 frame_type;

562 563 564
	u8 match[];
};

565
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
566 567
				u16 frame_type, const u8 *match_data,
				int match_len)
568
{
569 570
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
571
	struct cfg80211_mgmt_registration *reg, *nreg;
572
	int err = 0;
573 574 575 576 577 578 579 580 581 582 583 584 585 586
	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;
587 588 589 590 591

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

592
	spin_lock_bh(&wdev->mgmt_registrations_lock);
593

594
	list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
595 596
		int mlen = min(match_len, reg->match_len);

597 598 599
		if (frame_type != le16_to_cpu(reg->frame_type))
			continue;

600 601 602 603 604 605 606 607 608 609 610 611 612
		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;
613
	nreg->nlportid = snd_portid;
614 615
	nreg->frame_type = cpu_to_le16(frame_type);
	list_add(&nreg->list, &wdev->mgmt_registrations);
616

617
	if (rdev->ops->mgmt_frame_register)
618
		rdev_mgmt_frame_register(rdev, wdev, frame_type, true);
619

620
 out:
621
	spin_unlock_bh(&wdev->mgmt_registrations_lock);
622

623 624 625
	return err;
}

626
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
627
{
628 629
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
630
	struct cfg80211_mgmt_registration *reg, *tmp;
631

632
	spin_lock_bh(&wdev->mgmt_registrations_lock);
633

634
	list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
635
		if (reg->nlportid != nlportid)
636 637 638 639 640
			continue;

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

641 642
			rdev_mgmt_frame_register(rdev, wdev,
						 frame_type, false);
643
		}
644 645 646

		list_del(&reg->list);
		kfree(reg);
647 648
	}

649
	spin_unlock_bh(&wdev->mgmt_registrations_lock);
650

651 652 653 654 655
	if (nlportid && rdev->crit_proto_nlportid == nlportid) {
		rdev->crit_proto_nlportid = 0;
		rdev_crit_proto_stop(rdev, wdev);
	}

656 657
	if (nlportid == wdev->ap_unexpected_nlportid)
		wdev->ap_unexpected_nlportid = 0;
658 659
}

660
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
661
{
662
	struct cfg80211_mgmt_registration *reg, *tmp;
663

664
	spin_lock_bh(&wdev->mgmt_registrations_lock);
665

666
	list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
667 668 669 670
		list_del(&reg->list);
		kfree(reg);
	}

671
	spin_unlock_bh(&wdev->mgmt_registrations_lock);
672 673
}

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

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

686
	if (!rdev->ops->mgmt_tx)
687
		return -EOPNOTSUPP;
688

689 690 691 692
	if (len < 24 + 1)
		return -EINVAL;

	mgmt = (const struct ieee80211_mgmt *) buf;
693 694

	if (!ieee80211_is_mgmt(mgmt->frame_control))
695
		return -EINVAL;
696 697 698 699 700 701 702

	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) {
703 704
		int err = 0;

705 706
		wdev_lock(wdev);

707 708 709 710 711 712 713 714 715
		switch (wdev->iftype) {
		case NL80211_IFTYPE_ADHOC:
		case NL80211_IFTYPE_STATION:
		case NL80211_IFTYPE_P2P_CLIENT:
			if (!wdev->current_bss) {
				err = -ENOTCONN;
				break;
			}

716 717
			if (!ether_addr_equal(wdev->current_bss->pub.bssid,
					      mgmt->bssid)) {
718 719 720 721 722 723 724 725 726 727
				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;
728

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

		if (err)
			return err;
765 766
	}

767
	if (!ether_addr_equal(mgmt->sa, wdev_address(wdev)))
768 769 770
		return -EINVAL;

	/* Transmit the Action frame as requested by user space */
771 772 773
	return rdev_mgmt_tx(rdev, wdev, chan, offchan,
			    wait, buf, len, no_cck, dont_wait_for_ack,
			    cookie);
774 775
}

776
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
777
		      const u8 *buf, size_t len, gfp_t gfp)
778 779 780
{
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
781 782 783 784 785 786
	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;
787
	bool result = false;
788 789 790
	__le16 ftype = mgmt->frame_control &
		cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
	u16 stype;
791

792
	trace_cfg80211_rx_mgmt(wdev, freq, sig_mbm);
793
	stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
794

795 796
	if (!(stypes->rx & BIT(stype))) {
		trace_cfg80211_return_bool(false);
797
		return false;
798
	}
799

800 801 802 803 804 805 806 807
	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;
808

809
		if (reg->match_len > data_len)
810 811
			continue;

812
		if (memcmp(reg->match, data, reg->match_len))
813 814 815 816 817
			continue;

		/* found match! */

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

		result = true;
		break;
	}

827
	spin_unlock_bh(&wdev->mgmt_registrations_lock);
828

829
	trace_cfg80211_return_bool(result);
830 831
	return result;
}
832
EXPORT_SYMBOL(cfg80211_rx_mgmt);
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 949 950 951 952
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);