sme.c 25.4 KB
Newer Older
S
Samuel Ortiz 已提交
1
/*
2 3 4
 * SME code for cfg80211
 * both driver SME event handling and the SME implementation
 * (for nl80211's connect() and wext)
S
Samuel Ortiz 已提交
5 6 7 8 9 10 11
 *
 * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
 * Copyright (C) 2009   Intel Corporation. All rights reserved.
 */

#include <linux/etherdevice.h>
#include <linux/if_arp.h>
12
#include <linux/slab.h>
S
Samuel Ortiz 已提交
13
#include <linux/workqueue.h>
14
#include <linux/wireless.h>
15
#include <linux/export.h>
16
#include <net/iw_handler.h>
S
Samuel Ortiz 已提交
17 18 19
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include "nl80211.h"
20
#include "reg.h"
21
#include "rdev-ops.h"
S
Samuel Ortiz 已提交
22

23 24 25 26 27 28
/*
 * Software SME in cfg80211, using auth/assoc/deauth calls to the
 * driver. This is is for implementing nl80211's connect/disconnect
 * and wireless extensions (if configured.)
 */

29 30 31 32 33 34 35 36
struct cfg80211_conn {
	struct cfg80211_connect_params params;
	/* these are sub-states of the _CONNECTING sme_state */
	enum {
		CFG80211_CONN_SCANNING,
		CFG80211_CONN_SCAN_AGAIN,
		CFG80211_CONN_AUTHENTICATE_NEXT,
		CFG80211_CONN_AUTHENTICATING,
37
		CFG80211_CONN_AUTH_FAILED,
38 39
		CFG80211_CONN_ASSOCIATE_NEXT,
		CFG80211_CONN_ASSOCIATING,
40
		CFG80211_CONN_ASSOC_FAILED,
41 42
		CFG80211_CONN_DEAUTH,
		CFG80211_CONN_CONNECTED,
43
	} state;
44
	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
45 46
	u8 *ie;
	size_t ie_len;
47
	bool auto_auth, prev_bssid_valid;
48 49
};

50
static void cfg80211_sme_free(struct wireless_dev *wdev)
51
{
52 53
	if (!wdev->conn)
		return;
54

55 56 57
	kfree(wdev->conn->ie);
	kfree(wdev->conn);
	wdev->conn = NULL;
58 59
}

60 61
static int cfg80211_conn_scan(struct wireless_dev *wdev)
{
62
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
63 64 65 66
	struct cfg80211_scan_request *request;
	int n_channels, err;

	ASSERT_RTNL();
67
	ASSERT_RDEV_LOCK(rdev);
J
Johannes Berg 已提交
68
	ASSERT_WDEV_LOCK(wdev);
69

70
	if (rdev->scan_req)
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
		return -EBUSY;

	if (wdev->conn->params.channel) {
		n_channels = 1;
	} else {
		enum ieee80211_band band;
		n_channels = 0;

		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
			if (!wdev->wiphy->bands[band])
				continue;
			n_channels += wdev->wiphy->bands[band]->n_channels;
		}
	}
	request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
			  sizeof(request->channels[0]) * n_channels,
			  GFP_KERNEL);
	if (!request)
		return -ENOMEM;

	if (wdev->conn->params.channel)
		request->channels[0] = wdev->conn->params.channel;
	else {
		int i = 0, j;
		enum ieee80211_band band;
96 97
		struct ieee80211_supported_band *bands;
		struct ieee80211_channel *channel;
98 99

		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
100 101
			bands = wdev->wiphy->bands[band];
			if (!bands)
102
				continue;
103 104 105 106 107 108 109
			for (j = 0; j < bands->n_channels; j++) {
				channel = &bands->channels[j];
				if (channel->flags & IEEE80211_CHAN_DISABLED)
					continue;
				request->channels[i++] = channel;
			}
			request->rates[band] = (1 << bands->n_bitrates) - 1;
110
		}
111
		n_channels = i;
112 113
	}
	request->n_channels = n_channels;
114
	request->ssids = (void *)&request->channels[n_channels];
115 116 117 118 119 120
	request->n_ssids = 1;

	memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
		wdev->conn->params.ssid_len);
	request->ssids[0].ssid_len = wdev->conn->params.ssid_len;

J
Johannes Berg 已提交
121
	request->wdev = wdev;
122
	request->wiphy = &rdev->wiphy;
123
	request->scan_start = jiffies;
124

125
	rdev->scan_req = request;
126

127
	err = rdev_scan(rdev, request);
128 129
	if (!err) {
		wdev->conn->state = CFG80211_CONN_SCANNING;
J
Johannes Berg 已提交
130
		nl80211_send_scan_start(rdev, wdev);
131
		dev_hold(wdev->netdev);
132
	} else {
133
		rdev->scan_req = NULL;
134 135 136 137 138 139 140
		kfree(request);
	}
	return err;
}

static int cfg80211_conn_do_work(struct wireless_dev *wdev)
{
141
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
J
Johannes Berg 已提交
142
	struct cfg80211_connect_params *params;
143
	struct cfg80211_assoc_request req = {};
J
Johannes Berg 已提交
144
	int err;
145

J
Johannes Berg 已提交
146 147
	ASSERT_WDEV_LOCK(wdev);

148 149 150
	if (!wdev->conn)
		return 0;

J
Johannes Berg 已提交
151 152
	params = &wdev->conn->params;

153
	switch (wdev->conn->state) {
154 155 156
	case CFG80211_CONN_SCANNING:
		/* didn't find it during scan ... */
		return -ENOENT;
157 158 159
	case CFG80211_CONN_SCAN_AGAIN:
		return cfg80211_conn_scan(wdev);
	case CFG80211_CONN_AUTHENTICATE_NEXT:
160
		BUG_ON(!rdev->ops->auth);
J
Johannes Berg 已提交
161
		wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
162 163 164 165 166 167 168
		return cfg80211_mlme_auth(rdev, wdev->netdev,
					  params->channel, params->auth_type,
					  params->bssid,
					  params->ssid, params->ssid_len,
					  NULL, 0,
					  params->key, params->key_len,
					  params->key_idx, NULL, 0);
169 170
	case CFG80211_CONN_AUTH_FAILED:
		return -ENOTCONN;
171
	case CFG80211_CONN_ASSOCIATE_NEXT:
172
		BUG_ON(!rdev->ops->assoc);
J
Johannes Berg 已提交
173
		wdev->conn->state = CFG80211_CONN_ASSOCIATING;
174
		if (wdev->conn->prev_bssid_valid)
175 176 177 178 179 180 181 182 183 184 185
			req.prev_bssid = wdev->conn->prev_bssid;
		req.ie = params->ie;
		req.ie_len = params->ie_len;
		req.use_mfp = params->mfp != NL80211_MFP_NO;
		req.crypto = params->crypto;
		req.flags = params->flags;
		req.ht_capa = params->ht_capa;
		req.ht_capa_mask = params->ht_capa_mask;
		req.vht_capa = params->vht_capa;
		req.vht_capa_mask = params->vht_capa_mask;

186 187 188
		err = cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel,
					  params->bssid, params->ssid,
					  params->ssid_len, &req);
J
Johannes Berg 已提交
189
		if (err)
190 191 192 193
			cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
					     NULL, 0,
					     WLAN_REASON_DEAUTH_LEAVING,
					     false);
J
Johannes Berg 已提交
194
		return err;
195 196 197 198 199
	case CFG80211_CONN_ASSOC_FAILED:
		cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
				     NULL, 0,
				     WLAN_REASON_DEAUTH_LEAVING, false);
		return -ENOTCONN;
200
	case CFG80211_CONN_DEAUTH:
201 202 203
		cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
				     NULL, 0,
				     WLAN_REASON_DEAUTH_LEAVING, false);
204 205
		/* free directly, disconnected event already sent */
		cfg80211_sme_free(wdev);
206
		return 0;
207 208 209 210 211 212 213
	default:
		return 0;
	}
}

void cfg80211_conn_work(struct work_struct *work)
{
214
	struct cfg80211_registered_device *rdev =
215 216
		container_of(work, struct cfg80211_registered_device, conn_work);
	struct wireless_dev *wdev;
J
Johannes Berg 已提交
217
	u8 bssid_buf[ETH_ALEN], *bssid = NULL;
218 219 220

	rtnl_lock();

221
	list_for_each_entry(wdev, &rdev->wdev_list, list) {
222 223 224
		if (!wdev->netdev)
			continue;

J
Johannes Berg 已提交
225 226 227
		wdev_lock(wdev);
		if (!netif_running(wdev->netdev)) {
			wdev_unlock(wdev);
228
			continue;
J
Johannes Berg 已提交
229
		}
230 231
		if (!wdev->conn ||
		    wdev->conn->state == CFG80211_CONN_CONNECTED) {
J
Johannes Berg 已提交
232
			wdev_unlock(wdev);
233
			continue;
J
Johannes Berg 已提交
234
		}
J
Johannes Berg 已提交
235 236 237 238
		if (wdev->conn->params.bssid) {
			memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
			bssid = bssid_buf;
		}
239
		if (cfg80211_conn_do_work(wdev)) {
J
Johannes Berg 已提交
240
			__cfg80211_connect_result(
241
					wdev->netdev, bssid,
J
Johannes Berg 已提交
242 243
					NULL, 0, NULL, 0,
					WLAN_STATUS_UNSPECIFIED_FAILURE,
244
					false, NULL);
245 246
			cfg80211_sme_free(wdev);
		}
J
Johannes Berg 已提交
247
		wdev_unlock(wdev);
248 249 250 251 252
	}

	rtnl_unlock();
}

253
/* Returned bss is reference counted and must be cleaned up appropriately. */
J
Johannes Berg 已提交
254
static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
255
{
256
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
257 258 259
	struct cfg80211_bss *bss;
	u16 capa = WLAN_CAPABILITY_ESS;

J
Johannes Berg 已提交
260 261
	ASSERT_WDEV_LOCK(wdev);

262 263 264
	if (wdev->conn->params.privacy)
		capa |= WLAN_CAPABILITY_PRIVACY;

265 266
	bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel,
			       wdev->conn->params.bssid,
267 268 269 270 271
			       wdev->conn->params.ssid,
			       wdev->conn->params.ssid_len,
			       WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
			       capa);
	if (!bss)
J
Johannes Berg 已提交
272
		return NULL;
273 274 275 276 277

	memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
	wdev->conn->params.bssid = wdev->conn->bssid;
	wdev->conn->params.channel = bss->channel;
	wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
278
	schedule_work(&rdev->conn_work);
279

J
Johannes Berg 已提交
280
	return bss;
281 282
}

J
Johannes Berg 已提交
283
static void __cfg80211_sme_scan_done(struct net_device *dev)
284 285
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
286
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
J
Johannes Berg 已提交
287
	struct cfg80211_bss *bss;
288

J
Johannes Berg 已提交
289 290
	ASSERT_WDEV_LOCK(wdev);

291
	if (!wdev->conn)
292 293 294 295 296 297
		return;

	if (wdev->conn->state != CFG80211_CONN_SCANNING &&
	    wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
		return;

J
Johannes Berg 已提交
298
	bss = cfg80211_get_conn_bss(wdev);
299
	if (bss)
300
		cfg80211_put_bss(&rdev->wiphy, bss);
301 302
	else
		schedule_work(&rdev->conn_work);
303 304
}

J
Johannes Berg 已提交
305 306 307 308 309 310 311 312 313
void cfg80211_sme_scan_done(struct net_device *dev)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;

	wdev_lock(wdev);
	__cfg80211_sme_scan_done(dev);
	wdev_unlock(wdev);
}

314
void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
315 316 317 318 319 320
{
	struct wiphy *wiphy = wdev->wiphy;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
	u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);

J
Johannes Berg 已提交
321 322
	ASSERT_WDEV_LOCK(wdev);

323
	if (!wdev->conn || wdev->conn->state == CFG80211_CONN_CONNECTED)
324 325 326 327 328 329 330 331
		return;

	if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
	    wdev->conn->auto_auth &&
	    wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
		/* select automatically between only open, shared, leap */
		switch (wdev->conn->params.auth_type) {
		case NL80211_AUTHTYPE_OPEN_SYSTEM:
J
Johannes Berg 已提交
332 333 334 335 336 337
			if (wdev->connect_keys)
				wdev->conn->params.auth_type =
					NL80211_AUTHTYPE_SHARED_KEY;
			else
				wdev->conn->params.auth_type =
					NL80211_AUTHTYPE_NETWORK_EAP;
338 339 340 341 342 343 344 345 346 347 348 349 350
			break;
		case NL80211_AUTHTYPE_SHARED_KEY:
			wdev->conn->params.auth_type =
				NL80211_AUTHTYPE_NETWORK_EAP;
			break;
		default:
			/* huh? */
			wdev->conn->params.auth_type =
				NL80211_AUTHTYPE_OPEN_SYSTEM;
			break;
		}
		wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
		schedule_work(&rdev->conn_work);
J
Johannes Berg 已提交
351
	} else if (status_code != WLAN_STATUS_SUCCESS) {
352 353
		__cfg80211_connect_result(wdev->netdev, mgmt->bssid,
					  NULL, 0, NULL, 0,
354
					  status_code, false, NULL);
355
	} else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
356 357 358 359
		wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
		schedule_work(&rdev->conn_work);
	}
}
S
Samuel Ortiz 已提交
360

361
bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
362
{
363
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
364

365
	if (!wdev->conn)
366 367
		return false;

368 369
	if (status == WLAN_STATUS_SUCCESS) {
		wdev->conn->state = CFG80211_CONN_CONNECTED;
370
		return false;
371
	}
372

373 374 375 376 377 378 379 380 381 382 383 384
	if (wdev->conn->prev_bssid_valid) {
		/*
		 * Some stupid APs don't accept reassoc, so we
		 * need to fall back to trying regular assoc;
		 * return true so no event is sent to userspace.
		 */
		wdev->conn->prev_bssid_valid = false;
		wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
		schedule_work(&rdev->conn_work);
		return true;
	}

385
	wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
386
	schedule_work(&rdev->conn_work);
387 388
	return false;
}
389

390 391 392
void cfg80211_sme_deauth(struct wireless_dev *wdev)
{
	cfg80211_sme_free(wdev);
393 394
}

395
void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
396
{
397 398 399 400 401 402 403
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);

	if (!wdev->conn)
		return;

	wdev->conn->state = CFG80211_CONN_AUTH_FAILED;
	schedule_work(&rdev->conn_work);
404
}
405

406 407 408 409 410 411 412 413
void cfg80211_sme_disassoc(struct wireless_dev *wdev)
{
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);

	if (!wdev->conn)
		return;

	wdev->conn->state = CFG80211_CONN_DEAUTH;
414 415 416
	schedule_work(&rdev->conn_work);
}

417 418
void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
{
419 420 421 422 423 424 425
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);

	if (!wdev->conn)
		return;

	wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
	schedule_work(&rdev->conn_work);
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 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 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
}

static int cfg80211_sme_connect(struct wireless_dev *wdev,
				struct cfg80211_connect_params *connect,
				const u8 *prev_bssid)
{
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
	struct cfg80211_bss *bss;
	int err;

	if (!rdev->ops->auth || !rdev->ops->assoc)
		return -EOPNOTSUPP;

	if (wdev->current_bss)
		return -EALREADY;

	if (WARN_ON(wdev->conn))
		return -EINPROGRESS;

	wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
	if (!wdev->conn)
		return -ENOMEM;

	/*
	 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
	 */
	memcpy(&wdev->conn->params, connect, sizeof(*connect));
	if (connect->bssid) {
		wdev->conn->params.bssid = wdev->conn->bssid;
		memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
	}

	if (connect->ie) {
		wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
					GFP_KERNEL);
		wdev->conn->params.ie = wdev->conn->ie;
		if (!wdev->conn->ie) {
			kfree(wdev->conn);
			wdev->conn = NULL;
			return -ENOMEM;
		}
	}

	if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
		wdev->conn->auto_auth = true;
		/* start with open system ... should mostly work */
		wdev->conn->params.auth_type =
			NL80211_AUTHTYPE_OPEN_SYSTEM;
	} else {
		wdev->conn->auto_auth = false;
	}

	wdev->conn->params.ssid = wdev->ssid;
	wdev->conn->params.ssid_len = connect->ssid_len;

	/* see if we have the bss already */
	bss = cfg80211_get_conn_bss(wdev);

	if (prev_bssid) {
		memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
		wdev->conn->prev_bssid_valid = true;
	}

	/* we're good if we have a matching bss struct */
	if (bss) {
		wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
		err = cfg80211_conn_do_work(wdev);
		cfg80211_put_bss(wdev->wiphy, bss);
	} else {
		/* otherwise we'll need to scan for the AP first */
		err = cfg80211_conn_scan(wdev);

		/*
		 * If we can't scan right now, then we need to scan again
		 * after the current scan finished, since the parameters
		 * changed (unless we find a good AP anyway).
		 */
		if (err == -EBUSY) {
			err = 0;
			wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
		}
	}

	if (err)
		cfg80211_sme_free(wdev);

	return err;
}

static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason)
{
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
	int err;

	if (!wdev->conn)
		return 0;

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

	if (wdev->conn->state == CFG80211_CONN_SCANNING ||
	    wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) {
		err = 0;
		goto out;
	}

	/* wdev->conn->params.bssid must be set if > SCANNING */
	err = cfg80211_mlme_deauth(rdev, wdev->netdev,
				   wdev->conn->params.bssid,
				   NULL, 0, reason, false);
 out:
	cfg80211_sme_free(wdev);
	return err;
}

/*
 * code shared for in-device and software SME
 */

static bool cfg80211_is_all_idle(void)
{
	struct cfg80211_registered_device *rdev;
	struct wireless_dev *wdev;
	bool is_all_idle = true;

	/*
	 * All devices must be idle as otherwise if you are actively
	 * scanning some new beacon hints could be learned and would
	 * count as new regulatory hints.
	 */
	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
		list_for_each_entry(wdev, &rdev->wdev_list, list) {
			wdev_lock(wdev);
			if (wdev->conn || wdev->current_bss)
				is_all_idle = false;
			wdev_unlock(wdev);
		}
	}

	return is_all_idle;
}

static void disconnect_work(struct work_struct *work)
{
	rtnl_lock();
	if (cfg80211_is_all_idle())
		regulatory_hint_disconnect();
	rtnl_unlock();
}

static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);


/*
 * API calls for drivers implementing connect/disconnect and
 * SME event handling
 */

584
/* This method must consume bss one way or another */
J
Johannes Berg 已提交
585 586 587
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
			       const u8 *req_ie, size_t req_ie_len,
			       const u8 *resp_ie, size_t resp_ie_len,
588 589
			       u16 status, bool wextev,
			       struct cfg80211_bss *bss)
S
Samuel Ortiz 已提交
590 591
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
592
	const u8 *country_ie;
J
Johannes Berg 已提交
593
#ifdef CONFIG_CFG80211_WEXT
S
Samuel Ortiz 已提交
594 595 596
	union iwreq_data wrqu;
#endif

J
Johannes Berg 已提交
597 598
	ASSERT_WDEV_LOCK(wdev);

599
	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
600 601
		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
		cfg80211_put_bss(wdev->wiphy, bss);
S
Samuel Ortiz 已提交
602
		return;
603
	}
S
Samuel Ortiz 已提交
604

605
	nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
606
				    bssid, req_ie, req_ie_len,
607 608
				    resp_ie, resp_ie_len,
				    status, GFP_KERNEL);
609

J
Johannes Berg 已提交
610
#ifdef CONFIG_CFG80211_WEXT
611 612 613 614
	if (wextev) {
		if (req_ie && status == WLAN_STATUS_SUCCESS) {
			memset(&wrqu, 0, sizeof(wrqu));
			wrqu.data.length = req_ie_len;
Z
Zhu Yi 已提交
615
			wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
616 617 618 619 620 621 622 623 624 625
		}

		if (resp_ie && status == WLAN_STATUS_SUCCESS) {
			memset(&wrqu, 0, sizeof(wrqu));
			wrqu.data.length = resp_ie_len;
			wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
		}

		memset(&wrqu, 0, sizeof(wrqu));
		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
626
		if (bssid && status == WLAN_STATUS_SUCCESS) {
627
			memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
628 629 630
			memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
			wdev->wext.prev_bssid_valid = true;
		}
631 632 633 634
		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
	}
#endif

635 636 637 638 639 640 641 642 643 644
	if (!bss && (status == WLAN_STATUS_SUCCESS)) {
		WARN_ON_ONCE(!wiphy_to_dev(wdev->wiphy)->ops->connect);
		bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
				       wdev->ssid, wdev->ssid_len,
				       WLAN_CAPABILITY_ESS,
				       WLAN_CAPABILITY_ESS);
		if (bss)
			cfg80211_hold_bss(bss_from_pub(bss));
	}

645 646
	if (wdev->current_bss) {
		cfg80211_unhold_bss(wdev->current_bss);
647
		cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
648 649 650
		wdev->current_bss = NULL;
	}

J
Johannes Berg 已提交
651 652 653
	if (status != WLAN_STATUS_SUCCESS) {
		kfree(wdev->connect_keys);
		wdev->connect_keys = NULL;
654
		wdev->ssid_len = 0;
655 656 657 658
		if (bss) {
			cfg80211_unhold_bss(bss_from_pub(bss));
			cfg80211_put_bss(wdev->wiphy, bss);
		}
J
Johannes Berg 已提交
659
		return;
S
Samuel Ortiz 已提交
660
	}
J
Johannes Berg 已提交
661

662 663
	if (WARN_ON(!bss))
		return;
J
Johannes Berg 已提交
664 665 666 667

	wdev->current_bss = bss_from_pub(bss);

	cfg80211_upload_connect_keys(wdev);
668

669 670 671 672 673 674 675 676 677
	rcu_read_lock();
	country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
	if (!country_ie) {
		rcu_read_unlock();
		return;
	}

	country_ie = kmemdup(country_ie, 2 + country_ie[1], GFP_ATOMIC);
	rcu_read_unlock();
678 679 680 681 682 683 684 685 686

	if (!country_ie)
		return;

	/*
	 * ieee80211_bss_get_ie() ensures we can access:
	 * - country_ie + 2, the start of the country ie data, and
	 * - and country_ie[1] which is the IE length
	 */
687 688
	regulatory_hint_country_ie(wdev->wiphy, bss->channel->band,
				   country_ie + 2, country_ie[1]);
689
	kfree(country_ie);
S
Samuel Ortiz 已提交
690
}
691 692 693 694 695 696

void cfg80211_connect_result(struct net_device *dev, 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)
{
J
Johannes Berg 已提交
697 698 699 700 701 702 703 704 705 706
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
	struct cfg80211_event *ev;
	unsigned long flags;

	ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
	if (!ev)
		return;

	ev->type = EVENT_CONNECT_RESULT;
707 708
	if (bssid)
		memcpy(ev->cr.bssid, bssid, ETH_ALEN);
709 710 711 712 713 714 715 716 717 718
	if (req_ie_len) {
		ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
		ev->cr.req_ie_len = req_ie_len;
		memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
	}
	if (resp_ie_len) {
		ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
		ev->cr.resp_ie_len = resp_ie_len;
		memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
	}
J
Johannes Berg 已提交
719 720 721 722 723
	ev->cr.status = status;

	spin_lock_irqsave(&wdev->event_lock, flags);
	list_add_tail(&ev->list, &wdev->event_list);
	spin_unlock_irqrestore(&wdev->event_lock, flags);
724
	queue_work(cfg80211_wq, &rdev->event_work);
725
}
S
Samuel Ortiz 已提交
726 727
EXPORT_SYMBOL(cfg80211_connect_result);

728
/* Consumes bss object one way or another */
729
void __cfg80211_roamed(struct wireless_dev *wdev,
730
		       struct cfg80211_bss *bss,
J
Johannes Berg 已提交
731 732
		       const u8 *req_ie, size_t req_ie_len,
		       const u8 *resp_ie, size_t resp_ie_len)
S
Samuel Ortiz 已提交
733
{
J
Johannes Berg 已提交
734
#ifdef CONFIG_CFG80211_WEXT
S
Samuel Ortiz 已提交
735 736
	union iwreq_data wrqu;
#endif
J
Johannes Berg 已提交
737 738
	ASSERT_WDEV_LOCK(wdev);

739 740
	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
741
		goto out;
S
Samuel Ortiz 已提交
742

743
	if (WARN_ON(!wdev->current_bss))
744
		goto out;
S
Samuel Ortiz 已提交
745 746

	cfg80211_unhold_bss(wdev->current_bss);
747
	cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
S
Samuel Ortiz 已提交
748 749
	wdev->current_bss = NULL;

J
Johannes Berg 已提交
750 751
	cfg80211_hold_bss(bss_from_pub(bss));
	wdev->current_bss = bss_from_pub(bss);
S
Samuel Ortiz 已提交
752

753
	nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bss->bssid,
J
Johannes Berg 已提交
754 755
			    req_ie, req_ie_len, resp_ie, resp_ie_len,
			    GFP_KERNEL);
S
Samuel Ortiz 已提交
756

J
Johannes Berg 已提交
757
#ifdef CONFIG_CFG80211_WEXT
S
Samuel Ortiz 已提交
758 759 760
	if (req_ie) {
		memset(&wrqu, 0, sizeof(wrqu));
		wrqu.data.length = req_ie_len;
Z
Zhu Yi 已提交
761
		wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
J
Johannes Berg 已提交
762
				    &wrqu, req_ie);
S
Samuel Ortiz 已提交
763 764 765 766 767
	}

	if (resp_ie) {
		memset(&wrqu, 0, sizeof(wrqu));
		wrqu.data.length = resp_ie_len;
J
Johannes Berg 已提交
768 769
		wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
				    &wrqu, resp_ie);
S
Samuel Ortiz 已提交
770 771 772 773
	}

	memset(&wrqu, 0, sizeof(wrqu));
	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
774 775
	memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
	memcpy(wdev->wext.prev_bssid, bss->bssid, ETH_ALEN);
776
	wdev->wext.prev_bssid_valid = true;
J
Johannes Berg 已提交
777
	wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
S
Samuel Ortiz 已提交
778
#endif
779 780 781

	return;
out:
782
	cfg80211_put_bss(wdev->wiphy, bss);
S
Samuel Ortiz 已提交
783
}
J
Johannes Berg 已提交
784

785 786 787
void cfg80211_roamed(struct net_device *dev,
		     struct ieee80211_channel *channel,
		     const u8 *bssid,
J
Johannes Berg 已提交
788 789
		     const u8 *req_ie, size_t req_ie_len,
		     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_bss *bss;

	bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
			       wdev->ssid_len, WLAN_CAPABILITY_ESS,
			       WLAN_CAPABILITY_ESS);
	if (WARN_ON(!bss))
		return;

	cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie,
			    resp_ie_len, gfp);
}
EXPORT_SYMBOL(cfg80211_roamed);

805
/* Consumes bss object one way or another */
806 807 808 809
void cfg80211_roamed_bss(struct net_device *dev,
			 struct cfg80211_bss *bss, const u8 *req_ie,
			 size_t req_ie_len, const u8 *resp_ie,
			 size_t resp_ie_len, gfp_t gfp)
J
Johannes Berg 已提交
810 811 812 813 814 815
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
	struct cfg80211_event *ev;
	unsigned long flags;

816 817 818
	if (WARN_ON(!bss))
		return;

J
Johannes Berg 已提交
819
	ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
820
	if (!ev) {
821
		cfg80211_put_bss(wdev->wiphy, bss);
J
Johannes Berg 已提交
822
		return;
823
	}
J
Johannes Berg 已提交
824 825 826 827 828 829 830 831

	ev->type = EVENT_ROAMED;
	ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
	ev->rm.req_ie_len = req_ie_len;
	memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len);
	ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
	ev->rm.resp_ie_len = resp_ie_len;
	memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
832
	ev->rm.bss = bss;
J
Johannes Berg 已提交
833 834 835 836

	spin_lock_irqsave(&wdev->event_lock, flags);
	list_add_tail(&ev->list, &wdev->event_list);
	spin_unlock_irqrestore(&wdev->event_lock, flags);
837
	queue_work(cfg80211_wq, &rdev->event_work);
J
Johannes Berg 已提交
838
}
839
EXPORT_SYMBOL(cfg80211_roamed_bss);
S
Samuel Ortiz 已提交
840

J
Johannes Berg 已提交
841
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
842
			     size_t ie_len, u16 reason, bool from_ap)
S
Samuel Ortiz 已提交
843 844
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
J
Johannes Berg 已提交
845 846
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
	int i;
J
Johannes Berg 已提交
847
#ifdef CONFIG_CFG80211_WEXT
S
Samuel Ortiz 已提交
848 849 850
	union iwreq_data wrqu;
#endif

J
Johannes Berg 已提交
851 852
	ASSERT_WDEV_LOCK(wdev);

853 854
	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
S
Samuel Ortiz 已提交
855 856 857 858
		return;

	if (wdev->current_bss) {
		cfg80211_unhold_bss(wdev->current_bss);
859
		cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
S
Samuel Ortiz 已提交
860 861 862
	}

	wdev->current_bss = NULL;
863
	wdev->ssid_len = 0;
S
Samuel Ortiz 已提交
864

J
Johannes Berg 已提交
865 866 867 868 869 870 871 872
	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);

	/*
	 * Delete all the keys ... pairwise keys can't really
	 * exist any more anyway, but default keys might.
	 */
	if (rdev->ops->del_key)
		for (i = 0; i < 6; i++)
873
			rdev_del_key(rdev, dev, i, false, NULL);
S
Samuel Ortiz 已提交
874

J
Johannes Berg 已提交
875
#ifdef CONFIG_CFG80211_WEXT
S
Samuel Ortiz 已提交
876 877 878
	memset(&wrqu, 0, sizeof(wrqu));
	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
879
	wdev->wext.connect.ssid_len = 0;
S
Samuel Ortiz 已提交
880
#endif
881 882

	schedule_work(&cfg80211_disconnect_work);
S
Samuel Ortiz 已提交
883 884 885 886 887
}

void cfg80211_disconnected(struct net_device *dev, u16 reason,
			   u8 *ie, size_t ie_len, gfp_t gfp)
{
J
Johannes Berg 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
	struct cfg80211_event *ev;
	unsigned long flags;

	ev = kzalloc(sizeof(*ev) + ie_len, gfp);
	if (!ev)
		return;

	ev->type = EVENT_DISCONNECTED;
	ev->dc.ie = ((u8 *)ev) + sizeof(*ev);
	ev->dc.ie_len = ie_len;
	memcpy((void *)ev->dc.ie, ie, ie_len);
	ev->dc.reason = reason;

	spin_lock_irqsave(&wdev->event_lock, flags);
	list_add_tail(&ev->list, &wdev->event_list);
	spin_unlock_irqrestore(&wdev->event_lock, flags);
906
	queue_work(cfg80211_wq, &rdev->event_work);
S
Samuel Ortiz 已提交
907 908 909
}
EXPORT_SYMBOL(cfg80211_disconnected);

910 911 912
/*
 * API calls for nl80211/wext compatibility code
 */
913 914 915 916 917
int cfg80211_connect(struct cfg80211_registered_device *rdev,
		     struct net_device *dev,
		     struct cfg80211_connect_params *connect,
		     struct cfg80211_cached_keys *connkeys,
		     const u8 *prev_bssid)
S
Samuel Ortiz 已提交
918 919
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
J
Johannes Berg 已提交
920 921 922
	int err;

	ASSERT_WDEV_LOCK(wdev);
S
Samuel Ortiz 已提交
923

J
Johannes Berg 已提交
924 925 926 927 928
	if (WARN_ON(wdev->connect_keys)) {
		kfree(wdev->connect_keys);
		wdev->connect_keys = NULL;
	}

929 930 931
	cfg80211_oper_and_ht_capa(&connect->ht_capa_mask,
				  rdev->wiphy.ht_capa_mod_mask);

J
Johannes Berg 已提交
932 933
	if (connkeys && connkeys->def >= 0) {
		int idx;
S
Samuel Ortiz 已提交
934
		u32 cipher;
J
Johannes Berg 已提交
935 936

		idx = connkeys->def;
S
Samuel Ortiz 已提交
937
		cipher = connkeys->params[idx].cipher;
J
Johannes Berg 已提交
938
		/* If given a WEP key we may need it for shared key auth */
S
Samuel Ortiz 已提交
939 940
		if (cipher == WLAN_CIPHER_SUITE_WEP40 ||
		    cipher == WLAN_CIPHER_SUITE_WEP104) {
J
Johannes Berg 已提交
941 942 943
			connect->key_idx = idx;
			connect->key = connkeys->params[idx].key;
			connect->key_len = connkeys->params[idx].key_len;
S
Samuel Ortiz 已提交
944 945 946 947 948 949 950 951 952 953 954 955

			/*
			 * If ciphers are not set (e.g. when going through
			 * iwconfig), we have to set them appropriately here.
			 */
			if (connect->crypto.cipher_group == 0)
				connect->crypto.cipher_group = cipher;

			if (connect->crypto.n_ciphers_pairwise == 0) {
				connect->crypto.n_ciphers_pairwise = 1;
				connect->crypto.ciphers_pairwise[0] = cipher;
			}
J
Johannes Berg 已提交
956 957 958
		}
	}

959 960 961
	wdev->connect_keys = connkeys;
	memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
	wdev->ssid_len = connect->ssid_len;
962

963 964 965
	if (!rdev->ops->connect)
		err = cfg80211_sme_connect(wdev, connect, prev_bssid);
	else
966
		err = rdev_connect(rdev, dev, connect);
S
Samuel Ortiz 已提交
967

968 969 970 971
	if (err) {
		wdev->connect_keys = NULL;
		wdev->ssid_len = 0;
		return err;
972
	}
973 974

	return 0;
S
Samuel Ortiz 已提交
975 976
}

977 978
int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
			struct net_device *dev, u16 reason, bool wextev)
S
Samuel Ortiz 已提交
979
{
980
	struct wireless_dev *wdev = dev->ieee80211_ptr;
981
	int err = 0;
S
Samuel Ortiz 已提交
982

J
Johannes Berg 已提交
983 984
	ASSERT_WDEV_LOCK(wdev);

J
Johannes Berg 已提交
985 986 987
	kfree(wdev->connect_keys);
	wdev->connect_keys = NULL;

988
	if (wdev->conn)
989
		err = cfg80211_sme_disconnect(wdev, reason);
990
	else if (!rdev->ops->disconnect)
991
		cfg80211_mlme_down(rdev, dev);
992
	else if (wdev->current_bss)
993
		err = rdev_disconnect(rdev, dev, reason);
S
Samuel Ortiz 已提交
994

995
	return err;
J
Johannes Berg 已提交
996
}