mlme.c 57.2 KB
Newer Older
1
2
/*
 * BSS client mode implementation
3
 * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
4
5
6
7
8
9
10
11
12
13
 * 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.
 */

14
#include <linux/delay.h>
15
16
17
18
#include <linux/if_ether.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
19
#include <linux/rtnetlink.h>
20
#include <net/mac80211.h>
21
#include <asm/unaligned.h>
Johannes Berg's avatar
Johannes Berg committed
22

23
#include "ieee80211_i.h"
Johannes Berg's avatar
Johannes Berg committed
24
25
#include "rate.h"
#include "led.h"
26

27
#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2
28
29
30
31
32
33
34
35
#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)
#define IEEE80211_PROBE_INTERVAL (60 * HZ)
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)

36
37
/* utils */
static int ecw2cw(int ecw)
Johannes Berg's avatar
Johannes Berg committed
38
{
39
	return (1 << ecw) - 1;
Johannes Berg's avatar
Johannes Berg committed
40
41
}

42
static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie)
43
44
45
{
	u8 *end, *pos;

46
	pos = bss->cbss.information_elements;
47
48
	if (pos == NULL)
		return NULL;
49
	end = pos + bss->cbss.len_information_elements;
50
51
52
53
54
55
56
57
58
59
60
61

	while (pos + 1 < end) {
		if (pos + 2 + pos[1] > end)
			break;
		if (pos[0] == ie)
			return pos;
		pos += 2 + pos[1];
	}

	return NULL;
}

62
static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
63
				      struct ieee80211_supported_band *sband,
64
				      u32 *rates)
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
{
	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;
}

83
84
/* frame sending functions */

85
86
87
88
89
90
static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len)
{
	if (ies)
		memcpy(skb_put(skb, ies_len), ies, ies_len);
}

91
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
92
{
93
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
94
95
96
	struct ieee80211_local *local = sdata->local;
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;
97
	u8 *pos, *ies, *ht_ie, *e_ies;
98
99
	int i, len, count, rates_len, supp_rates_len;
	u16 capab;
100
	struct ieee80211_bss *bss;
101
102
	int wmm = 0;
	struct ieee80211_supported_band *sband;
103
	u32 rates = 0;
104
105
	size_t e_ies_len;

106
	if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) {
107
108
		e_ies = sdata->u.mgd.ie_reassocreq;
		e_ies_len = sdata->u.mgd.ie_reassocreq_len;
109
	} else {
110
111
		e_ies = sdata->u.mgd.ie_assocreq;
		e_ies_len = sdata->u.mgd.ie_assocreq_len;
112
	}
113
114

	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
115
116
			    sizeof(*mgmt) + 200 + ifmgd->extra_ie_len +
			    ifmgd->ssid_len + e_ies_len);
117
118
119
120
121
122
123
124
125
	if (!skb) {
		printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
		       "frame\n", sdata->dev->name);
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

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

126
	capab = ifmgd->capab;
127
128
129
130
131
132
133
134

	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;
	}

135
	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
136
				   local->hw.conf.channel->center_freq,
137
				   ifmgd->ssid, ifmgd->ssid_len);
138
	if (bss) {
139
		if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
140
141
142
143
144
145
146
147
148
149
			capab |= WLAN_CAPABILITY_PRIVACY;
		if (bss->wmm_used)
			wmm = 1;

		/* 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);

150
		if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
151
152
153
154
155
156
157
158
159
160
161
		    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
			capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;

		ieee80211_rx_bss_put(local, bss);
	} else {
		rates = ~0;
		rates_len = sband->n_bitrates;
	}

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
	memset(mgmt, 0, 24);
162
	memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
163
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
164
	memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
165

166
	if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) {
167
168
169
170
171
172
		skb_put(skb, 10);
		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
						  IEEE80211_STYPE_REASSOC_REQ);
		mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
		mgmt->u.reassoc_req.listen_interval =
				cpu_to_le16(local->hw.conf.listen_interval);
173
		memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid,
174
175
176
177
178
179
		       ETH_ALEN);
	} else {
		skb_put(skb, 4);
		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
						  IEEE80211_STYPE_ASSOC_REQ);
		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
180
		mgmt->u.assoc_req.listen_interval =
181
182
183
184
				cpu_to_le16(local->hw.conf.listen_interval);
	}

	/* SSID */
185
	ies = pos = skb_put(skb, 2 + ifmgd->ssid_len);
186
	*pos++ = WLAN_EID_SSID;
187
188
	*pos++ = ifmgd->ssid_len;
	memcpy(pos, ifmgd->ssid, ifmgd->ssid_len);
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242

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

	len = sband->n_bitrates;
	pos = skb_put(skb, supp_rates_len + 2);
	*pos++ = WLAN_EID_SUPP_RATES;
	*pos++ = supp_rates_len;

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

	if (rates_len > count) {
		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);
			}
		}
	}

	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*/
		}
	}

243
244
245
	if (ifmgd->extra_ie) {
		pos = skb_put(skb, ifmgd->extra_ie_len);
		memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len);
246
247
	}

248
	if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) {
249
250
251
252
253
254
255
256
257
258
259
260
261
		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;
	}

	/* wmm support is a must to HT */
262
263
264
265
266
267
	/*
	 * IEEE802.11n does not allow TKIP/WEP as pairwise
	 * ciphers in HT mode. We still associate in non-ht
	 * mode (11a/b/g) if any one of these ciphers is
	 * configured as pairwise.
	 */
268
	if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
269
270
	    sband->ht_cap.ht_supported &&
	    (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) &&
271
	    ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&
272
	    (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) {
273
274
275
		struct ieee80211_ht_info *ht_info =
			(struct ieee80211_ht_info *)(ht_ie + 2);
		u16 cap = sband->ht_cap.cap;
276
277
278
		__le16 tmp;
		u32 flags = local->hw.conf.channel->flags;

279
280
		switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
281
			if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
282
				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
283
284
285
				cap &= ~IEEE80211_HT_CAP_SGI_40;
			}
			break;
286
		case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
287
			if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
288
				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
289
290
291
292
293
294
295
296
297
298
299
300
301
				cap &= ~IEEE80211_HT_CAP_SGI_40;
			}
			break;
		}

		tmp = cpu_to_le16(cap);
		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);
		/* TODO: needs a define here for << 2 */
302
303
304
		*pos++ = sband->ht_cap.ampdu_factor |
			 (sband->ht_cap.ampdu_density << 2);
		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
305
306
	}

307
308
	add_extra_ies(skb, e_ies, e_ies_len);

309
310
311
312
313
	kfree(ifmgd->assocreq_ies);
	ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies;
	ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL);
	if (ifmgd->assocreq_ies)
		memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len);
314

315
	ieee80211_tx_skb(sdata, skb, 0);
316
317
318
}


319
320
static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
					   u16 stype, u16 reason)
321
322
{
	struct ieee80211_local *local = sdata->local;
323
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
324
325
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;
326
327
	u8 *ies;
	size_t ies_len;
328

329
	if (stype == IEEE80211_STYPE_DEAUTH) {
330
331
		ies = sdata->u.mgd.ie_deauth;
		ies_len = sdata->u.mgd.ie_deauth_len;
332
	} else {
333
334
		ies = sdata->u.mgd.ie_disassoc;
		ies_len = sdata->u.mgd.ie_disassoc_len;
335
336
337
338
	}

	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) +
			    ies_len);
339
	if (!skb) {
340
341
		printk(KERN_DEBUG "%s: failed to allocate buffer for "
		       "deauth/disassoc frame\n", sdata->dev->name);
342
343
344
345
346
347
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
	memset(mgmt, 0, 24);
348
	memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
349
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
350
	memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
351
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
352
	skb_put(skb, 2);
353
	/* u.deauth.reason_code == u.disassoc.reason_code */
354
355
	mgmt->u.deauth.reason_code = cpu_to_le16(reason);

356
357
	add_extra_ies(skb, ies, ies_len);

358
	ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
359
360
}

361
362
363
void ieee80211_send_pspoll(struct ieee80211_local *local,
			   struct ieee80211_sub_if_data *sdata)
{
364
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
	struct ieee80211_pspoll *pspoll;
	struct sk_buff *skb;
	u16 fc;

	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
	if (!skb) {
		printk(KERN_DEBUG "%s: failed to allocate buffer for "
		       "pspoll frame\n", sdata->dev->name);
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

	pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
	memset(pspoll, 0, sizeof(*pspoll));
	fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;
	pspoll->frame_control = cpu_to_le16(fc);
381
	pspoll->aid = cpu_to_le16(ifmgd->aid);
382
383
384
385

	/* aid in PS-Poll has its two MSBs each set to 1 */
	pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);

386
	memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
387
388
389
390
391
	memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);

	ieee80211_tx_skb(sdata, skb, 0);
}

Johannes Berg's avatar
Johannes Berg committed
392
/* MLME */
393
static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
394
				     struct ieee80211_if_managed *ifmgd,
395
396
397
398
399
400
401
				     u8 *wmm_param, size_t wmm_param_len)
{
	struct ieee80211_tx_queue_params params;
	size_t left;
	int count;
	u8 *pos;

402
	if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED))
403
404
405
406
407
		return;

	if (!wmm_param)
		return;

408
409
410
	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
		return;
	count = wmm_param[6] & 0x0f;
411
	if (count == ifmgd->wmm_last_param_set)
412
		return;
413
	ifmgd->wmm_last_param_set = count;
414
415
416
417
418
419
420
421
422
423
424
425
426

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

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

	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) {
427
		case 1: /* AC_BK */
Johannes Berg's avatar
Johannes Berg committed
428
			queue = 3;
Johannes Berg's avatar
Johannes Berg committed
429
			if (acm)
430
				local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
431
			break;
432
		case 2: /* AC_VI */
Johannes Berg's avatar
Johannes Berg committed
433
			queue = 1;
Johannes Berg's avatar
Johannes Berg committed
434
			if (acm)
435
				local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
436
			break;
437
		case 3: /* AC_VO */
Johannes Berg's avatar
Johannes Berg committed
438
			queue = 0;
Johannes Berg's avatar
Johannes Berg committed
439
			if (acm)
440
				local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
441
			break;
442
		case 0: /* AC_BE */
443
		default:
Johannes Berg's avatar
Johannes Berg committed
444
			queue = 2;
Johannes Berg's avatar
Johannes Berg committed
445
			if (acm)
446
				local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
447
448
449
450
451
452
			break;
		}

		params.aifs = pos[0] & 0x0f;
		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
		params.cw_min = ecw2cw(pos[1] & 0x0f);
453
		params.txop = get_unaligned_le16(pos + 2);
454
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
455
		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
456
		       "cWmin=%d cWmax=%d txop=%d\n",
457
		       local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
458
459
		       params.cw_max, params.txop);
#endif
460
461
		if (local->ops->conf_tx &&
		    local->ops->conf_tx(local_to_hw(local), queue, &params)) {
462
			printk(KERN_DEBUG "%s: failed to set TX queue "
463
			       "parameters for queue %d\n", local->mdev->name, queue);
464
465
466
467
		}
	}
}

468
static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid)
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
{
	u8 mask;
	u8 index, indexn1, indexn2;
	struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim;

	aid &= 0x3fff;
	index = aid / 8;
	mask  = 1 << (aid & 7);

	indexn1 = tim->bitmap_ctrl & 0xfe;
	indexn2 = elems->tim_len + indexn1 - 4;

	if (index < indexn1 || index > indexn2)
		return false;

	index -= indexn1;

	return !!(tim->virtual_map[index] & mask);
}

489
490
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
					   u16 capab, bool erp_valid, u8 erp)
491
{
492
	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
493
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
494
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
495
#endif
496
	u32 changed = 0;
497
498
499
500
501
502
503
504
505
506
507
508
509
	bool use_protection;
	bool use_short_preamble;
	bool use_short_slot;

	if (erp_valid) {
		use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0;
		use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0;
	} else {
		use_protection = false;
		use_short_preamble = !!(capab & WLAN_CAPABILITY_SHORT_PREAMBLE);
	}

	use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
510

511
	if (use_protection != bss_conf->use_cts_prot) {
512
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
513
		if (net_ratelimit()) {
514
			printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n",
515
			       sdata->dev->name,
516
			       use_protection ? "enabled" : "disabled",
517
			       ifmgd->bssid);
518
		}
519
#endif
520
521
		bss_conf->use_cts_prot = use_protection;
		changed |= BSS_CHANGED_ERP_CTS_PROT;
522
	}
523

524
	if (use_short_preamble != bss_conf->use_short_preamble) {
525
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
526
527
		if (net_ratelimit()) {
			printk(KERN_DEBUG "%s: switched to %s barker preamble"
528
			       " (BSSID=%pM)\n",
529
			       sdata->dev->name,
530
			       use_short_preamble ? "short" : "long",
531
			       ifmgd->bssid);
532
		}
533
#endif
534
		bss_conf->use_short_preamble = use_short_preamble;
535
		changed |= BSS_CHANGED_ERP_PREAMBLE;
536
	}
537

538
539
540
	if (use_short_slot != bss_conf->use_short_slot) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
		if (net_ratelimit()) {
541
542
			printk(KERN_DEBUG "%s: switched to %s slot time"
			       " (BSSID=%pM)\n",
543
544
			       sdata->dev->name,
			       use_short_slot ? "short" : "long",
545
			       ifmgd->bssid);
546
547
548
549
		}
#endif
		bss_conf->use_short_slot = use_short_slot;
		changed |= BSS_CHANGED_ERP_SLOT;
550
551
552
553
554
	}

	return changed;
}

555
static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata)
556
557
{
	union iwreq_data wrqu;
558

559
	memset(&wrqu, 0, sizeof(wrqu));
560
561
	if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)
		memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN);
562
563
564
565
	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
	wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
}

566
static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata)
567
{
568
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
569
570
571
	char *buf;
	size_t len;
	int i;
572
573
	union iwreq_data wrqu;

574
	if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies)
575
576
		return;

577
578
	buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len +
				ifmgd->assocresp_ies_len), GFP_KERNEL);
579
580
581
582
	if (!buf)
		return;

	len = sprintf(buf, "ASSOCINFO(");
583
	if (ifmgd->assocreq_ies) {
584
		len += sprintf(buf + len, "ReqIEs=");
585
		for (i = 0; i < ifmgd->assocreq_ies_len; i++) {
586
			len += sprintf(buf + len, "%02x",
587
				       ifmgd->assocreq_ies[i]);
588
		}
589
	}
590
591
	if (ifmgd->assocresp_ies) {
		if (ifmgd->assocreq_ies)
592
593
			len += sprintf(buf + len, " ");
		len += sprintf(buf + len, "RespIEs=");
594
		for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
595
			len += sprintf(buf + len, "%02x",
596
				       ifmgd->assocresp_ies[i]);
597
		}
598
	}
599
600
601
602
	len += sprintf(buf + len, ")");

	if (len > IW_CUSTOM_MAX) {
		len = sprintf(buf, "ASSOCRESPIE=");
603
		for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
604
			len += sprintf(buf + len, "%02x",
605
				       ifmgd->assocresp_ies[i]);
606
607
608
		}
	}

609
610
611
612
613
	if (len <= IW_CUSTOM_MAX) {
		memset(&wrqu, 0, sizeof(wrqu));
		wrqu.data.length = len;
		wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
	}
614
615

	kfree(buf);
616
617
618
}


619
static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
Johannes Berg's avatar
Johannes Berg committed
620
				     u32 bss_info_changed)
621
{
622
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
623
	struct ieee80211_local *local = sdata->local;
Tomas Winkler's avatar
Tomas Winkler committed
624
	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
625

626
	struct ieee80211_bss *bss;
627

Johannes Berg's avatar
Johannes Berg committed
628
	bss_info_changed |= BSS_CHANGED_ASSOC;
629
	ifmgd->flags |= IEEE80211_STA_ASSOCIATED;
630

631
	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
632
				   conf->channel->center_freq,
633
				   ifmgd->ssid, ifmgd->ssid_len);
634
635
	if (bss) {
		/* set timing information */
636
637
		sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
		sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
638
		sdata->vif.bss_conf.dtim_period = bss->dtim_period;
639

Johannes Berg's avatar
Johannes Berg committed
640
		bss_info_changed |= ieee80211_handle_bss_capability(sdata,
641
			bss->cbss.capability, bss->has_erp_value, bss->erp_value);
642
643

		ieee80211_rx_bss_put(local, bss);
644
645
	}

646
647
648
	ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
	memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
	ieee80211_sta_send_associnfo(sdata);
649

650
	ifmgd->last_probe = jiffies;
651
	ieee80211_led_assoc(local, 1);
652

653
	sdata->vif.bss_conf.assoc = 1;
654
655
656
657
658
	/*
	 * For now just always ask the driver to update the basic rateset
	 * when we have associated, we aren't checking whether it actually
	 * changed or not.
	 */
Johannes Berg's avatar
Johannes Berg committed
659
660
	bss_info_changed |= BSS_CHANGED_BASIC_RATES;
	ieee80211_bss_info_change_notify(sdata, bss_info_changed);
661

662
663
664
	if (local->powersave) {
		if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
		    local->hw.conf.dynamic_ps_timeout > 0) {
665
			mod_timer(&local->dynamic_ps_timer, jiffies +
666
667
				  msecs_to_jiffies(
					local->hw.conf.dynamic_ps_timeout));
668
669
670
		} else {
			if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
				ieee80211_send_nullfunc(local, sdata, 1);
671
			conf->flags |= IEEE80211_CONF_PS;
672
			ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
673
		}
674
675
	}

676
677
	netif_tx_start_all_queues(sdata->dev);
	netif_carrier_on(sdata->dev);
678

679
	ieee80211_sta_send_apinfo(sdata);
680
681
}

682
static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
683
{
684
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
685
	struct ieee80211_local *local = sdata->local;
686
687
688

	ifmgd->direct_probe_tries++;
	if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
689
		printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
690
691
692
		       sdata->dev->name, ifmgd->bssid);
		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
		ieee80211_sta_send_apinfo(sdata);
693
694
695
696
697

		/*
		 * Most likely AP is not in the range so remove the
		 * bss information associated to the AP
		 */
698
		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
699
				sdata->local->hw.conf.channel->center_freq,
700
				ifmgd->ssid, ifmgd->ssid_len);
701
702
703
704
705
706
707

		/*
		 * We might have a pending scan which had no chance to run yet
		 * due to state == IEEE80211_STA_MLME_DIRECT_PROBE.
		 * Hence, queue the STAs work again
		 */
		queue_work(local->hw.workqueue, &ifmgd->work);
708
709
710
		return;
	}

711
	printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",
712
713
			sdata->dev->name, ifmgd->bssid,
			ifmgd->direct_probe_tries);
714

715
	ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
716

717
	set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request);
718
719
720
721
722

	/* Direct probe is sent to broadcast address as some APs
	 * will not answer to direct packet in unassociated state.
	 */
	ieee80211_send_probe_req(sdata, NULL,
723
				 ifmgd->ssid, ifmgd->ssid_len, NULL, 0);
724

725
	mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
Johannes Berg's avatar
Johannes Berg committed
726
}
727

728

729
static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
730
{
731
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
732
	struct ieee80211_local *local = sdata->local;
733
734
735

	ifmgd->auth_tries++;
	if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
736
		printk(KERN_DEBUG "%s: authentication with AP %pM"
737
		       " timed out\n",
738
739
740
741
		       sdata->dev->name, ifmgd->bssid);
		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
		ieee80211_sta_send_apinfo(sdata);
		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
742
				sdata->local->hw.conf.channel->center_freq,
743
				ifmgd->ssid, ifmgd->ssid_len);
744
745
746
747
748
749
750

		/*
		 * We might have a pending scan which had no chance to run yet
		 * due to state == IEEE80211_STA_MLME_AUTHENTICATE.
		 * Hence, queue the STAs work again
		 */
		queue_work(local->hw.workqueue, &ifmgd->work);
751
752
753
		return;
	}

754
	ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
755
	printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
756
	       sdata->dev->name, ifmgd->bssid);
757

758
759
760
	ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0,
			    ifmgd->bssid, 0);
	ifmgd->auth_transaction = 2;
761

762
	mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
763
764
}

765
766
767
768
/*
 * The disassoc 'reason' argument can be either our own reason
 * if self disconnected or a reason code from the AP.
 */
769
static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
770
771
				   bool deauth, bool self_disconnected,
				   u16 reason)
772
{
773
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
774
775
	struct ieee80211_local *local = sdata->local;
	struct sta_info *sta;
776
	u32 changed = 0, config_changed = 0;
777
778
779

	rcu_read_lock();

780
	sta = sta_info_get(local, ifmgd->bssid);
781
782
783
784
785
786
	if (!sta) {
		rcu_read_unlock();
		return;
	}

	if (deauth) {
787
788
		ifmgd->direct_probe_tries = 0;
		ifmgd->auth_tries = 0;
789
	}
790
791
	ifmgd->assoc_scan_tries = 0;
	ifmgd->assoc_tries = 0;
792

793
	netif_tx_stop_all_queues(sdata->dev);
794
795
	netif_carrier_off(sdata->dev);

796
	ieee80211_sta_tear_down_BA_sessions(sta);
797
798
799

	if (self_disconnected) {
		if (deauth)
800
801
			ieee80211_send_deauth_disassoc(sdata,
				IEEE80211_STYPE_DEAUTH, reason);
802
		else
803
804
			ieee80211_send_deauth_disassoc(sdata,
				IEEE80211_STYPE_DISASSOC, reason);
805
806
	}

807
	ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;
808
809
810
	changed |= ieee80211_reset_erp_info(sdata);

	ieee80211_led_assoc(local, 0);
Johannes Berg's avatar
Johannes Berg committed
811
812
	changed |= BSS_CHANGED_ASSOC;
	sdata->vif.bss_conf.assoc = false;
813

814
	ieee80211_sta_send_apinfo(sdata);
815

816
	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
817
818
		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
819
				sdata->local->hw.conf.channel->center_freq,
820
				ifmgd->ssid, ifmgd->ssid_len);
821
	}
822
823
824

	rcu_read_unlock();

825
	/* channel(_type) changes are handled by ieee80211_hw_config */
Sujith's avatar
Sujith committed
826
	local->oper_channel_type = NL80211_CHAN_NO_HT;
827

828
829
	local->power_constr_level = 0;

830
831
832
	del_timer_sync(&local->dynamic_ps_timer);
	cancel_work_sync(&local->dynamic_ps_enable_work);

833
834
835
836
	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
		config_changed |= IEEE80211_CONF_CHANGE_PS;
	}
Johannes Berg's avatar
Johannes Berg committed
837

838
	ieee80211_hw_config(local, config_changed);
Johannes Berg's avatar
Johannes Berg committed
839
	ieee80211_bss_info_change_notify(sdata, changed);
840
841
842

	rcu_read_lock();

843
	sta = sta_info_get(local, ifmgd->bssid);
844
845
846
847
848
849
850
851
852
853
	if (!sta) {
		rcu_read_unlock();
		return;
	}

	sta_info_unlink(&sta);

	rcu_read_unlock();

	sta_info_destroy(sta);
854
}
855

856
857
858
859
860
861
862
863
static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
{
	if (!sdata || !sdata->default_key ||
	    sdata->default_key->conf.alg != ALG_WEP)
		return 0;
	return 1;
}

864
static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata)
865
{
866
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
867
	struct ieee80211_local *local = sdata->local;
868
	struct ieee80211_bss *bss;
869
870
871
	int bss_privacy;
	int wep_privacy;
	int privacy_invoked;
872

873
	if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL))
874
875
		return 0;

876
	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
877
				   local->hw.conf.channel->center_freq,
878
				   ifmgd->ssid, ifmgd->ssid_len);
879
880
881
	if (!bss)
		return 0;

882
	bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY);
883
	wep_privacy = !!ieee80211_sta_wep_configured(sdata);
884
	privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED);
885

886
	ieee80211_rx_bss_put(local, bss);
887

888
889
890
891
	if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
		return 0;

	return 1;
892
893
}

894
static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)