mlme.c 74 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * 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.
 */

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

26
#include "ieee80211_i.h"
Johannes Berg's avatar
Johannes Berg committed
27
28
#include "rate.h"
#include "led.h"
29

30
#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2
31
32
33
34
35
36
37
38
39
#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)
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
40
#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
41
42
43
44
45
46
47

#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)

#define IEEE80211_IBSS_MAX_STA_ENTRIES 128


48
49
/* utils */
static int ecw2cw(int ecw)
Johannes Berg's avatar
Johannes Berg committed
50
{
51
	return (1 << ecw) - 1;
Johannes Berg's avatar
Johannes Berg committed
52
53
}

54
static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie)
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{
	u8 *end, *pos;

	pos = bss->ies;
	if (pos == NULL)
		return NULL;
	end = pos + bss->ies_len;

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

	return NULL;
}

74
static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
				      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;
}

95
96
97
98
/* also used by mesh code */
u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
			    struct ieee802_11_elems *elems,
			    enum ieee80211_band band)
Johannes Berg's avatar
Johannes Berg committed
99
{
100
101
102
103
104
105
	struct ieee80211_supported_band *sband;
	struct ieee80211_rate *bitrates;
	size_t num_rates;
	u64 supp_rates;
	int i, j;
	sband = local->hw.wiphy->bands[band];
Johannes Berg's avatar
Johannes Berg committed
106

107
108
109
	if (!sband) {
		WARN_ON(1);
		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
Johannes Berg's avatar
Johannes Berg committed
110
111
	}

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
	bitrates = sband->bitrates;
	num_rates = sband->n_bitrates;
	supp_rates = 0;
	for (i = 0; i < elems->supp_rates_len +
		     elems->ext_supp_rates_len; i++) {
		u8 rate = 0;
		int own_rate;
		if (i < elems->supp_rates_len)
			rate = elems->supp_rates[i];
		else if (elems->ext_supp_rates)
			rate = elems->ext_supp_rates
				[i - elems->supp_rates_len];
		own_rate = 5 * (rate & 0x7f);
		for (j = 0; j < num_rates; j++)
			if (bitrates[j].bitrate == own_rate)
				supp_rates |= BIT(j);
	}
	return supp_rates;
Johannes Berg's avatar
Johannes Berg committed
130
131
}

132
133
134
/* frame sending functions */

/* also used by scanning code */
135
136
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
			      u8 *ssid, size_t ssid_len)
Johannes Berg's avatar
Johannes Berg committed
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
{
	struct ieee80211_local *local = sdata->local;
	struct ieee80211_supported_band *sband;
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;
	u8 *pos, *supp_rates, *esupp_rates = NULL;
	int i;

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

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
	memset(mgmt, 0, 24);
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
					  IEEE80211_STYPE_PROBE_REQ);
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
	if (dst) {
		memcpy(mgmt->da, dst, ETH_ALEN);
		memcpy(mgmt->bssid, dst, ETH_ALEN);
	} else {
		memset(mgmt->da, 0xff, ETH_ALEN);
		memset(mgmt->bssid, 0xff, ETH_ALEN);
	}
	pos = skb_put(skb, 2 + ssid_len);
	*pos++ = WLAN_EID_SSID;
	*pos++ = ssid_len;
	memcpy(pos, ssid, ssid_len);

	supp_rates = skb_put(skb, 2);
	supp_rates[0] = WLAN_EID_SUPP_RATES;
	supp_rates[1] = 0;
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];

	for (i = 0; i < sband->n_bitrates; i++) {
		struct ieee80211_rate *rate = &sband->bitrates[i];
		if (esupp_rates) {
			pos = skb_put(skb, 1);
			esupp_rates[1]++;
		} else if (supp_rates[1] == 8) {
			esupp_rates = skb_put(skb, 3);
			esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
			esupp_rates[1] = 1;
			pos = &esupp_rates[2];
		} else {
			pos = skb_put(skb, 1);
			supp_rates[1]++;
		}
		*pos = rate->bitrate / 5;
	}

192
	ieee80211_tx_skb(sdata, skb, 0);
Johannes Berg's avatar
Johannes Berg committed
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
static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
				struct ieee80211_if_sta *ifsta,
				int transaction, u8 *extra, size_t extra_len,
				int encrypt)
{
	struct ieee80211_local *local = sdata->local;
	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 "
		       "frame\n", sdata->dev->name);
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
	memset(mgmt, 0, 24 + 6);
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
					  IEEE80211_STYPE_AUTH);
	if (encrypt)
		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
	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);

	ieee80211_tx_skb(sdata, skb, encrypt);
}

232
233
234
235
236
237
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
				 struct ieee80211_if_sta *ifsta)
{
	struct ieee80211_local *local = sdata->local;
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;
238
	u8 *pos, *ies, *ht_ie;
239
240
	int i, len, count, rates_len, supp_rates_len;
	u16 capab;
241
	struct ieee80211_bss *bss;
242
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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
	int wmm = 0;
	struct ieee80211_supported_band *sband;
	u64 rates = 0;

	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 "
		       "frame\n", sdata->dev->name);
		return;
	}
	skb_reserve(skb, local->hw.extra_tx_headroom);

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

	capab = ifsta->capab;

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

	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
				   local->hw.conf.channel->center_freq,
				   ifsta->ssid, ifsta->ssid_len);
	if (bss) {
		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
			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);

		if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
		    (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);
	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);

	if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
		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);
		memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid,
		       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);
312
		mgmt->u.assoc_req.listen_interval =
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
				cpu_to_le16(local->hw.conf.listen_interval);
	}

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

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

	if (ifsta->extra_ie) {
		pos = skb_put(skb, ifsta->extra_ie_len);
		memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
	}

	if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
		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 */
394
395
396
397
398
399
	/*
	 * 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.
	 */
400
	if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
401
402
	    sband->ht_cap.ht_supported &&
	    (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) &&
403
404
	    ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&
	    (!(ifsta->flags & IEEE80211_STA_TKIP_WEP_USED))) {
405
406
407
		struct ieee80211_ht_info *ht_info =
			(struct ieee80211_ht_info *)(ht_ie + 2);
		u16 cap = sband->ht_cap.cap;
408
409
410
		__le16 tmp;
		u32 flags = local->hw.conf.channel->flags;

411
412
		switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
413
			if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
414
				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
415
416
417
				cap &= ~IEEE80211_HT_CAP_SGI_40;
			}
			break;
418
		case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
419
			if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
420
				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
421
422
423
424
425
426
427
428
429
430
431
432
433
				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 */
434
435
436
		*pos++ = sband->ht_cap.ampdu_factor |
			 (sband->ht_cap.ampdu_density << 2);
		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
437
438
439
440
441
442
443
444
	}

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

445
	ieee80211_tx_skb(sdata, skb, 0);
446
447
448
}


449
450
static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
					   u16 stype, u16 reason)
451
452
{
	struct ieee80211_local *local = sdata->local;
453
	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
454
455
456
457
458
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;

	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
	if (!skb) {
459
460
		printk(KERN_DEBUG "%s: failed to allocate buffer for "
		       "deauth/disassoc frame\n", sdata->dev->name);
461
462
463
464
465
466
467
468
469
		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);
	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
470
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
471
	skb_put(skb, 2);
472
	/* u.deauth.reason_code == u.disassoc.reason_code */
473
474
	mgmt->u.deauth.reason_code = cpu_to_le16(reason);

475
	ieee80211_tx_skb(sdata, skb, 0);
476
477
}

Johannes Berg's avatar
Johannes Berg committed
478
/* MLME */
479
static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
480
					 struct ieee80211_bss *bss)
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
{
	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;

496
	ieee80211_set_wmm_default(sdata);
497
498
}

499
static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
500
501
502
503
504
505
506
507
				     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;

508
509
510
511
512
513
	if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
		return;

	if (!wmm_param)
		return;

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
	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
537
			queue = 3;
Johannes Berg's avatar
Johannes Berg committed
538
			if (acm)
539
540
541
				local->wmm_acm |= BIT(0) | BIT(3);
			break;
		case 2:
Johannes Berg's avatar
Johannes Berg committed
542
			queue = 1;
Johannes Berg's avatar
Johannes Berg committed
543
			if (acm)
544
545
546
				local->wmm_acm |= BIT(4) | BIT(5);
			break;
		case 3:
Johannes Berg's avatar
Johannes Berg committed
547
			queue = 0;
Johannes Berg's avatar
Johannes Berg committed
548
			if (acm)
549
550
551
552
				local->wmm_acm |= BIT(6) | BIT(7);
			break;
		case 0:
		default:
Johannes Berg's avatar
Johannes Berg committed
553
			queue = 2;
Johannes Berg's avatar
Johannes Berg committed
554
			if (acm)
555
556
557
558
559
560
561
				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);
562
		params.txop = get_unaligned_le16(pos + 2);
563
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
564
		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
565
		       "cWmin=%d cWmax=%d txop=%d\n",
566
		       local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
567
568
		       params.cw_max, params.txop);
#endif
569
570
571
572
		/* 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 "
573
			       "parameters for queue %d\n", local->mdev->name, queue);
574
575
576
577
		}
	}
}

578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
static bool check_tim(struct ieee802_11_elems *elems, u16 aid, bool *is_mc)
{
	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);

	if (tim->bitmap_ctrl & 0x01)
		*is_mc = true;

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

602
603
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
					   u16 capab, bool erp_valid, u8 erp)
604
{
605
	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
606
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
607
	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
608
#endif
609
	u32 changed = 0;
610
611
612
613
614
615
616
617
618
619
620
621
622
	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);
623

624
	if (use_protection != bss_conf->use_cts_prot) {
625
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
626
		if (net_ratelimit()) {
627
			printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n",
628
			       sdata->dev->name,
629
			       use_protection ? "enabled" : "disabled",
630
			       ifsta->bssid);
631
		}
632
#endif
633
634
		bss_conf->use_cts_prot = use_protection;
		changed |= BSS_CHANGED_ERP_CTS_PROT;
635
	}
636

637
	if (use_short_preamble != bss_conf->use_short_preamble) {
638
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
639
640
		if (net_ratelimit()) {
			printk(KERN_DEBUG "%s: switched to %s barker preamble"
641
			       " (BSSID=%pM)\n",
642
			       sdata->dev->name,
643
			       use_short_preamble ? "short" : "long",
644
			       ifsta->bssid);
645
		}
646
#endif
647
		bss_conf->use_short_preamble = use_short_preamble;
648
		changed |= BSS_CHANGED_ERP_PREAMBLE;
649
	}
650

651
652
653
	if (use_short_slot != bss_conf->use_short_slot) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
		if (net_ratelimit()) {
654
655
			printk(KERN_DEBUG "%s: switched to %s slot time"
			       " (BSSID=%pM)\n",
656
657
658
659
660
661
662
			       sdata->dev->name,
			       use_short_slot ? "short" : "long",
			       ifsta->bssid);
		}
#endif
		bss_conf->use_short_slot = use_short_slot;
		changed |= BSS_CHANGED_ERP_SLOT;
663
664
665
666
667
	}

	return changed;
}

668
669
670
671
672
673
674
675
676
677
678
static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata,
					struct ieee80211_if_sta *ifsta)
{
	union iwreq_data wrqu;
	memset(&wrqu, 0, sizeof(wrqu));
	if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
		memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
	wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
}

679
static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata,
680
681
					 struct ieee80211_if_sta *ifsta)
{
682
683
684
	char *buf;
	size_t len;
	int i;
685
686
	union iwreq_data wrqu;

687
688
689
690
691
692
693
694
695
	if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
		return;

	buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
				ifsta->assocresp_ies_len), GFP_KERNEL);
	if (!buf)
		return;

	len = sprintf(buf, "ASSOCINFO(");
696
	if (ifsta->assocreq_ies) {
697
698
699
700
701
		len += sprintf(buf + len, "ReqIEs=");
		for (i = 0; i < ifsta->assocreq_ies_len; i++) {
			len += sprintf(buf + len, "%02x",
				       ifsta->assocreq_ies[i]);
		}
702
	}
703
	if (ifsta->assocresp_ies) {
704
705
706
707
708
709
710
		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]);
		}
711
	}
712
713
714
715
716
717
718
719
720
721
	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]);
		}
	}

722
723
724
725
726
	if (len <= IW_CUSTOM_MAX) {
		memset(&wrqu, 0, sizeof(wrqu));
		wrqu.data.length = len;
		wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
	}
727
728

	kfree(buf);
729
730
731
}


732
static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
Johannes Berg's avatar
Johannes Berg committed
733
734
				     struct ieee80211_if_sta *ifsta,
				     u32 bss_info_changed)
735
{
736
	struct ieee80211_local *local = sdata->local;
Tomas Winkler's avatar
Tomas Winkler committed
737
	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
738

739
	struct ieee80211_bss *bss;
740

Johannes Berg's avatar
Johannes Berg committed
741
	bss_info_changed |= BSS_CHANGED_ASSOC;
742
	ifsta->flags |= IEEE80211_STA_ASSOCIATED;
743

744
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
745
		return;
746

747
748
749
750
751
	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
				   conf->channel->center_freq,
				   ifsta->ssid, ifsta->ssid_len);
	if (bss) {
		/* set timing information */
752
753
754
		sdata->vif.bss_conf.beacon_int = bss->beacon_int;
		sdata->vif.bss_conf.timestamp = bss->timestamp;
		sdata->vif.bss_conf.dtim_period = bss->dtim_period;
755

Johannes Berg's avatar
Johannes Berg committed
756
		bss_info_changed |= ieee80211_handle_bss_capability(sdata,
757
			bss->capability, bss->has_erp_value, bss->erp_value);
758
759

		ieee80211_rx_bss_put(local, bss);
760
761
	}

762
763
764
	ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
	memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
	ieee80211_sta_send_associnfo(sdata, ifsta);
765

766
767
	ifsta->last_probe = jiffies;
	ieee80211_led_assoc(local, 1);
768

769
	sdata->vif.bss_conf.assoc = 1;
770
771
772
773
774
	/*
	 * 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
775
776
	bss_info_changed |= BSS_CHANGED_BASIC_RATES;
	ieee80211_bss_info_change_notify(sdata, bss_info_changed);
777

778
779
	if (local->powersave &&
			!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) {
780
781
782
783
		if (local->dynamic_ps_timeout > 0)
			mod_timer(&local->dynamic_ps_timer, jiffies +
				  msecs_to_jiffies(local->dynamic_ps_timeout));
		else {
784
			ieee80211_send_nullfunc(local, sdata, 1);
785
786
787
788
			conf->flags |= IEEE80211_CONF_PS;
			ieee80211_hw_config(local,
					    IEEE80211_CONF_CHANGE_PS);
		}
789
790
	}

791
792
	netif_tx_start_all_queues(sdata->dev);
	netif_carrier_on(sdata->dev);
793

794
	ieee80211_sta_send_apinfo(sdata, ifsta);
795
796
}

797
798
static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
				   struct ieee80211_if_sta *ifsta)
799
{
800
801
	ifsta->direct_probe_tries++;
	if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
802
803
		printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
		       sdata->dev->name, ifsta->bssid);
804
		ifsta->state = IEEE80211_STA_MLME_DISABLED;
805
		ieee80211_sta_send_apinfo(sdata, ifsta);
806
807
808
		return;
	}

809
810
	printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",
			sdata->dev->name, ifsta->bssid,
811
			ifsta->direct_probe_tries);
812

813
	ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
814

815
816
817
818
819
820
821
822
823
	set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request);

	/* 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,
				 ifsta->ssid, ifsta->ssid_len);

	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
Johannes Berg's avatar
Johannes Berg committed
824
}
825

826
827
828

static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
				   struct ieee80211_if_sta *ifsta)
829
{
830
831
	ifsta->auth_tries++;
	if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
832
		printk(KERN_DEBUG "%s: authentication with AP %pM"
833
		       " timed out\n",
834
		       sdata->dev->name, ifsta->bssid);
835
		ifsta->state = IEEE80211_STA_MLME_DISABLED;
836
		ieee80211_sta_send_apinfo(sdata, ifsta);
837
838
839
		return;
	}

840
	ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
841
842
	printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
	       sdata->dev->name, ifsta->bssid);
843

844
845
846
	ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0);

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

849
850
851
852
/*
 * The disassoc 'reason' argument can be either our own reason
 * if self disconnected or a reason code from the AP.
 */
853
854
855
856
857
858
static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
				   struct ieee80211_if_sta *ifsta, bool deauth,
				   bool self_disconnected, u16 reason)
{
	struct ieee80211_local *local = sdata->local;
	struct sta_info *sta;
859
	u32 changed = 0, config_changed = 0;
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875

	rcu_read_lock();

	sta = sta_info_get(local, ifsta->bssid);
	if (!sta) {
		rcu_read_unlock();
		return;
	}

	if (deauth) {
		ifsta->direct_probe_tries = 0;
		ifsta->auth_tries = 0;
	}
	ifsta->assoc_scan_tries = 0;
	ifsta->assoc_tries = 0;

876
	netif_tx_stop_all_queues(sdata->dev);
877
878
	netif_carrier_off(sdata->dev);

879
	ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr);
880
881
882

	if (self_disconnected) {
		if (deauth)
883
884
			ieee80211_send_deauth_disassoc(sdata,
				IEEE80211_STYPE_DEAUTH, reason);
885
		else
886
887
			ieee80211_send_deauth_disassoc(sdata,
				IEEE80211_STYPE_DISASSOC, reason);
888
889
	}

890
891
892
893
	ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
	changed |= ieee80211_reset_erp_info(sdata);

	ieee80211_led_assoc(local, 0);
Johannes Berg's avatar
Johannes Berg committed
894
895
	changed |= BSS_CHANGED_ASSOC;
	sdata->vif.bss_conf.assoc = false;
896
897

	ieee80211_sta_send_apinfo(sdata, ifsta);
898

899
	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT)
900
901
902
903
		ifsta->state = IEEE80211_STA_MLME_DISABLED;

	rcu_read_unlock();

904
	/* channel(_type) changes are handled by ieee80211_hw_config */
Sujith's avatar
Sujith committed
905
	local->oper_channel_type = NL80211_CHAN_NO_HT;
906

907
908
909
	del_timer_sync(&local->dynamic_ps_timer);
	cancel_work_sync(&local->dynamic_ps_enable_work);

910
911
912
913
	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
914

915
	ieee80211_hw_config(local, config_changed);
Johannes Berg's avatar
Johannes Berg committed
916
	ieee80211_bss_info_change_notify(sdata, changed);
917
918
919
920
921
922
923
924
925
926
927
928
929
930

	rcu_read_lock();

	sta = sta_info_get(local, ifsta->bssid);
	if (!sta) {
		rcu_read_unlock();
		return;
	}

	sta_info_unlink(&sta);

	rcu_read_unlock();

	sta_info_destroy(sta);
931
}
932

933
934
935
936
937
938
939
940
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;
}

941
static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata,
942
943
				      struct ieee80211_if_sta *ifsta)
{
944
	struct ieee80211_local *local = sdata->local;
945
	struct ieee80211_bss *bss;
946
947
948
	int bss_privacy;
	int wep_privacy;
	int privacy_invoked;
949

950
	if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
951
952
		return 0;

953
	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
954
				   local->hw.conf.channel->center_freq,
955
				   ifsta->ssid, ifsta->ssid_len);
956
957
958
	if (!bss)
		return 0;

959
	bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
960
	wep_privacy = !!ieee80211_sta_wep_configured(sdata);
961
	privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
962

963
	ieee80211_rx_bss_put(local, bss);
964

965
966
967
968
	if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
		return 0;

	return 1;
969
970
}

971
static void ieee80211_associate(struct ieee80211_sub_if_data *sdata,
972
973
974
975
				struct ieee80211_if_sta *ifsta)
{
	ifsta->assoc_tries++;
	if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
976
		printk(KERN_DEBUG "%s: association with AP %pM"
977
		       " timed out\n",
978
		       sdata->dev->name, ifsta->bssid);
979
		ifsta->state = IEEE80211_STA_MLME_DISABLED;
980
		ieee80211_sta_send_apinfo(sdata, ifsta);
981
982
983
		return;
	}

984
	ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
985
986
	printk(KERN_DEBUG "%s: associate with AP %pM\n",
	       sdata->dev->name, ifsta->bssid);
987
	if (ieee80211_privacy_mismatch(sdata, ifsta)) {
988
		printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
989
		       "mixed-cell disabled - abort association\n", sdata->dev->name);
990
		ifsta->state = IEEE80211_STA_MLME_DISABLED;
991
992
993
		return;
	}

994
	ieee80211_send_assoc(sdata, ifsta);
995
996
997
998
999

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


1000
static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
1001
1002
				 struct ieee80211_if_sta *ifsta)
{
1003
	struct ieee80211_local *local = sdata->local;
1004
1005
1006
1007
1008
1009
1010
1011
	struct sta_info *sta;
	int disassoc;

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

1012
	ifsta->state = IEEE80211_STA_MLME_ASSOCIATED;
1013

1014
1015
	rcu_read_lock();

1016
1017
	sta = sta_info_get(local, ifsta->bssid);
	if (!sta) {
1018
1019
		printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
		       sdata->dev->name, ifsta->bssid);
1020
1021
1022
1023
1024
		disassoc = 1;
	} else {
		disassoc = 0;
		if (time_after(jiffies,
			       sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
1025
			if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) {
1026
				printk(KERN_DEBUG "%s: No ProbeResp from "
1027
				       "current AP %pM - assume out of "
1028
				       "range\n",
1029
				       sdata->dev->name, ifsta->bssid);
1030
				disassoc = 1;
1031
			} else
1032
				ieee80211_send_probe_req(sdata, ifsta->bssid,
1033
1034
							 ifsta->ssid,
							 ifsta->ssid_len);
1035
			ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL;
1036
		} else {
1037
			ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
1038
1039
1040
			if (time_after(jiffies, ifsta->last_probe +
				       IEEE80211_PROBE_INTERVAL)) {
				ifsta->last_probe = jiffies;
1041
				ieee80211_send_probe_req(sdata, ifsta->bssid,
1042
1043
1044
1045
1046
							 ifsta->ssid,
							 ifsta->ssid_len);
			}
		}
	}
1047
1048
1049

	rcu_read_unlock();

Johannes Berg's avatar
Johannes Berg committed
1050
1051
1052
1053
1054
1055
	if (disassoc)
		ieee80211_set_disassoc(sdata, ifsta, true, true,
					WLAN_REASON_PREV_AUTH_NOT_VALID);
	else
		mod_timer(&ifsta->timer, jiffies +
				      IEEE80211_MONITORING_INTERVAL);
1056
1057
1058
}


1059
static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
1060
1061
				     struct ieee80211_if_sta *ifsta)
{
1062
	printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
1063
	ifsta->flags |= IEEE80211_STA_AUTHENTICATED;
1064
	ieee80211_associate(sdata, ifsta);
1065
1066
1067
}


1068
static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
1069
1070
1071
1072
1073
1074
1075
1076
				     struct ieee80211_if_sta *ifsta,
				     struct ieee80211_mgmt *mgmt,
				     size_t len)
{
	u8 *pos;
	struct ieee802_11_elems elems;

	pos = mgmt->u.auth.variable;
1077
	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
1078
	if (!elems.challenge)
1079
		return;
1080
	ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2,
1081
1082
1083
			    elems.challenge_len + 2, 1);
}

1084
static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
1085
1086
1087
1088
1089
1090
				   struct ieee80211_if_sta *ifsta,
				   struct ieee80211_mgmt *mgmt,
				   size_t len)
{
	u16 auth_alg, auth_transaction, status_code;

1091
	if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
1092
	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
1093
1094
		return;

1095
	if (len < 24 + 6)
1096
1097
		return;

1098
	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
1099
	    memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
1100
1101
		return;

1102
	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
1103
	    memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
1104
1105
1106
1107
1108
1109
		return;

	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
	status_code = le16_to_cpu(mgmt->u.auth.status_code);

1110
	if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
1111
1112
		/*
		 * IEEE 802.11 standard does not require authentication in IBSS
1113
1114
1115
		 * networks and most implementations do not seem to use it.
		 * However, try to reply to authentication attempts if someone
		 * has actually implemented this.
1116
		 */
1117
		if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
1118
			return;
1119
		ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
1120
1121
1122
	}

	if (auth_alg != ifsta->auth_alg ||
1123
	    auth_transaction != ifsta->auth_transaction)
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
		return;

	if (status_code != WLAN_STATUS_SUCCESS) {
		if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
			u8 algs[3];
			const int num_algs = ARRAY_SIZE(algs);
			int i, pos;
			algs[0] = algs[1] = algs[2] = 0xff;
			if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)
				algs[0] = WLAN_AUTH_OPEN;
			if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
				algs[1] = WLAN_AUTH_SHARED_KEY;
			if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)
				algs[2] = WLAN_AUTH_LEAP;
			if (ifsta->auth_alg == WLAN_AUTH_OPEN)
				pos = 0;
			else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY)