All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

mlme.c 123 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * BSS client mode implementation
 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
 * Copyright 2004, Instant802 Networks, Inc.
 * Copyright 2005, Devicescape Software, Inc.
 * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

/* TODO:
 * order BSS list by RSSI(?) ("quality of AP")
 * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
 *    SSID)
 */
19
#include <linux/delay.h>
20 21 22 23 24 25 26
#include <linux/if_ether.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/random.h>
#include <linux/etherdevice.h>
27
#include <linux/rtnetlink.h>
28 29 30 31 32
#include <net/iw_handler.h>
#include <asm/types.h>

#include <net/mac80211.h>
#include "ieee80211_i.h"
Johannes Berg's avatar
Johannes Berg committed
33 34
#include "rate.h"
#include "led.h"
35
#include "mesh.h"
36 37 38 39 40 41

#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_MAX_TRIES 3
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
42
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
43 44 45 46
#define IEEE80211_PROBE_INTERVAL (60 * HZ)
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
47
#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
48 49 50 51 52 53 54

#define IEEE80211_PROBE_DELAY (HZ / 33)
#define IEEE80211_CHANNEL_TIME (HZ / 33)
#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
55
#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
56 57 58 59 60 61

#define IEEE80211_IBSS_MAX_STA_ENTRIES 128


#define ERP_INFO_USE_PROTECTION BIT(1)

62 63 64 65 66 67
/* mgmt header + 1 byte action code */
#define IEEE80211_MIN_ACTION_SIZE (24 + 1)

#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
68 69
#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
70

71 72 73 74 75
/* next values represent the buffer size for A-MPDU frame.
 * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */
#define IEEE80211_MIN_AMPDU_BUF 0x8
#define IEEE80211_MAX_AMPDU_BUF 0x40

76
static void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
77 78
				     u8 *ssid, size_t ssid_len);
static struct ieee80211_sta_bss *
79
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
80
		     u8 *ssid, u8 ssid_len);
81
static void ieee80211_rx_bss_put(struct ieee80211_local *local,
82
				 struct ieee80211_sta_bss *bss);
83
static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata,
84
				   struct ieee80211_if_sta *ifsta);
85 86
static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata);
static int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *sdata,
87
				    u8 *ssid, size_t ssid_len);
88
static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
89
				     struct ieee80211_if_sta *ifsta);
90
static void sta_rx_agg_session_timer_expired(unsigned long data);
91 92


93 94
void ieee802_11_parse_elems(u8 *start, size_t len,
			    struct ieee802_11_elems *elems)
95 96 97 98 99 100 101 102 103 104 105 106 107
{
	size_t left = len;
	u8 *pos = start;

	memset(elems, 0, sizeof(*elems));

	while (left >= 2) {
		u8 id, elen;

		id = *pos++;
		elen = *pos++;
		left -= 2;

108 109
		if (elen > left)
			return;
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174

		switch (id) {
		case WLAN_EID_SSID:
			elems->ssid = pos;
			elems->ssid_len = elen;
			break;
		case WLAN_EID_SUPP_RATES:
			elems->supp_rates = pos;
			elems->supp_rates_len = elen;
			break;
		case WLAN_EID_FH_PARAMS:
			elems->fh_params = pos;
			elems->fh_params_len = elen;
			break;
		case WLAN_EID_DS_PARAMS:
			elems->ds_params = pos;
			elems->ds_params_len = elen;
			break;
		case WLAN_EID_CF_PARAMS:
			elems->cf_params = pos;
			elems->cf_params_len = elen;
			break;
		case WLAN_EID_TIM:
			elems->tim = pos;
			elems->tim_len = elen;
			break;
		case WLAN_EID_IBSS_PARAMS:
			elems->ibss_params = pos;
			elems->ibss_params_len = elen;
			break;
		case WLAN_EID_CHALLENGE:
			elems->challenge = pos;
			elems->challenge_len = elen;
			break;
		case WLAN_EID_WPA:
			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
			    pos[2] == 0xf2) {
				/* Microsoft OUI (00:50:F2) */
				if (pos[3] == 1) {
					/* OUI Type 1 - WPA IE */
					elems->wpa = pos;
					elems->wpa_len = elen;
				} else if (elen >= 5 && pos[3] == 2) {
					if (pos[4] == 0) {
						elems->wmm_info = pos;
						elems->wmm_info_len = elen;
					} else if (pos[4] == 1) {
						elems->wmm_param = pos;
						elems->wmm_param_len = elen;
					}
				}
			}
			break;
		case WLAN_EID_RSN:
			elems->rsn = pos;
			elems->rsn_len = elen;
			break;
		case WLAN_EID_ERP_INFO:
			elems->erp_info = pos;
			elems->erp_info_len = elen;
			break;
		case WLAN_EID_EXT_SUPP_RATES:
			elems->ext_supp_rates = pos;
			elems->ext_supp_rates_len = elen;
			break;
175 176 177 178 179 180 181 182
		case WLAN_EID_HT_CAPABILITY:
			elems->ht_cap_elem = pos;
			elems->ht_cap_elem_len = elen;
			break;
		case WLAN_EID_HT_EXTRA_INFO:
			elems->ht_info_elem = pos;
			elems->ht_info_elem_len = elen;
			break;
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
		case WLAN_EID_MESH_ID:
			elems->mesh_id = pos;
			elems->mesh_id_len = elen;
			break;
		case WLAN_EID_MESH_CONFIG:
			elems->mesh_config = pos;
			elems->mesh_config_len = elen;
			break;
		case WLAN_EID_PEER_LINK:
			elems->peer_link = pos;
			elems->peer_link_len = elen;
			break;
		case WLAN_EID_PREQ:
			elems->preq = pos;
			elems->preq_len = elen;
			break;
		case WLAN_EID_PREP:
			elems->prep = pos;
			elems->prep_len = elen;
			break;
		case WLAN_EID_PERR:
			elems->perr = pos;
			elems->perr_len = elen;
			break;
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
		case WLAN_EID_CHANNEL_SWITCH:
			elems->ch_switch_elem = pos;
			elems->ch_switch_elem_len = elen;
			break;
		case WLAN_EID_QUIET:
			if (!elems->quiet_elem) {
				elems->quiet_elem = pos;
				elems->quiet_elem_len = elen;
			}
			elems->num_of_quiet_elem++;
			break;
		case WLAN_EID_COUNTRY:
			elems->country_elem = pos;
			elems->country_elem_len = elen;
			break;
		case WLAN_EID_PWR_CONSTRAINT:
			elems->pwr_constr_elem = pos;
			elems->pwr_constr_elem_len = elen;
			break;
226 227 228 229 230 231 232 233 234 235 236 237
		default:
			break;
		}

		left -= elen;
		pos += elen;
	}
}


static int ecw2cw(int ecw)
{
238
	return (1 << ecw) - 1;
239 240
}

241

242
static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
					 struct ieee80211_sta_bss *bss,
					 int ibss)
{
	struct ieee80211_local *local = sdata->local;
	int i, have_higher_than_11mbit = 0;


	/* cf. IEEE 802.11 9.2.12 */
	for (i = 0; i < bss->supp_rates_len; i++)
		if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
			have_higher_than_11mbit = 1;

	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
	    have_higher_than_11mbit)
		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
	else
		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;


	if (local->ops->conf_tx) {
		struct ieee80211_tx_queue_params qparam;

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

		qparam.aifs = 2;

		if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
		    !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
			qparam.cw_min = 31;
		else
			qparam.cw_min = 15;

		qparam.cw_max = 1023;
		qparam.txop = 0;

Johannes Berg's avatar
Johannes Berg committed
278 279
		for (i = 0; i < local_to_hw(local)->queues; i++)
			local->ops->conf_tx(local_to_hw(local), i, &qparam);
280 281 282
	}
}

283
static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
284 285 286 287 288 289 290 291
				     struct ieee80211_if_sta *ifsta,
				     u8 *wmm_param, size_t wmm_param_len)
{
	struct ieee80211_tx_queue_params params;
	size_t left;
	int count;
	u8 *pos;

292 293 294 295 296 297
	if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
		return;

	if (!wmm_param)
		return;

298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
		return;
	count = wmm_param[6] & 0x0f;
	if (count == ifsta->wmm_last_param_set)
		return;
	ifsta->wmm_last_param_set = count;

	pos = wmm_param + 8;
	left = wmm_param_len - 8;

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

	if (!local->ops->conf_tx)
		return;

	local->wmm_acm = 0;
	for (; left >= 4; left -= 4, pos += 4) {
		int aci = (pos[0] >> 5) & 0x03;
		int acm = (pos[0] >> 4) & 0x01;
		int queue;

		switch (aci) {
		case 1:
Johannes Berg's avatar
Johannes Berg committed
321
			queue = 3;
Johannes Berg's avatar
Johannes Berg committed
322
			if (acm)
323 324 325
				local->wmm_acm |= BIT(0) | BIT(3);
			break;
		case 2:
Johannes Berg's avatar
Johannes Berg committed
326
			queue = 1;
Johannes Berg's avatar
Johannes Berg committed
327
			if (acm)
328 329 330
				local->wmm_acm |= BIT(4) | BIT(5);
			break;
		case 3:
Johannes Berg's avatar
Johannes Berg committed
331
			queue = 0;
Johannes Berg's avatar
Johannes Berg committed
332
			if (acm)
333 334 335 336
				local->wmm_acm |= BIT(6) | BIT(7);
			break;
		case 0:
		default:
Johannes Berg's avatar
Johannes Berg committed
337
			queue = 2;
Johannes Berg's avatar
Johannes Berg committed
338
			if (acm)
339 340 341 342 343 344 345
				local->wmm_acm |= BIT(1) | BIT(2);
			break;
		}

		params.aifs = pos[0] & 0x0f;
		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
		params.cw_min = ecw2cw(pos[1] & 0x0f);
346
		params.txop = get_unaligned_le16(pos + 2);
347
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
348
		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
349
		       "cWmin=%d cWmax=%d txop=%d\n",
350
		       local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
351 352
		       params.cw_max, params.txop);
#endif
353 354 355 356
		/* TODO: handle ACM (block TX, fallback to next lowest allowed
		 * AC for now) */
		if (local->ops->conf_tx(local_to_hw(local), queue, &params)) {
			printk(KERN_DEBUG "%s: failed to set TX queue "
357
			       "parameters for queue %d\n", local->mdev->name, queue);
358 359 360 361
		}
	}
}

362 363 364
static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
					   bool use_protection,
					   bool use_short_preamble)
365
{
366
	struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
367
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
368
	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
369
	DECLARE_MAC_BUF(mac);
370
#endif
371
	u32 changed = 0;
372

373
	if (use_protection != bss_conf->use_cts_prot) {
374
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
375 376
		if (net_ratelimit()) {
			printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
377
			       "%s)\n",
378
			       sdata->dev->name,
379
			       use_protection ? "enabled" : "disabled",
380
			       print_mac(mac, ifsta->bssid));
381
		}
382
#endif
383 384
		bss_conf->use_cts_prot = use_protection;
		changed |= BSS_CHANGED_ERP_CTS_PROT;
385
	}
386

387
	if (use_short_preamble != bss_conf->use_short_preamble) {
388
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
389 390
		if (net_ratelimit()) {
			printk(KERN_DEBUG "%s: switched to %s barker preamble"
391
			       " (BSSID=%s)\n",
392
			       sdata->dev->name,
393
			       use_short_preamble ? "short" : "long",
394
			       print_mac(mac, ifsta->bssid));
395
		}
396
#endif
397
		bss_conf->use_short_preamble = use_short_preamble;
398
		changed |= BSS_CHANGED_ERP_PREAMBLE;
399
	}
400

401
	return changed;
402 403
}

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
				   u8 erp_value)
{
	bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
	bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;

	return ieee80211_handle_protect_preamb(sdata,
			use_protection, use_short_preamble);
}

static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
					   struct ieee80211_sta_bss *bss)
{
	u32 changed = 0;

	if (bss->has_erp_value)
		changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value);
	else {
		u16 capab = bss->capability;
		changed |= ieee80211_handle_protect_preamb(sdata, false,
				(capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
	}

	return changed;
}

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
int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
				   struct ieee80211_ht_info *ht_info)
{

	if (ht_info == NULL)
		return -EINVAL;

	memset(ht_info, 0, sizeof(*ht_info));

	if (ht_cap_ie) {
		u8 ampdu_info = ht_cap_ie->ampdu_params_info;

		ht_info->ht_supported = 1;
		ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
		ht_info->ampdu_factor =
			ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
		ht_info->ampdu_density =
			(ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
		memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
	} else
		ht_info->ht_supported = 0;

	return 0;
}

int ieee80211_ht_addt_info_ie_to_ht_bss_info(
			struct ieee80211_ht_addt_info *ht_add_info_ie,
			struct ieee80211_ht_bss_info *bss_info)
{
	if (bss_info == NULL)
		return -EINVAL;

	memset(bss_info, 0, sizeof(*bss_info));

	if (ht_add_info_ie) {
		u16 op_mode;
		op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);

		bss_info->primary_channel = ht_add_info_ie->control_chan;
		bss_info->bss_cap = ht_add_info_ie->ht_param;
		bss_info->bss_op_mode = (u8)(op_mode & 0xff);
	}

	return 0;
}
475

476
static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata,
477 478 479 480 481 482 483 484 485 486 487
					 struct ieee80211_if_sta *ifsta)
{
	char *buf;
	size_t len;
	int i;
	union iwreq_data wrqu;

	if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
		return;

	buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
488
				ifsta->assocresp_ies_len), GFP_KERNEL);
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
	if (!buf)
		return;

	len = sprintf(buf, "ASSOCINFO(");
	if (ifsta->assocreq_ies) {
		len += sprintf(buf + len, "ReqIEs=");
		for (i = 0; i < ifsta->assocreq_ies_len; i++) {
			len += sprintf(buf + len, "%02x",
				       ifsta->assocreq_ies[i]);
		}
	}
	if (ifsta->assocresp_ies) {
		if (ifsta->assocreq_ies)
			len += sprintf(buf + len, " ");
		len += sprintf(buf + len, "RespIEs=");
		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
			len += sprintf(buf + len, "%02x",
				       ifsta->assocresp_ies[i]);
		}
	}
	len += sprintf(buf + len, ")");

	if (len > IW_CUSTOM_MAX) {
		len = sprintf(buf, "ASSOCRESPIE=");
		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
			len += sprintf(buf + len, "%02x",
				       ifsta->assocresp_ies[i]);
		}
	}

	memset(&wrqu, 0, sizeof(wrqu));
	wrqu.data.length = len;
521
	wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
522 523 524 525 526

	kfree(buf);
}


527
static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
528
				     struct ieee80211_if_sta *ifsta,
529
				     bool assoc)
530
{
531
	struct ieee80211_local *local = sdata->local;
Tomas Winkler's avatar
Tomas Winkler committed
532
	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
533
	union iwreq_data wrqu;
534
	u32 changed = BSS_CHANGED_ASSOC;
535 536

	if (assoc) {
537
		struct ieee80211_sta_bss *bss;
538 539 540

		ifsta->flags |= IEEE80211_STA_ASSOCIATED;

541
		if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
542
			return;
543

544
		bss = ieee80211_rx_bss_get(local, ifsta->bssid,
Tomas Winkler's avatar
Tomas Winkler committed
545
					   conf->channel->center_freq,
546
					   ifsta->ssid, ifsta->ssid_len);
547
		if (bss) {
548 549 550
			/* set timing information */
			sdata->bss_conf.beacon_int = bss->beacon_int;
			sdata->bss_conf.timestamp = bss->timestamp;
551
			sdata->bss_conf.dtim_period = bss->dtim_period;
552

553
			changed |= ieee80211_handle_bss_capability(sdata, bss);
554

555
			ieee80211_rx_bss_put(local, bss);
556 557
		}

Tomas Winkler's avatar
Tomas Winkler committed
558 559 560 561 562 563 564
		if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
			changed |= BSS_CHANGED_HT;
			sdata->bss_conf.assoc_ht = 1;
			sdata->bss_conf.ht_conf = &conf->ht_conf;
			sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
		}

565
		ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
566 567
		memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
		memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
568
		ieee80211_sta_send_associnfo(sdata, ifsta);
569
	} else {
570 571
		netif_carrier_off(sdata->dev);
		ieee80211_sta_tear_down_BA_sessions(sdata, ifsta->bssid);
572
		ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
573
		changed |= ieee80211_reset_erp_info(sdata);
Tomas Winkler's avatar
Tomas Winkler committed
574 575 576 577 578

		sdata->bss_conf.assoc_ht = 0;
		sdata->bss_conf.ht_conf = NULL;
		sdata->bss_conf.ht_bss_conf = NULL;

579 580 581
		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
	}
	ifsta->last_probe = jiffies;
582
	ieee80211_led_assoc(local, assoc);
583

584
	sdata->bss_conf.assoc = assoc;
585
	ieee80211_bss_info_change_notify(sdata, changed);
586 587

	if (assoc)
588
		netif_carrier_on(sdata->dev);
589

590
	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
591
	wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
592 593
}

594
static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
595 596 597 598 599
				   struct ieee80211_if_sta *ifsta, int deauth)
{
	if (deauth)
		ifsta->auth_tries = 0;
	ifsta->assoc_tries = 0;
600
	ieee80211_set_associated(sdata, ifsta, 0);
601 602
}

603
void ieee80211_sta_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
604
		      int encrypt)
605 606 607 608 609 610
{
	skb->dev = sdata->local->mdev;
	skb_set_mac_header(skb, 0);
	skb_set_network_header(skb, 0);
	skb_set_transport_header(skb, 0);

611 612
	skb->iif = sdata->dev->ifindex;
	skb->do_not_encrypt = !encrypt;
613 614 615 616 617

	dev_queue_xmit(skb);
}


618
static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
619 620 621 622
				struct ieee80211_if_sta *ifsta,
				int transaction, u8 *extra, size_t extra_len,
				int encrypt)
{
623
	struct ieee80211_local *local = sdata->local;
624 625 626 627 628 629 630
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;

	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
			    sizeof(*mgmt) + 6 + extra_len);
	if (!skb) {
		printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
631
		       "frame\n", sdata->dev->name);
632 633 634 635 636 637
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
	memset(mgmt, 0, 24 + 6);
638 639
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
					  IEEE80211_STYPE_AUTH);
640 641 642
	if (encrypt)
		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
643
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
644 645 646 647 648 649 650 651
	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
	mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);
	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
	ifsta->auth_transaction = transaction + 1;
	mgmt->u.auth.status_code = cpu_to_le16(0);
	if (extra)
		memcpy(skb_put(skb, extra_len), extra, extra_len);

652
	ieee80211_sta_tx(sdata, skb, encrypt);
653 654 655
}


656
static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
657 658
				   struct ieee80211_if_sta *ifsta)
{
659 660
	DECLARE_MAC_BUF(mac);

661 662
	ifsta->auth_tries++;
	if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
663
		printk(KERN_DEBUG "%s: authentication with AP %s"
664
		       " timed out\n",
665
		       sdata->dev->name, print_mac(mac, ifsta->bssid));
666
		ifsta->state = IEEE80211_STA_MLME_DISABLED;
667 668 669
		return;
	}

670
	ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
671
	printk(KERN_DEBUG "%s: authenticate with AP %s\n",
672
	       sdata->dev->name, print_mac(mac, ifsta->bssid));
673

674
	ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0);
675 676 677 678

	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
}

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
				      struct ieee80211_supported_band *sband,
				      u64 *rates)
{
	int i, j, count;
	*rates = 0;
	count = 0;
	for (i = 0; i < bss->supp_rates_len; i++) {
		int rate = (bss->supp_rates[i] & 0x7F) * 5;

		for (j = 0; j < sband->n_bitrates; j++)
			if (sband->bitrates[j].bitrate == rate) {
				*rates |= BIT(j);
				count++;
				break;
			}
	}

	return count;
}
699

700
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
701 702
				 struct ieee80211_if_sta *ifsta)
{
703
	struct ieee80211_local *local = sdata->local;
704 705 706
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;
	u8 *pos, *ies;
707
	int i, len, count, rates_len, supp_rates_len;
708 709 710
	u16 capab;
	struct ieee80211_sta_bss *bss;
	int wmm = 0;
711
	struct ieee80211_supported_band *sband;
712
	u64 rates = 0;
713 714 715 716 717 718

	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
			    sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
			    ifsta->ssid_len);
	if (!skb) {
		printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
719
		       "frame\n", sdata->dev->name);
720 721 722 723
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

724 725
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];

726
	capab = ifsta->capab;
727 728 729 730 731 732

	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
			capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
			capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
733
	}
734

735
	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
736
				   local->hw.conf.channel->center_freq,
737
				   ifsta->ssid, ifsta->ssid_len);
738 739 740
	if (bss) {
		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
			capab |= WLAN_CAPABILITY_PRIVACY;
Johannes Berg's avatar
Johannes Berg committed
741
		if (bss->wmm_ie)
742
			wmm = 1;
743 744 745 746 747 748 749

		/* get all rates supported by the device and the AP as
		 * some APs don't like getting a superset of their rates
		 * in the association request (e.g. D-Link DAP 1353 in
		 * b-only mode) */
		rates_len = ieee80211_compatible_rates(bss, sband, &rates);

750 751 752 753
		if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
		    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
			capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;

754
		ieee80211_rx_bss_put(local, bss);
755 756 757
	} else {
		rates = ~0;
		rates_len = sband->n_bitrates;
758 759 760 761 762
	}

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
	memset(mgmt, 0, 24);
	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
763
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
764 765
	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);

766
	if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
767
		skb_put(skb, 10);
768 769
		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
						  IEEE80211_STYPE_REASSOC_REQ);
770
		mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
771 772
		mgmt->u.reassoc_req.listen_interval =
				cpu_to_le16(local->hw.conf.listen_interval);
773 774 775 776
		memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid,
		       ETH_ALEN);
	} else {
		skb_put(skb, 4);
777 778
		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
						  IEEE80211_STYPE_ASSOC_REQ);
779
		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
780 781
		mgmt->u.reassoc_req.listen_interval =
				cpu_to_le16(local->hw.conf.listen_interval);
782 783 784 785 786 787 788 789
	}

	/* SSID */
	ies = pos = skb_put(skb, 2 + ifsta->ssid_len);
	*pos++ = WLAN_EID_SSID;
	*pos++ = ifsta->ssid_len;
	memcpy(pos, ifsta->ssid, ifsta->ssid_len);

790
	/* add all rates which were marked to be used above */
791 792 793 794
	supp_rates_len = rates_len;
	if (supp_rates_len > 8)
		supp_rates_len = 8;

795
	len = sband->n_bitrates;
796
	pos = skb_put(skb, supp_rates_len + 2);
797
	*pos++ = WLAN_EID_SUPP_RATES;
798
	*pos++ = supp_rates_len;
799

800 801 802
	count = 0;
	for (i = 0; i < sband->n_bitrates; i++) {
		if (BIT(i) & rates) {
803
			int rate = sband->bitrates[i].bitrate;
804
			*pos++ = (u8) (rate / 5);
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
			if (++count == 8)
				break;
		}
	}

	if (count == 8) {
		pos = skb_put(skb, rates_len - count + 2);
		*pos++ = WLAN_EID_EXT_SUPP_RATES;
		*pos++ = rates_len - count;

		for (i++; i < sband->n_bitrates; i++) {
			if (BIT(i) & rates) {
				int rate = sband->bitrates[i].bitrate;
				*pos++ = (u8) (rate / 5);
			}
820 821 822
		}
	}

823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
		/* 1. power capabilities */
		pos = skb_put(skb, 4);
		*pos++ = WLAN_EID_PWR_CAPABILITY;
		*pos++ = 2;
		*pos++ = 0; /* min tx power */
		*pos++ = local->hw.conf.channel->max_power; /* max tx power */

		/* 2. supported channels */
		/* TODO: get this in reg domain format */
		pos = skb_put(skb, 2 * sband->n_channels + 2);
		*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
		*pos++ = 2 * sband->n_channels;
		for (i = 0; i < sband->n_channels; i++) {
			*pos++ = ieee80211_frequency_to_channel(
					sband->channels[i].center_freq);
			*pos++ = 1; /* one channel in the subband*/
		}
	}

843 844 845 846 847
	if (ifsta->extra_ie) {
		pos = skb_put(skb, ifsta->extra_ie_len);
		memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
	}

848
	if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
849 850 851 852 853 854 855 856 857 858 859
		pos = skb_put(skb, 9);
		*pos++ = WLAN_EID_VENDOR_SPECIFIC;
		*pos++ = 7; /* len */
		*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
		*pos++ = 0x50;
		*pos++ = 0xf2;
		*pos++ = 2; /* WME */
		*pos++ = 0; /* WME info */
		*pos++ = 1; /* WME ver */
		*pos++ = 0;
	}
860

861
	/* wmm support is a must to HT */
862
	if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
	    sband->ht_info.ht_supported && bss->ht_add_ie) {
		struct ieee80211_ht_addt_info *ht_add_info =
			(struct ieee80211_ht_addt_info *)bss->ht_add_ie;
		u16 cap = sband->ht_info.cap;
		__le16 tmp;
		u32 flags = local->hw.conf.channel->flags;

		switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
		case IEEE80211_HT_IE_CHA_SEC_ABOVE:
			if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
				cap &= ~IEEE80211_HT_CAP_SGI_40;
			}
			break;
		case IEEE80211_HT_IE_CHA_SEC_BELOW:
			if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
				cap &= ~IEEE80211_HT_CAP_SGI_40;
			}
			break;
		}

		tmp = cpu_to_le16(cap);
886 887 888 889 890 891
		pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
		*pos++ = WLAN_EID_HT_CAPABILITY;
		*pos++ = sizeof(struct ieee80211_ht_cap);
		memset(pos, 0, sizeof(struct ieee80211_ht_cap));
		memcpy(pos, &tmp, sizeof(u16));
		pos += sizeof(u16);
892 893 894 895
		/* TODO: needs a define here for << 2 */
		*pos++ = sband->ht_info.ampdu_factor |
			 (sband->ht_info.ampdu_density << 2);
		memcpy(pos, sband->ht_info.supp_mcs_set, 16);
896
	}
897 898 899

	kfree(ifsta->assocreq_ies);
	ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
900
	ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL);
901 902 903
	if (ifsta->assocreq_ies)
		memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);

904
	ieee80211_sta_tx(sdata, skb, 0);
905 906 907
}


908
static void ieee80211_send_deauth(struct ieee80211_sub_if_data *sdata,
909 910
				  struct ieee80211_if_sta *ifsta, u16 reason)
{
911
	struct ieee80211_local *local = sdata->local;
912 913 914 915 916 917
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;

	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
	if (!skb) {
		printk(KERN_DEBUG "%s: failed to allocate buffer for deauth "
918
		       "frame\n", sdata->dev->name);
919 920 921 922 923 924 925
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
	memset(mgmt, 0, 24);
	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
926
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
927
	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
928 929
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
					  IEEE80211_STYPE_DEAUTH);
930 931 932
	skb_put(skb, 2);
	mgmt->u.deauth.reason_code = cpu_to_le16(reason);

933
	ieee80211_sta_tx(sdata, skb, 0);
934 935 936
}


937
static void ieee80211_send_disassoc(struct ieee80211_sub_if_data *sdata,
938 939
				    struct ieee80211_if_sta *ifsta, u16 reason)
{
940
	struct ieee80211_local *local = sdata->local;
941 942 943 944 945 946
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;

	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
	if (!skb) {
		printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc "
947
		       "frame\n", sdata->dev->name);
948 949 950 951 952 953 954
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
	memset(mgmt, 0, 24);
	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
955
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
956
	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
957 958
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
					  IEEE80211_STYPE_DISASSOC);
959 960 961
	skb_put(skb, 2);
	mgmt->u.disassoc.reason_code = cpu_to_le16(reason);

962
	ieee80211_sta_tx(sdata, skb, 0);
963 964 965
}


966
static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata,
967 968
				      struct ieee80211_if_sta *ifsta)
{
969
	struct ieee80211_local *local = sdata->local;
970
	struct ieee80211_sta_bss *bss;
971 972 973
	int bss_privacy;
	int wep_privacy;
	int privacy_invoked;
974

975
	if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
976 977
		return 0;

978
	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
979
				   local->hw.conf.channel->center_freq,
980
				   ifsta->ssid, ifsta->ssid_len);
981 982 983
	if (!bss)
		return 0;

984
	bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
985
	wep_privacy = !!ieee80211_sta_wep_configured(sdata);
986
	privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
987

988
	ieee80211_rx_bss_put(local, bss);
989

990 991 992 993
	if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
		return 0;

	return 1;
994 995 996
}


997
static void ieee80211_associate(struct ieee80211_sub_if_data *sdata,
998 999
				struct ieee80211_if_sta *ifsta)
{
1000 1001
	DECLARE_MAC_BUF(mac);

1002 1003
	ifsta->assoc_tries++;
	if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
1004
		printk(KERN_DEBUG "%s: association with AP %s"
1005
		       " timed out\n",
1006
		       sdata->dev->name, print_mac(mac, ifsta->bssid));
1007
		ifsta->state = IEEE80211_STA_MLME_DISABLED;
1008 1009 1010
		return;
	}

1011
	ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
1012
	printk(KERN_DEBUG "%s: associate with AP %s\n",
1013 1014
	       sdata->dev->name, print_mac(mac, ifsta->bssid));
	if (ieee80211_privacy_mismatch(sdata, ifsta)) {
1015
		printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
1016
		       "mixed-cell disabled - abort association\n", sdata->dev->name);
1017
		ifsta->state = IEEE80211_STA_MLME_DISABLED;
1018 1019 1020
		return;
	}

1021
	ieee80211_send_assoc(sdata, ifsta);
1022 1023 1024 1025 1026

	mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
}


1027
static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
1028 1029
				 struct ieee80211_if_sta *ifsta)
{
1030
	struct ieee80211_local *local = sdata->local;
1031 1032
	struct sta_info *sta;
	int disassoc;
1033
	DECLARE_MAC_BUF(mac);
1034 1035 1036 1037 1038 1039

	/* TODO: start monitoring current AP signal quality and number of
	 * missed beacons. Scan other channels every now and then and search
	 * for better APs. */
	/* TODO: remove expired BSSes */

1040
	ifsta->state = IEEE80211_STA_MLME_ASSOCIATED;
1041

1042 1043
	rcu_read_lock();

1044 1045
	sta = sta_info_get(local, ifsta->bssid);
	if (!sta) {
1046
		printk(KERN_DEBUG "%s: No STA entry for own AP %s\n",
1047
		       sdata->dev->name, print_mac(mac, ifsta->bssid));
1048 1049 1050 1051 1052
		disassoc = 1;
	} else {
		disassoc = 0;
		if (time_after(jiffies,
			       sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
1053
			if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) {
1054
				printk(KERN_DEBUG "%s: No ProbeResp from "
1055
				       "current AP %s - assume out of "
1056
				       "range\n",
1057
				       sdata->dev->name, print_mac(mac, ifsta->bssid));
1058
				disassoc = 1;
1059
				sta_info_unlink(&sta);
1060
			} else
1061
				ieee80211_send_probe_req(sdata, ifsta->bssid,
1062 1063
							 local->scan_ssid,
							 local->scan_ssid_len);
1064
			ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL;
1065
		} else {
1066
			ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
1067 1068 1069
			if (time_after(jiffies, ifsta->last_probe +
				       IEEE80211_PROBE_INTERVAL)) {
				ifsta->last_probe = jiffies;
1070
				ieee80211_send_probe_req(sdata, ifsta->bssid,
1071 1072 1073 1074 1075
							 ifsta->ssid,
							 ifsta->ssid_len);
			}
		}
	}
1076 1077 1078

	rcu_read_unlock();

1079
	if (disassoc && sta)
1080 1081
		sta_info_destroy(sta);

Jiri Benc's avatar