mlme.c 56.1 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
107
108
	if (ifmgd->flags & IEEE80211_IBSS_PREV_BSSID_SET) {
		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
685
686
687
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

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

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

703
	printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",
704
705
			sdata->dev->name, ifmgd->bssid,
			ifmgd->direct_probe_tries);
706

707
	ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
708

709
	set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request);
710
711
712
713
714

	/* 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,
715
				 ifmgd->ssid, ifmgd->ssid_len, NULL, 0);
716

717
	mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
Johannes Berg's avatar
Johannes Berg committed
718
}
719

720

721
static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
722
{
723
724
725
726
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

	ifmgd->auth_tries++;
	if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
727
		printk(KERN_DEBUG "%s: authentication with AP %pM"
728
		       " timed out\n",
729
730
731
732
		       sdata->dev->name, ifmgd->bssid);
		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
		ieee80211_sta_send_apinfo(sdata);
		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
733
				sdata->local->hw.conf.channel->center_freq,
734
				ifmgd->ssid, ifmgd->ssid_len);
735
736
737
		return;
	}

738
	ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
739
	printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
740
	       sdata->dev->name, ifmgd->bssid);
741

742
743
744
	ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0,
			    ifmgd->bssid, 0);
	ifmgd->auth_transaction = 2;
745

746
	mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
747
748
}

749
750
751
752
/*
 * The disassoc 'reason' argument can be either our own reason
 * if self disconnected or a reason code from the AP.
 */
753
static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
754
755
				   bool deauth, bool self_disconnected,
				   u16 reason)
756
{
757
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
758
759
	struct ieee80211_local *local = sdata->local;
	struct sta_info *sta;
760
	u32 changed = 0, config_changed = 0;
761
762
763

	rcu_read_lock();

764
	sta = sta_info_get(local, ifmgd->bssid);
765
766
767
768
769
770
	if (!sta) {
		rcu_read_unlock();
		return;
	}

	if (deauth) {
771
772
		ifmgd->direct_probe_tries = 0;
		ifmgd->auth_tries = 0;
773
	}
774
775
	ifmgd->assoc_scan_tries = 0;
	ifmgd->assoc_tries = 0;
776

777
	netif_tx_stop_all_queues(sdata->dev);
778
779
	netif_carrier_off(sdata->dev);

780
	ieee80211_sta_tear_down_BA_sessions(sta);
781
782
783

	if (self_disconnected) {
		if (deauth)
784
785
			ieee80211_send_deauth_disassoc(sdata,
				IEEE80211_STYPE_DEAUTH, reason);
786
		else
787
788
			ieee80211_send_deauth_disassoc(sdata,
				IEEE80211_STYPE_DISASSOC, reason);
789
790
	}

791
	ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;
792
793
794
	changed |= ieee80211_reset_erp_info(sdata);

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

798
	ieee80211_sta_send_apinfo(sdata);
799

800
	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
801
802
		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
803
				sdata->local->hw.conf.channel->center_freq,
804
				ifmgd->ssid, ifmgd->ssid_len);
805
	}
806
807
808

	rcu_read_unlock();

809
	/* channel(_type) changes are handled by ieee80211_hw_config */
Sujith's avatar
Sujith committed
810
	local->oper_channel_type = NL80211_CHAN_NO_HT;
811

812
813
	local->power_constr_level = 0;

814
815
816
	del_timer_sync(&local->dynamic_ps_timer);
	cancel_work_sync(&local->dynamic_ps_enable_work);

817
818
819
820
	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
821

822
	ieee80211_hw_config(local, config_changed);
Johannes Berg's avatar
Johannes Berg committed
823
	ieee80211_bss_info_change_notify(sdata, changed);
824
825
826

	rcu_read_lock();

827
	sta = sta_info_get(local, ifmgd->bssid);
828
829
830
831
832
833
834
835
836
837
	if (!sta) {
		rcu_read_unlock();
		return;
	}

	sta_info_unlink(&sta);

	rcu_read_unlock();

	sta_info_destroy(sta);
838
}
839

840
841
842
843
844
845
846
847
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;
}

848
static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata)
849
{
850
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
851
	struct ieee80211_local *local = sdata->local;
852
	struct ieee80211_bss *bss;
853
854
855
	int bss_privacy;
	int wep_privacy;
	int privacy_invoked;
856

857
	if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL))
858
859
		return 0;

860
	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
861
				   local->hw.conf.channel->center_freq,
862
				   ifmgd->ssid, ifmgd->ssid_len);
863
864
865
	if (!bss)
		return 0;

866
	bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY);
867
	wep_privacy = !!ieee80211_sta_wep_configured(sdata);
868
	privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED);
869

870
	ieee80211_rx_bss_put(local, bss);
871

872
873
874
875
	if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
		return 0;

	return 1;
876
877
}

878
static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
879
{
880
881
882
883
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

	ifmgd->assoc_tries++;
	if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
884
		printk(KERN_DEBUG "%s: association with AP %pM"
885
		       " timed out\n",
886
887
888
889
		       sdata->dev->name, ifmgd->bssid);
		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
		ieee80211_sta_send_apinfo(sdata);
		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
890
				sdata->local->hw.conf.channel->center_freq,
891
				ifmgd->ssid, ifmgd->ssid_len);