blob: e714ed8bb198727c6738c1e3ae7650243dd2a07e [file] [log] [blame]
Jiri Bencf0706e82007-05-05 11:45:53 -07001/*
2 * BSS client mode implementation
Jouni Malinen5394af42009-01-08 13:31:59 +02003 * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
Jiri Bencf0706e82007-05-05 11:45:53 -07004 * Copyright 2004, Instant802 Networks, Inc.
5 * Copyright 2005, Devicescape Software, Inc.
6 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
7 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
Geert Uytterhoeven5b323ed2007-05-08 18:40:27 -070014#include <linux/delay.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070015#include <linux/if_ether.h>
16#include <linux/skbuff.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070017#include <linux/if_arp.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070018#include <linux/etherdevice.h>
Paul Gortmakerd9b93842011-09-18 13:21:27 -040019#include <linux/moduleparam.h>
Johannes Bergd0709a62008-02-25 16:27:46 +010020#include <linux/rtnetlink.h>
Jean Pihete8db0be2011-08-25 15:35:03 +020021#include <linux/pm_qos.h>
Johannes Bergd91f36d2009-04-16 13:17:26 +020022#include <linux/crc32.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040024#include <linux/export.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070025#include <net/mac80211.h>
Johannes Berg472dbc42008-09-11 00:01:49 +020026#include <asm/unaligned.h>
Johannes Berg60f8b392008-09-08 17:44:22 +020027
Jiri Bencf0706e82007-05-05 11:45:53 -070028#include "ieee80211_i.h"
Johannes Berg24487982009-04-23 18:52:52 +020029#include "driver-ops.h"
Johannes Berg2c8dccc2008-04-08 15:14:40 -040030#include "rate.h"
31#include "led.h"
Jiri Bencf0706e82007-05-05 11:45:53 -070032
Johannes Berg66e67e42012-01-20 13:55:27 +010033#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
34#define IEEE80211_AUTH_MAX_TRIES 3
35#define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5)
36#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
37#define IEEE80211_ASSOC_MAX_TRIES 3
38
Ben Greear180205b2011-02-04 15:30:24 -080039static int max_nullfunc_tries = 2;
40module_param(max_nullfunc_tries, int, 0644);
41MODULE_PARM_DESC(max_nullfunc_tries,
42 "Maximum nullfunc tx tries before disconnecting (reason 4).");
43
44static int max_probe_tries = 5;
45module_param(max_probe_tries, int, 0644);
46MODULE_PARM_DESC(max_probe_tries,
47 "Maximum probe tries before disconnecting (reason 4).");
Johannes Bergb291ba12009-07-10 15:29:03 +020048
49/*
Felix Fietkau7ccc8bd2010-11-19 22:55:38 +010050 * Beacon loss timeout is calculated as N frames times the
51 * advertised beacon interval. This may need to be somewhat
52 * higher than what hardware might detect to account for
53 * delays in the host processing frames. But since we also
54 * probe on beacon miss before declaring the connection lost
55 * default to what we want.
Johannes Bergb291ba12009-07-10 15:29:03 +020056 */
Felix Fietkau7ccc8bd2010-11-19 22:55:38 +010057#define IEEE80211_BEACON_LOSS_COUNT 7
58
Johannes Bergb291ba12009-07-10 15:29:03 +020059/*
60 * Time the connection can be idle before we probe
61 * it to see if we can still talk to the AP.
62 */
Maxim Levitskyd1c50912009-07-31 18:54:23 +030063#define IEEE80211_CONNECTION_IDLE_TIME (30 * HZ)
Johannes Bergb291ba12009-07-10 15:29:03 +020064/*
65 * Time we wait for a probe response after sending
66 * a probe request because of beacon loss or for
67 * checking the connection still works.
68 */
Ben Greear180205b2011-02-04 15:30:24 -080069static int probe_wait_ms = 500;
70module_param(probe_wait_ms, int, 0644);
71MODULE_PARM_DESC(probe_wait_ms,
72 "Maximum time(ms) to wait for probe response"
73 " before disconnecting (reason 4).");
Jiri Bencf0706e82007-05-05 11:45:53 -070074
Jouni Malinen17e4ec12010-03-29 23:28:30 -070075/*
76 * Weight given to the latest Beacon frame when calculating average signal
77 * strength for Beacon frames received in the current BSS. This must be
78 * between 1 and 15.
79 */
80#define IEEE80211_SIGNAL_AVE_WEIGHT 3
81
Jouni Malinen391a2002010-08-27 22:22:00 +030082/*
83 * How many Beacon frames need to have been used in average signal strength
84 * before starting to indicate signal change events.
85 */
86#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
87
Johannes Berg5bb644a2009-05-17 11:40:42 +020088#define TMR_RUNNING_TIMER 0
89#define TMR_RUNNING_CHANSW 1
90
Johannes Berg77fdaa12009-07-07 03:45:17 +020091/*
92 * All cfg80211 functions have to be called outside a locked
93 * section so that they can acquire a lock themselves... This
94 * is much simpler than queuing up things in cfg80211, but we
95 * do need some indirection for that here.
96 */
97enum rx_mgmt_action {
98 /* no action required */
99 RX_MGMT_NONE,
100
Johannes Berg77fdaa12009-07-07 03:45:17 +0200101 /* caller must call cfg80211_send_deauth() */
102 RX_MGMT_CFG80211_DEAUTH,
103
104 /* caller must call cfg80211_send_disassoc() */
105 RX_MGMT_CFG80211_DISASSOC,
Johannes Berg66e67e42012-01-20 13:55:27 +0100106
107 /* caller must call cfg80211_send_rx_auth() */
108 RX_MGMT_CFG80211_RX_AUTH,
109
110 /* caller must call cfg80211_send_rx_assoc() */
111 RX_MGMT_CFG80211_RX_ASSOC,
112
113 /* caller must call cfg80211_send_assoc_timeout() */
114 RX_MGMT_CFG80211_ASSOC_TIMEOUT,
Johannes Berg77fdaa12009-07-07 03:45:17 +0200115};
116
Johannes Berg5484e232008-09-08 17:44:27 +0200117/* utils */
Johannes Berg77fdaa12009-07-07 03:45:17 +0200118static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
119{
Johannes Berg46a5eba2010-09-15 13:28:15 +0200120 lockdep_assert_held(&ifmgd->mtx);
Johannes Berg77fdaa12009-07-07 03:45:17 +0200121}
122
Johannes Bergca386f32009-07-10 02:39:48 +0200123/*
124 * We can have multiple work items (and connection probing)
125 * scheduling this timer, but we need to take care to only
126 * reschedule it when it should fire _earlier_ than it was
127 * asked for before, or if it's not pending right now. This
128 * function ensures that. Note that it then is required to
129 * run this function for all timeouts after the first one
130 * has happened -- the work that runs from this timer will
131 * do that.
132 */
Johannes Berg66e67e42012-01-20 13:55:27 +0100133static void run_again(struct ieee80211_if_managed *ifmgd, unsigned long timeout)
Johannes Bergca386f32009-07-10 02:39:48 +0200134{
135 ASSERT_MGD_MTX(ifmgd);
136
137 if (!timer_pending(&ifmgd->timer) ||
138 time_before(timeout, ifmgd->timer.expires))
139 mod_timer(&ifmgd->timer, timeout);
140}
141
Luis R. Rodriguezd3a910a2010-09-16 15:12:32 -0400142void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata)
Johannes Bergb291ba12009-07-10 15:29:03 +0200143{
Johannes Bergc1288b12012-01-19 09:29:57 +0100144 if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
Johannes Bergb291ba12009-07-10 15:29:03 +0200145 return;
146
Johannes Berg7eeff742012-07-18 10:27:27 +0200147 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
148 return;
149
Johannes Bergb291ba12009-07-10 15:29:03 +0200150 mod_timer(&sdata->u.mgd.bcn_mon_timer,
Felix Fietkau7ccc8bd2010-11-19 22:55:38 +0100151 round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout));
Johannes Bergb291ba12009-07-10 15:29:03 +0200152}
153
Luis R. Rodriguezbe099e82010-09-16 15:12:29 -0400154void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata)
155{
Luis R. Rodriguez0c699c32010-09-16 15:12:30 -0400156 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
157
Stanislaw Gruszka86281722011-02-25 14:46:02 +0100158 if (unlikely(!sdata->u.mgd.associated))
159 return;
160
Luis R. Rodriguezbe099e82010-09-16 15:12:29 -0400161 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
162 return;
163
164 mod_timer(&sdata->u.mgd.conn_mon_timer,
165 round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
Luis R. Rodriguez0c699c32010-09-16 15:12:30 -0400166
167 ifmgd->probe_send_count = 0;
Luis R. Rodriguezbe099e82010-09-16 15:12:29 -0400168}
169
Johannes Berg5484e232008-09-08 17:44:27 +0200170static int ecw2cw(int ecw)
Johannes Berg60f8b392008-09-08 17:44:22 +0200171{
Johannes Berg5484e232008-09-08 17:44:27 +0200172 return (1 << ecw) - 1;
Johannes Berg60f8b392008-09-08 17:44:22 +0200173}
174
Johannes Berg24398e32012-03-28 10:58:36 +0200175static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
176 struct ieee80211_ht_operation *ht_oper,
177 const u8 *bssid, bool reconfig)
Johannes Bergd5522e02009-03-30 13:23:35 +0200178{
179 struct ieee80211_local *local = sdata->local;
180 struct ieee80211_supported_band *sband;
Johannes Bergd5522e02009-03-30 13:23:35 +0200181 struct sta_info *sta;
182 u32 changed = 0;
Johannes Berg9ed6bcc2009-05-08 20:47:39 +0200183 u16 ht_opmode;
Johannes Berg64f68e52012-03-28 10:58:37 +0200184 bool disable_40 = false;
Johannes Bergd5522e02009-03-30 13:23:35 +0200185
Johannes Berg568d6e22012-07-23 14:29:21 +0200186 sband = local->hw.wiphy->bands[local->oper_channel->band];
Johannes Berg0aaffa92010-05-05 15:28:27 +0200187
Johannes Berg64f68e52012-03-28 10:58:37 +0200188 switch (sdata->vif.bss_conf.channel_type) {
189 case NL80211_CHAN_HT40PLUS:
Johannes Berg568d6e22012-07-23 14:29:21 +0200190 if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
Johannes Berg64f68e52012-03-28 10:58:37 +0200191 disable_40 = true;
192 break;
193 case NL80211_CHAN_HT40MINUS:
Johannes Berg568d6e22012-07-23 14:29:21 +0200194 if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
Johannes Berg64f68e52012-03-28 10:58:37 +0200195 disable_40 = true;
196 break;
197 default:
198 break;
199 }
Johannes Bergd5522e02009-03-30 13:23:35 +0200200
Johannes Berg24398e32012-03-28 10:58:36 +0200201 /* This can change during the lifetime of the BSS */
202 if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
Johannes Berg64f68e52012-03-28 10:58:37 +0200203 disable_40 = true;
Johannes Bergd5522e02009-03-30 13:23:35 +0200204
Johannes Berg64f68e52012-03-28 10:58:37 +0200205 mutex_lock(&local->sta_mtx);
206 sta = sta_info_get(sdata, bssid);
207
208 WARN_ON_ONCE(!sta);
209
210 if (sta && !sta->supports_40mhz)
211 disable_40 = true;
212
213 if (sta && (!reconfig ||
Rajkumar Manoharan91a00992012-04-25 20:24:24 +0530214 (disable_40 != !(sta->sta.ht_cap.cap &
Johannes Berg64f68e52012-03-28 10:58:37 +0200215 IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
Rajkumar Manoharan7cc44ed2011-09-16 15:32:34 +0530216
Johannes Berg64f68e52012-03-28 10:58:37 +0200217 if (disable_40)
218 sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
219 else
220 sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Rajkumar Manoharan7cc44ed2011-09-16 15:32:34 +0530221
Johannes Berg64f68e52012-03-28 10:58:37 +0200222 rate_control_rate_update(local, sband, sta,
Johannes Berg8f727ef2012-03-30 08:43:32 +0200223 IEEE80211_RC_BW_CHANGED);
Johannes Berg0aaffa92010-05-05 15:28:27 +0200224 }
Johannes Berg64f68e52012-03-28 10:58:37 +0200225 mutex_unlock(&local->sta_mtx);
Johannes Bergd5522e02009-03-30 13:23:35 +0200226
Johannes Berg074d46d2012-03-15 19:45:16 +0100227 ht_opmode = le16_to_cpu(ht_oper->operation_mode);
Johannes Bergd5522e02009-03-30 13:23:35 +0200228
229 /* if bss configuration changed store the new one */
Johannes Berg24398e32012-03-28 10:58:36 +0200230 if (!reconfig || (sdata->vif.bss_conf.ht_operation_mode != ht_opmode)) {
Johannes Bergd5522e02009-03-30 13:23:35 +0200231 changed |= BSS_CHANGED_HT;
Johannes Berg9ed6bcc2009-05-08 20:47:39 +0200232 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
Johannes Bergd5522e02009-03-30 13:23:35 +0200233 }
234
235 return changed;
236}
237
Johannes Berg9c6bd792008-09-11 00:01:52 +0200238/* frame sending functions */
239
Johannes Berg66e67e42012-01-20 13:55:27 +0100240static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
241 struct ieee80211_supported_band *sband,
242 u32 *rates)
243{
244 int i, j, count;
245 *rates = 0;
246 count = 0;
247 for (i = 0; i < supp_rates_len; i++) {
248 int rate = (supp_rates[i] & 0x7F) * 5;
249
250 for (j = 0; j < sband->n_bitrates; j++)
251 if (sband->bitrates[j].bitrate == rate) {
252 *rates |= BIT(j);
253 count++;
254 break;
255 }
256 }
257
258 return count;
259}
260
261static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
Johannes Berg9dde6422012-05-16 23:43:19 +0200262 struct sk_buff *skb, u8 ap_ht_param,
Johannes Berg66e67e42012-01-20 13:55:27 +0100263 struct ieee80211_supported_band *sband,
264 struct ieee80211_channel *channel,
265 enum ieee80211_smps_mode smps)
266{
Johannes Berg66e67e42012-01-20 13:55:27 +0100267 u8 *pos;
268 u32 flags = channel->flags;
269 u16 cap;
270 struct ieee80211_sta_ht_cap ht_cap;
271
272 BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
273
Johannes Berg66e67e42012-01-20 13:55:27 +0100274 memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
275 ieee80211_apply_htcap_overrides(sdata, &ht_cap);
276
Johannes Berg66e67e42012-01-20 13:55:27 +0100277 /* determine capability flags */
278 cap = ht_cap.cap;
279
Johannes Berg9dde6422012-05-16 23:43:19 +0200280 switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
Johannes Berg66e67e42012-01-20 13:55:27 +0100281 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
282 if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
283 cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
284 cap &= ~IEEE80211_HT_CAP_SGI_40;
285 }
286 break;
287 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
288 if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
289 cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
290 cap &= ~IEEE80211_HT_CAP_SGI_40;
291 }
292 break;
293 }
294
Johannes Berg24398e32012-03-28 10:58:36 +0200295 /*
296 * If 40 MHz was disabled associate as though we weren't
297 * capable of 40 MHz -- some broken APs will never fall
298 * back to trying to transmit in 20 MHz.
299 */
300 if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_40MHZ) {
301 cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
302 cap &= ~IEEE80211_HT_CAP_SGI_40;
303 }
304
Johannes Berg66e67e42012-01-20 13:55:27 +0100305 /* set SM PS mode properly */
306 cap &= ~IEEE80211_HT_CAP_SM_PS;
307 switch (smps) {
308 case IEEE80211_SMPS_AUTOMATIC:
309 case IEEE80211_SMPS_NUM_MODES:
310 WARN_ON(1);
311 case IEEE80211_SMPS_OFF:
312 cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
313 IEEE80211_HT_CAP_SM_PS_SHIFT;
314 break;
315 case IEEE80211_SMPS_STATIC:
316 cap |= WLAN_HT_CAP_SM_PS_STATIC <<
317 IEEE80211_HT_CAP_SM_PS_SHIFT;
318 break;
319 case IEEE80211_SMPS_DYNAMIC:
320 cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
321 IEEE80211_HT_CAP_SM_PS_SHIFT;
322 break;
323 }
324
325 /* reserve and fill IE */
326 pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
327 ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
328}
329
Mahesh Palivelad545dab2012-07-24 03:33:10 +0000330static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
331 struct sk_buff *skb,
332 struct ieee80211_supported_band *sband)
333{
334 u8 *pos;
335 u32 cap;
336 struct ieee80211_sta_vht_cap vht_cap;
337
338 BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));
339
340 memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
341
342 /* determine capability flags */
343 cap = vht_cap.cap;
344
345 /* reserve and fill IE */
346 pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2);
347 ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
348}
349
Johannes Berg66e67e42012-01-20 13:55:27 +0100350static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
351{
352 struct ieee80211_local *local = sdata->local;
353 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
354 struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
355 struct sk_buff *skb;
356 struct ieee80211_mgmt *mgmt;
357 u8 *pos, qos_info;
358 size_t offset = 0, noffset;
359 int i, count, rates_len, supp_rates_len;
360 u16 capab;
361 struct ieee80211_supported_band *sband;
362 u32 rates = 0;
Johannes Berg66e67e42012-01-20 13:55:27 +0100363
364 lockdep_assert_held(&ifmgd->mtx);
365
366 sband = local->hw.wiphy->bands[local->oper_channel->band];
367
368 if (assoc_data->supp_rates_len) {
369 /*
370 * Get all rates supported by the device and the AP as
371 * some APs don't like getting a superset of their rates
372 * in the association request (e.g. D-Link DAP 1353 in
373 * b-only mode)...
374 */
375 rates_len = ieee80211_compatible_rates(assoc_data->supp_rates,
376 assoc_data->supp_rates_len,
377 sband, &rates);
378 } else {
379 /*
380 * In case AP not provide any supported rates information
381 * before association, we send information element(s) with
382 * all rates that we support.
383 */
384 rates = ~0;
385 rates_len = sband->n_bitrates;
386 }
387
388 skb = alloc_skb(local->hw.extra_tx_headroom +
389 sizeof(*mgmt) + /* bit too much but doesn't matter */
390 2 + assoc_data->ssid_len + /* SSID */
391 4 + rates_len + /* (extended) rates */
392 4 + /* power capability */
393 2 + 2 * sband->n_channels + /* supported channels */
394 2 + sizeof(struct ieee80211_ht_cap) + /* HT */
Mahesh Palivelad545dab2012-07-24 03:33:10 +0000395 2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */
Johannes Berg66e67e42012-01-20 13:55:27 +0100396 assoc_data->ie_len + /* extra IEs */
397 9, /* WMM */
398 GFP_KERNEL);
399 if (!skb)
400 return;
401
402 skb_reserve(skb, local->hw.extra_tx_headroom);
403
404 capab = WLAN_CAPABILITY_ESS;
405
406 if (sband->band == IEEE80211_BAND_2GHZ) {
407 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
408 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
409 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
410 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
411 }
412
413 if (assoc_data->capability & WLAN_CAPABILITY_PRIVACY)
414 capab |= WLAN_CAPABILITY_PRIVACY;
415
416 if ((assoc_data->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
417 (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
418 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
419
420 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
421 memset(mgmt, 0, 24);
422 memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN);
423 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
424 memcpy(mgmt->bssid, assoc_data->bss->bssid, ETH_ALEN);
425
426 if (!is_zero_ether_addr(assoc_data->prev_bssid)) {
427 skb_put(skb, 10);
428 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
429 IEEE80211_STYPE_REASSOC_REQ);
430 mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
431 mgmt->u.reassoc_req.listen_interval =
432 cpu_to_le16(local->hw.conf.listen_interval);
433 memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid,
434 ETH_ALEN);
435 } else {
436 skb_put(skb, 4);
437 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
438 IEEE80211_STYPE_ASSOC_REQ);
439 mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
440 mgmt->u.assoc_req.listen_interval =
441 cpu_to_le16(local->hw.conf.listen_interval);
442 }
443
444 /* SSID */
445 pos = skb_put(skb, 2 + assoc_data->ssid_len);
446 *pos++ = WLAN_EID_SSID;
447 *pos++ = assoc_data->ssid_len;
448 memcpy(pos, assoc_data->ssid, assoc_data->ssid_len);
449
450 /* add all rates which were marked to be used above */
451 supp_rates_len = rates_len;
452 if (supp_rates_len > 8)
453 supp_rates_len = 8;
454
455 pos = skb_put(skb, supp_rates_len + 2);
456 *pos++ = WLAN_EID_SUPP_RATES;
457 *pos++ = supp_rates_len;
458
459 count = 0;
460 for (i = 0; i < sband->n_bitrates; i++) {
461 if (BIT(i) & rates) {
462 int rate = sband->bitrates[i].bitrate;
463 *pos++ = (u8) (rate / 5);
464 if (++count == 8)
465 break;
466 }
467 }
468
469 if (rates_len > count) {
470 pos = skb_put(skb, rates_len - count + 2);
471 *pos++ = WLAN_EID_EXT_SUPP_RATES;
472 *pos++ = rates_len - count;
473
474 for (i++; i < sband->n_bitrates; i++) {
475 if (BIT(i) & rates) {
476 int rate = sband->bitrates[i].bitrate;
477 *pos++ = (u8) (rate / 5);
478 }
479 }
480 }
481
482 if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
483 /* 1. power capabilities */
484 pos = skb_put(skb, 4);
485 *pos++ = WLAN_EID_PWR_CAPABILITY;
486 *pos++ = 2;
487 *pos++ = 0; /* min tx power */
488 *pos++ = local->oper_channel->max_power; /* max tx power */
489
490 /* 2. supported channels */
491 /* TODO: get this in reg domain format */
492 pos = skb_put(skb, 2 * sband->n_channels + 2);
493 *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
494 *pos++ = 2 * sband->n_channels;
495 for (i = 0; i < sband->n_channels; i++) {
496 *pos++ = ieee80211_frequency_to_channel(
497 sband->channels[i].center_freq);
498 *pos++ = 1; /* one channel in the subband*/
499 }
500 }
501
502 /* if present, add any custom IEs that go before HT */
503 if (assoc_data->ie_len && assoc_data->ie) {
504 static const u8 before_ht[] = {
505 WLAN_EID_SSID,
506 WLAN_EID_SUPP_RATES,
507 WLAN_EID_EXT_SUPP_RATES,
508 WLAN_EID_PWR_CAPABILITY,
509 WLAN_EID_SUPPORTED_CHANNELS,
510 WLAN_EID_RSN,
511 WLAN_EID_QOS_CAPA,
512 WLAN_EID_RRM_ENABLED_CAPABILITIES,
513 WLAN_EID_MOBILITY_DOMAIN,
514 WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
515 };
516 noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
517 before_ht, ARRAY_SIZE(before_ht),
518 offset);
519 pos = skb_put(skb, noffset - offset);
520 memcpy(pos, assoc_data->ie + offset, noffset - offset);
521 offset = noffset;
522 }
523
Johannes Berg4e74bfd2012-03-08 15:02:04 +0100524 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
Johannes Berg9dde6422012-05-16 23:43:19 +0200525 ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
Johannes Berg66e67e42012-01-20 13:55:27 +0100526 sband, local->oper_channel, ifmgd->ap_smps);
527
Mahesh Palivelad545dab2012-07-24 03:33:10 +0000528 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
529 ieee80211_add_vht_ie(sdata, skb, sband);
530
Johannes Berg66e67e42012-01-20 13:55:27 +0100531 /* if present, add any custom non-vendor IEs that go after HT */
532 if (assoc_data->ie_len && assoc_data->ie) {
533 noffset = ieee80211_ie_split_vendor(assoc_data->ie,
534 assoc_data->ie_len,
535 offset);
536 pos = skb_put(skb, noffset - offset);
537 memcpy(pos, assoc_data->ie + offset, noffset - offset);
538 offset = noffset;
539 }
540
Johannes Berg76f03032012-03-08 15:02:05 +0100541 if (assoc_data->wmm) {
542 if (assoc_data->uapsd) {
Eliad Pellerdc41e4d2012-03-14 16:15:03 +0200543 qos_info = ifmgd->uapsd_queues;
544 qos_info |= (ifmgd->uapsd_max_sp_len <<
Johannes Berg66e67e42012-01-20 13:55:27 +0100545 IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
546 } else {
547 qos_info = 0;
548 }
549
550 pos = skb_put(skb, 9);
551 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
552 *pos++ = 7; /* len */
553 *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
554 *pos++ = 0x50;
555 *pos++ = 0xf2;
556 *pos++ = 2; /* WME */
557 *pos++ = 0; /* WME info */
558 *pos++ = 1; /* WME ver */
559 *pos++ = qos_info;
560 }
561
562 /* add any remaining custom (i.e. vendor specific here) IEs */
563 if (assoc_data->ie_len && assoc_data->ie) {
564 noffset = assoc_data->ie_len;
565 pos = skb_put(skb, noffset - offset);
566 memcpy(pos, assoc_data->ie + offset, noffset - offset);
567 }
568
Johannes Berga1845fc2012-06-27 13:18:36 +0200569 drv_mgd_prepare_tx(local, sdata);
570
Johannes Berg66e67e42012-01-20 13:55:27 +0100571 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
572 ieee80211_tx_skb(sdata, skb);
573}
574
Kalle Valo572e0012009-02-10 17:09:31 +0200575void ieee80211_send_pspoll(struct ieee80211_local *local,
576 struct ieee80211_sub_if_data *sdata)
577{
Kalle Valo572e0012009-02-10 17:09:31 +0200578 struct ieee80211_pspoll *pspoll;
579 struct sk_buff *skb;
Kalle Valo572e0012009-02-10 17:09:31 +0200580
Kalle Valod8cd1892010-01-05 20:16:26 +0200581 skb = ieee80211_pspoll_get(&local->hw, &sdata->vif);
582 if (!skb)
Kalle Valo572e0012009-02-10 17:09:31 +0200583 return;
Kalle Valo572e0012009-02-10 17:09:31 +0200584
Kalle Valod8cd1892010-01-05 20:16:26 +0200585 pspoll = (struct ieee80211_pspoll *) skb->data;
586 pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
Kalle Valo572e0012009-02-10 17:09:31 +0200587
Johannes Berg62ae67b2009-11-18 18:42:05 +0100588 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
589 ieee80211_tx_skb(sdata, skb);
Kalle Valo572e0012009-02-10 17:09:31 +0200590}
591
Johannes Berg965beda2009-04-16 13:17:24 +0200592void ieee80211_send_nullfunc(struct ieee80211_local *local,
593 struct ieee80211_sub_if_data *sdata,
594 int powersave)
595{
596 struct sk_buff *skb;
Kalle Valod8cd1892010-01-05 20:16:26 +0200597 struct ieee80211_hdr_3addr *nullfunc;
Rajkumar Manoharanb6f35302011-09-29 20:34:04 +0530598 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Johannes Berg965beda2009-04-16 13:17:24 +0200599
Kalle Valod8cd1892010-01-05 20:16:26 +0200600 skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif);
601 if (!skb)
Johannes Berg965beda2009-04-16 13:17:24 +0200602 return;
603
Kalle Valod8cd1892010-01-05 20:16:26 +0200604 nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
Johannes Berg965beda2009-04-16 13:17:24 +0200605 if (powersave)
Kalle Valod8cd1892010-01-05 20:16:26 +0200606 nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
Johannes Berg965beda2009-04-16 13:17:24 +0200607
Johannes Berg62ae67b2009-11-18 18:42:05 +0100608 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
Rajkumar Manoharanb6f35302011-09-29 20:34:04 +0530609 if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
610 IEEE80211_STA_CONNECTION_POLL))
611 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
612
Johannes Berg62ae67b2009-11-18 18:42:05 +0100613 ieee80211_tx_skb(sdata, skb);
Johannes Berg965beda2009-04-16 13:17:24 +0200614}
615
Felix Fietkaud5242152010-01-08 18:06:26 +0100616static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
617 struct ieee80211_sub_if_data *sdata)
618{
619 struct sk_buff *skb;
620 struct ieee80211_hdr *nullfunc;
621 __le16 fc;
622
623 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
624 return;
625
626 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30);
Joe Perchesd15b8452011-08-29 14:17:31 -0700627 if (!skb)
Felix Fietkaud5242152010-01-08 18:06:26 +0100628 return;
Joe Perchesd15b8452011-08-29 14:17:31 -0700629
Felix Fietkaud5242152010-01-08 18:06:26 +0100630 skb_reserve(skb, local->hw.extra_tx_headroom);
631
632 nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30);
633 memset(nullfunc, 0, 30);
634 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
635 IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
636 nullfunc->frame_control = fc;
637 memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
638 memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
639 memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
640 memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN);
641
642 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
643 ieee80211_tx_skb(sdata, skb);
644}
645
Johannes Bergcc32abd2009-05-15 11:52:31 +0200646/* spectrum management related things */
647static void ieee80211_chswitch_work(struct work_struct *work)
648{
649 struct ieee80211_sub_if_data *sdata =
650 container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
Johannes Bergcc32abd2009-05-15 11:52:31 +0200651 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
652
Johannes Berg9607e6b2009-12-23 13:15:31 +0100653 if (!ieee80211_sdata_running(sdata))
Johannes Bergcc32abd2009-05-15 11:52:31 +0200654 return;
655
Johannes Berg77fdaa12009-07-07 03:45:17 +0200656 mutex_lock(&ifmgd->mtx);
657 if (!ifmgd->associated)
658 goto out;
Johannes Bergcc32abd2009-05-15 11:52:31 +0200659
660 sdata->local->oper_channel = sdata->local->csa_channel;
Johannes Berg5ce6e432010-05-11 16:20:57 +0200661 if (!sdata->local->ops->channel_switch) {
662 /* call "hw_config" only if doing sw channel switch */
663 ieee80211_hw_config(sdata->local,
664 IEEE80211_CONF_CHANGE_CHANNEL);
Shahar Levi1ea57b12011-09-08 08:44:05 +0300665 } else {
666 /* update the device channel directly */
667 sdata->local->hw.conf.channel = sdata->local->oper_channel;
Johannes Berg5ce6e432010-05-11 16:20:57 +0200668 }
Johannes Bergcc32abd2009-05-15 11:52:31 +0200669
Johannes Berg77fdaa12009-07-07 03:45:17 +0200670 /* XXX: shouldn't really modify cfg80211-owned data! */
Johannes Berg0c1ad2c2009-12-23 13:15:39 +0100671 ifmgd->associated->channel = sdata->local->oper_channel;
Johannes Berg77fdaa12009-07-07 03:45:17 +0200672
Johannes Berg57eebdf2012-08-01 15:50:46 +0200673 /* XXX: wait for a beacon first? */
Johannes Bergcc32abd2009-05-15 11:52:31 +0200674 ieee80211_wake_queues_by_reason(&sdata->local->hw,
675 IEEE80211_QUEUE_STOP_REASON_CSA);
Johannes Berg77fdaa12009-07-07 03:45:17 +0200676 out:
677 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
678 mutex_unlock(&ifmgd->mtx);
Johannes Bergcc32abd2009-05-15 11:52:31 +0200679}
680
Johannes Berg5ce6e432010-05-11 16:20:57 +0200681void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
682{
683 struct ieee80211_sub_if_data *sdata;
684 struct ieee80211_if_managed *ifmgd;
685
686 sdata = vif_to_sdata(vif);
687 ifmgd = &sdata->u.mgd;
688
689 trace_api_chswitch_done(sdata, success);
690 if (!success) {
Johannes Berg882a7c62012-08-01 22:32:45 +0200691 sdata_info(sdata,
692 "driver channel switch failed, disconnecting\n");
693 ieee80211_queue_work(&sdata->local->hw,
694 &ifmgd->csa_connection_drop_work);
695 } else {
696 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
Johannes Berg5ce6e432010-05-11 16:20:57 +0200697 }
Johannes Berg5ce6e432010-05-11 16:20:57 +0200698}
699EXPORT_SYMBOL(ieee80211_chswitch_done);
700
Johannes Bergcc32abd2009-05-15 11:52:31 +0200701static void ieee80211_chswitch_timer(unsigned long data)
702{
703 struct ieee80211_sub_if_data *sdata =
704 (struct ieee80211_sub_if_data *) data;
705 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
706
Johannes Berg5bb644a2009-05-17 11:40:42 +0200707 if (sdata->local->quiescing) {
708 set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
709 return;
710 }
711
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -0400712 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
Johannes Bergcc32abd2009-05-15 11:52:31 +0200713}
714
715void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
716 struct ieee80211_channel_sw_ie *sw_elem,
Johannes Berg5ce6e432010-05-11 16:20:57 +0200717 struct ieee80211_bss *bss,
718 u64 timestamp)
Johannes Bergcc32abd2009-05-15 11:52:31 +0200719{
Johannes Berg0c1ad2c2009-12-23 13:15:39 +0100720 struct cfg80211_bss *cbss =
721 container_of((void *)bss, struct cfg80211_bss, priv);
Johannes Bergcc32abd2009-05-15 11:52:31 +0200722 struct ieee80211_channel *new_ch;
723 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Bruno Randolf59eb21a2011-01-17 13:37:28 +0900724 int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num,
725 cbss->channel->band);
Johannes Bergcc32abd2009-05-15 11:52:31 +0200726
Johannes Berg77fdaa12009-07-07 03:45:17 +0200727 ASSERT_MGD_MTX(ifmgd);
728
729 if (!ifmgd->associated)
Johannes Bergcc32abd2009-05-15 11:52:31 +0200730 return;
731
Helmut Schaafbe9c422009-07-23 12:14:04 +0200732 if (sdata->local->scanning)
Johannes Bergcc32abd2009-05-15 11:52:31 +0200733 return;
734
735 /* Disregard subsequent beacons if we are already running a timer
736 processing a CSA */
737
738 if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
739 return;
740
741 new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
Johannes Berg882a7c62012-08-01 22:32:45 +0200742 if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
743 sdata_info(sdata,
744 "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
745 ifmgd->associated->bssid, new_freq);
746 ieee80211_queue_work(&sdata->local->hw,
747 &ifmgd->csa_connection_drop_work);
Johannes Bergcc32abd2009-05-15 11:52:31 +0200748 return;
Johannes Berg882a7c62012-08-01 22:32:45 +0200749 }
Johannes Bergcc32abd2009-05-15 11:52:31 +0200750
751 sdata->local->csa_channel = new_ch;
752
Johannes Berg57eebdf2012-08-01 15:50:46 +0200753 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
754
755 if (sw_elem->mode)
756 ieee80211_stop_queues_by_reason(&sdata->local->hw,
757 IEEE80211_QUEUE_STOP_REASON_CSA);
758
Johannes Berg5ce6e432010-05-11 16:20:57 +0200759 if (sdata->local->ops->channel_switch) {
760 /* use driver's channel switch callback */
Johannes Berg57eebdf2012-08-01 15:50:46 +0200761 struct ieee80211_channel_switch ch_switch = {
762 .timestamp = timestamp,
763 .block_tx = sw_elem->mode,
764 .channel = new_ch,
765 .count = sw_elem->count,
766 };
767
Johannes Berg5ce6e432010-05-11 16:20:57 +0200768 drv_channel_switch(sdata->local, &ch_switch);
769 return;
770 }
771
772 /* channel switch handled in software */
Johannes Berg57eebdf2012-08-01 15:50:46 +0200773 if (sw_elem->count <= 1)
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -0400774 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
Johannes Berg57eebdf2012-08-01 15:50:46 +0200775 else
Johannes Bergcc32abd2009-05-15 11:52:31 +0200776 mod_timer(&ifmgd->chswitch_timer,
Johannes Berg30490002012-08-01 15:53:45 +0200777 TU_TO_EXP_TIME(sw_elem->count *
778 cbss->beacon_interval));
Johannes Bergcc32abd2009-05-15 11:52:31 +0200779}
780
781static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
Johannes Berg04b7b2f2012-09-05 13:41:37 +0200782 struct ieee80211_channel *channel,
783 const u8 *country_ie, u8 country_ie_len,
784 const u8 *pwr_constr_elem)
Johannes Bergcc32abd2009-05-15 11:52:31 +0200785{
Johannes Berg04b7b2f2012-09-05 13:41:37 +0200786 struct ieee80211_country_ie_triplet *triplet;
787 int chan = ieee80211_frequency_to_channel(channel->center_freq);
788 int i, chan_pwr, chan_increment, new_ap_level;
789 bool have_chan_pwr = false;
Johannes Bergcc32abd2009-05-15 11:52:31 +0200790
Johannes Berg04b7b2f2012-09-05 13:41:37 +0200791 /* Invalid IE */
792 if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
Johannes Bergcc32abd2009-05-15 11:52:31 +0200793 return;
794
Johannes Berg04b7b2f2012-09-05 13:41:37 +0200795 triplet = (void *)(country_ie + 3);
796 country_ie_len -= 3;
797
798 switch (channel->band) {
799 default:
800 WARN_ON_ONCE(1);
801 /* fall through */
802 case IEEE80211_BAND_2GHZ:
803 case IEEE80211_BAND_60GHZ:
804 chan_increment = 1;
805 break;
806 case IEEE80211_BAND_5GHZ:
807 chan_increment = 4;
808 break;
Johannes Bergcc32abd2009-05-15 11:52:31 +0200809 }
Johannes Berg04b7b2f2012-09-05 13:41:37 +0200810
811 /* find channel */
812 while (country_ie_len >= 3) {
813 u8 first_channel = triplet->chans.first_channel;
814
815 if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID)
816 goto next;
817
818 for (i = 0; i < triplet->chans.num_channels; i++) {
819 if (first_channel + i * chan_increment == chan) {
820 have_chan_pwr = true;
821 chan_pwr = triplet->chans.max_power;
822 break;
823 }
824 }
825 if (have_chan_pwr)
826 break;
827
828 next:
829 triplet++;
830 country_ie_len -= 3;
831 }
832
833 if (!have_chan_pwr)
834 return;
835
836 new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
837
838 if (sdata->local->ap_power_level == new_ap_level)
839 return;
840
841 sdata_info(sdata,
842 "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
843 new_ap_level, chan_pwr, *pwr_constr_elem,
844 sdata->u.mgd.bssid);
845 sdata->local->ap_power_level = new_ap_level;
846 ieee80211_hw_config(sdata->local, 0);
Johannes Bergcc32abd2009-05-15 11:52:31 +0200847}
848
Juuso Oikarinenf90754c2010-06-21 08:59:39 +0300849void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
850{
851 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
852 struct ieee80211_local *local = sdata->local;
853 struct ieee80211_conf *conf = &local->hw.conf;
854
855 WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
856 !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
857 (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
858
859 local->disable_dynamic_ps = false;
860 conf->dynamic_ps_timeout = local->dynamic_ps_user_timeout;
861}
862EXPORT_SYMBOL(ieee80211_enable_dyn_ps);
863
864void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif)
865{
866 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
867 struct ieee80211_local *local = sdata->local;
868 struct ieee80211_conf *conf = &local->hw.conf;
869
870 WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
871 !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
872 (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
873
874 local->disable_dynamic_ps = true;
875 conf->dynamic_ps_timeout = 0;
876 del_timer_sync(&local->dynamic_ps_timer);
877 ieee80211_queue_work(&local->hw,
878 &local->dynamic_ps_enable_work);
879}
880EXPORT_SYMBOL(ieee80211_disable_dyn_ps);
881
Johannes Berg965beda2009-04-16 13:17:24 +0200882/* powersave */
883static void ieee80211_enable_ps(struct ieee80211_local *local,
884 struct ieee80211_sub_if_data *sdata)
885{
886 struct ieee80211_conf *conf = &local->hw.conf;
887
Johannes Bergd5edaed2009-04-22 23:02:51 +0200888 /*
889 * If we are scanning right now then the parameters will
890 * take effect when scan finishes.
891 */
Helmut Schaafbe9c422009-07-23 12:14:04 +0200892 if (local->scanning)
Johannes Bergd5edaed2009-04-22 23:02:51 +0200893 return;
894
Johannes Berg965beda2009-04-16 13:17:24 +0200895 if (conf->dynamic_ps_timeout > 0 &&
896 !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) {
897 mod_timer(&local->dynamic_ps_timer, jiffies +
898 msecs_to_jiffies(conf->dynamic_ps_timeout));
899 } else {
900 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
901 ieee80211_send_nullfunc(local, sdata, 1);
Vivek Natarajan375177b2010-02-09 14:50:28 +0530902
Juuso Oikarinen2a130522010-03-09 14:25:02 +0200903 if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
904 (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
905 return;
906
907 conf->flags |= IEEE80211_CONF_PS;
908 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
Johannes Berg965beda2009-04-16 13:17:24 +0200909 }
910}
911
912static void ieee80211_change_ps(struct ieee80211_local *local)
913{
914 struct ieee80211_conf *conf = &local->hw.conf;
915
916 if (local->ps_sdata) {
Johannes Berg965beda2009-04-16 13:17:24 +0200917 ieee80211_enable_ps(local, local->ps_sdata);
918 } else if (conf->flags & IEEE80211_CONF_PS) {
919 conf->flags &= ~IEEE80211_CONF_PS;
920 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
921 del_timer_sync(&local->dynamic_ps_timer);
922 cancel_work_sync(&local->dynamic_ps_enable_work);
923 }
924}
925
Jason Young808118c2011-03-10 16:43:19 -0800926static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
927{
928 struct ieee80211_if_managed *mgd = &sdata->u.mgd;
929 struct sta_info *sta = NULL;
Johannes Bergc2c98fd2011-09-29 16:04:36 +0200930 bool authorized = false;
Jason Young808118c2011-03-10 16:43:19 -0800931
932 if (!mgd->powersave)
933 return false;
934
Johannes Berg05cb9102011-10-28 11:59:47 +0200935 if (mgd->broken_ap)
936 return false;
937
Jason Young808118c2011-03-10 16:43:19 -0800938 if (!mgd->associated)
939 return false;
940
Jason Young808118c2011-03-10 16:43:19 -0800941 if (mgd->flags & (IEEE80211_STA_BEACON_POLL |
942 IEEE80211_STA_CONNECTION_POLL))
943 return false;
944
945 rcu_read_lock();
946 sta = sta_info_get(sdata, mgd->bssid);
947 if (sta)
Johannes Bergc2c98fd2011-09-29 16:04:36 +0200948 authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
Jason Young808118c2011-03-10 16:43:19 -0800949 rcu_read_unlock();
950
Johannes Bergc2c98fd2011-09-29 16:04:36 +0200951 return authorized;
Jason Young808118c2011-03-10 16:43:19 -0800952}
953
Johannes Berg965beda2009-04-16 13:17:24 +0200954/* need to hold RTNL or interface lock */
Johannes Berg10f644a2009-04-16 13:17:25 +0200955void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
Johannes Berg965beda2009-04-16 13:17:24 +0200956{
957 struct ieee80211_sub_if_data *sdata, *found = NULL;
958 int count = 0;
Juuso Oikarinen195e2942010-04-27 12:47:40 +0300959 int timeout;
Johannes Berg965beda2009-04-16 13:17:24 +0200960
961 if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
962 local->ps_sdata = NULL;
963 return;
964 }
965
966 list_for_each_entry(sdata, &local->interfaces, list) {
Johannes Berg9607e6b2009-12-23 13:15:31 +0100967 if (!ieee80211_sdata_running(sdata))
Johannes Berg965beda2009-04-16 13:17:24 +0200968 continue;
Rajkumar Manoharan8c7914d2011-02-01 00:28:59 +0530969 if (sdata->vif.type == NL80211_IFTYPE_AP) {
970 /* If an AP vif is found, then disable PS
971 * by setting the count to zero thereby setting
972 * ps_sdata to NULL.
973 */
974 count = 0;
975 break;
976 }
Johannes Berg965beda2009-04-16 13:17:24 +0200977 if (sdata->vif.type != NL80211_IFTYPE_STATION)
978 continue;
979 found = sdata;
980 count++;
981 }
982
Jason Young808118c2011-03-10 16:43:19 -0800983 if (count == 1 && ieee80211_powersave_allowed(found)) {
Juuso Oikarinenf90754c2010-06-21 08:59:39 +0300984 struct ieee80211_conf *conf = &local->hw.conf;
Johannes Berg10f644a2009-04-16 13:17:25 +0200985 s32 beaconint_us;
986
987 if (latency < 0)
Mark Grossed771342010-05-06 01:59:26 +0200988 latency = pm_qos_request(PM_QOS_NETWORK_LATENCY);
Johannes Berg10f644a2009-04-16 13:17:25 +0200989
990 beaconint_us = ieee80211_tu_to_usec(
991 found->vif.bss_conf.beacon_int);
992
Juuso Oikarinenff616382010-06-09 09:51:52 +0300993 timeout = local->dynamic_ps_forced_timeout;
Juuso Oikarinen195e2942010-04-27 12:47:40 +0300994 if (timeout < 0) {
995 /*
Juuso Oikarinenff616382010-06-09 09:51:52 +0300996 * Go to full PSM if the user configures a very low
997 * latency requirement.
Eliad Peller0ab82b02010-12-03 02:16:23 +0200998 * The 2000 second value is there for compatibility
999 * until the PM_QOS_NETWORK_LATENCY is configured
1000 * with real values.
Juuso Oikarinen195e2942010-04-27 12:47:40 +03001001 */
Eliad Peller0ab82b02010-12-03 02:16:23 +02001002 if (latency > (1900 * USEC_PER_MSEC) &&
1003 latency != (2000 * USEC_PER_SEC))
Juuso Oikarinen195e2942010-04-27 12:47:40 +03001004 timeout = 0;
Juuso Oikarinenff616382010-06-09 09:51:52 +03001005 else
1006 timeout = 100;
Juuso Oikarinen195e2942010-04-27 12:47:40 +03001007 }
Juuso Oikarinenf90754c2010-06-21 08:59:39 +03001008 local->dynamic_ps_user_timeout = timeout;
1009 if (!local->disable_dynamic_ps)
1010 conf->dynamic_ps_timeout =
1011 local->dynamic_ps_user_timeout;
Juuso Oikarinen195e2942010-04-27 12:47:40 +03001012
Johannes Berg04fe2032009-04-22 18:44:37 +02001013 if (beaconint_us > latency) {
Johannes Berg10f644a2009-04-16 13:17:25 +02001014 local->ps_sdata = NULL;
Johannes Berg04fe2032009-04-22 18:44:37 +02001015 } else {
Johannes Berg56007a02010-01-26 14:19:52 +01001016 struct ieee80211_bss *bss;
Johannes Berg04fe2032009-04-22 18:44:37 +02001017 int maxslp = 1;
Johannes Berg56007a02010-01-26 14:19:52 +01001018 u8 dtimper;
Johannes Berg04fe2032009-04-22 18:44:37 +02001019
Johannes Berg56007a02010-01-26 14:19:52 +01001020 bss = (void *)found->u.mgd.associated->priv;
1021 dtimper = bss->dtim_period;
1022
1023 /* If the TIM IE is invalid, pretend the value is 1 */
1024 if (!dtimper)
1025 dtimper = 1;
1026 else if (dtimper > 1)
Johannes Berg04fe2032009-04-22 18:44:37 +02001027 maxslp = min_t(int, dtimper,
1028 latency / beaconint_us);
1029
Johannes Berg9ccebe62009-04-23 10:32:36 +02001030 local->hw.conf.max_sleep_period = maxslp;
Johannes Berg56007a02010-01-26 14:19:52 +01001031 local->hw.conf.ps_dtim_period = dtimper;
Johannes Berg10f644a2009-04-16 13:17:25 +02001032 local->ps_sdata = found;
Johannes Berg04fe2032009-04-22 18:44:37 +02001033 }
Johannes Berg10f644a2009-04-16 13:17:25 +02001034 } else {
Johannes Berg965beda2009-04-16 13:17:24 +02001035 local->ps_sdata = NULL;
Johannes Berg10f644a2009-04-16 13:17:25 +02001036 }
Johannes Berg965beda2009-04-16 13:17:24 +02001037
1038 ieee80211_change_ps(local);
1039}
1040
Eliad Pellerab095872012-07-27 12:33:22 +03001041void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata)
1042{
1043 bool ps_allowed = ieee80211_powersave_allowed(sdata);
1044
1045 if (sdata->vif.bss_conf.ps != ps_allowed) {
1046 sdata->vif.bss_conf.ps = ps_allowed;
1047 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_PS);
1048 }
1049}
1050
Johannes Berg965beda2009-04-16 13:17:24 +02001051void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
1052{
1053 struct ieee80211_local *local =
1054 container_of(work, struct ieee80211_local,
1055 dynamic_ps_disable_work);
1056
1057 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
1058 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
1059 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
1060 }
1061
1062 ieee80211_wake_queues_by_reason(&local->hw,
1063 IEEE80211_QUEUE_STOP_REASON_PS);
1064}
1065
1066void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
1067{
1068 struct ieee80211_local *local =
1069 container_of(work, struct ieee80211_local,
1070 dynamic_ps_enable_work);
1071 struct ieee80211_sub_if_data *sdata = local->ps_sdata;
Christian Lamparter5e340692011-06-30 21:08:43 +02001072 struct ieee80211_if_managed *ifmgd;
Rajkumar Manoharan1ddc2862011-05-03 17:03:59 +05301073 unsigned long flags;
1074 int q;
Johannes Berg965beda2009-04-16 13:17:24 +02001075
1076 /* can only happen when PS was just disabled anyway */
1077 if (!sdata)
1078 return;
1079
Christian Lamparter5e340692011-06-30 21:08:43 +02001080 ifmgd = &sdata->u.mgd;
1081
Johannes Berg965beda2009-04-16 13:17:24 +02001082 if (local->hw.conf.flags & IEEE80211_CONF_PS)
1083 return;
1084
Arik Nemtsov77b70232011-06-26 12:06:54 +03001085 if (!local->disable_dynamic_ps &&
1086 local->hw.conf.dynamic_ps_timeout > 0) {
1087 /* don't enter PS if TX frames are pending */
1088 if (drv_tx_frames_pending(local)) {
Rajkumar Manoharan1ddc2862011-05-03 17:03:59 +05301089 mod_timer(&local->dynamic_ps_timer, jiffies +
1090 msecs_to_jiffies(
1091 local->hw.conf.dynamic_ps_timeout));
1092 return;
1093 }
Arik Nemtsov77b70232011-06-26 12:06:54 +03001094
1095 /*
1096 * transmission can be stopped by others which leads to
1097 * dynamic_ps_timer expiry. Postpone the ps timer if it
1098 * is not the actual idle state.
1099 */
1100 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
1101 for (q = 0; q < local->hw.queues; q++) {
1102 if (local->queue_stop_reasons[q]) {
1103 spin_unlock_irqrestore(&local->queue_stop_reason_lock,
1104 flags);
1105 mod_timer(&local->dynamic_ps_timer, jiffies +
1106 msecs_to_jiffies(
1107 local->hw.conf.dynamic_ps_timeout));
1108 return;
1109 }
1110 }
1111 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
Rajkumar Manoharan1ddc2862011-05-03 17:03:59 +05301112 }
Rajkumar Manoharan1ddc2862011-05-03 17:03:59 +05301113
Vivek Natarajan375177b2010-02-09 14:50:28 +05301114 if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
Mohammed Shafi Shajakhan9c38a8b2011-12-14 19:46:07 +05301115 !(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
Vivek Natarajanf3e85b92011-02-23 13:04:32 +05301116 netif_tx_stop_all_queues(sdata->dev);
Johannes Berg965beda2009-04-16 13:17:24 +02001117
Vivek Natarajane8306f92011-04-06 11:41:10 +05301118 if (drv_tx_frames_pending(local))
1119 mod_timer(&local->dynamic_ps_timer, jiffies +
1120 msecs_to_jiffies(
1121 local->hw.conf.dynamic_ps_timeout));
1122 else {
1123 ieee80211_send_nullfunc(local, sdata, 1);
1124 /* Flush to get the tx status of nullfunc frame */
1125 drv_flush(local, false);
1126 }
Vivek Natarajanf3e85b92011-02-23 13:04:32 +05301127 }
1128
Juuso Oikarinen2a130522010-03-09 14:25:02 +02001129 if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
1130 (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) ||
Vivek Natarajan375177b2010-02-09 14:50:28 +05301131 (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
1132 ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
1133 local->hw.conf.flags |= IEEE80211_CONF_PS;
1134 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
1135 }
Vivek Natarajanf3e85b92011-02-23 13:04:32 +05301136
Arik Nemtsov77b70232011-06-26 12:06:54 +03001137 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
1138 netif_tx_wake_all_queues(sdata->dev);
Johannes Berg965beda2009-04-16 13:17:24 +02001139}
1140
1141void ieee80211_dynamic_ps_timer(unsigned long data)
1142{
1143 struct ieee80211_local *local = (void *) data;
1144
Luis R. Rodriguez78f1a8b2009-07-27 08:38:25 -07001145 if (local->quiescing || local->suspended)
Johannes Berg5bb644a2009-05-17 11:40:42 +02001146 return;
1147
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04001148 ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
Johannes Berg965beda2009-04-16 13:17:24 +02001149}
1150
Johannes Berg60f8b392008-09-08 17:44:22 +02001151/* MLME */
Johannes Berg7d257452012-07-06 17:37:43 +02001152static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
Johannes Berg4ced3f72010-07-19 16:39:04 +02001153 struct ieee80211_sub_if_data *sdata,
Jiri Bencf0706e82007-05-05 11:45:53 -07001154 u8 *wmm_param, size_t wmm_param_len)
1155{
Jiri Bencf0706e82007-05-05 11:45:53 -07001156 struct ieee80211_tx_queue_params params;
Johannes Berg4ced3f72010-07-19 16:39:04 +02001157 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Jiri Bencf0706e82007-05-05 11:45:53 -07001158 size_t left;
1159 int count;
Kalle Valoab133152010-01-12 10:42:31 +02001160 u8 *pos, uapsd_queues = 0;
Jiri Bencf0706e82007-05-05 11:45:53 -07001161
Stanislaw Gruszkae1b3ec12010-03-29 12:18:34 +02001162 if (!local->ops->conf_tx)
Johannes Berg7d257452012-07-06 17:37:43 +02001163 return false;
Stanislaw Gruszkae1b3ec12010-03-29 12:18:34 +02001164
Johannes Berg32c50572012-03-28 11:04:29 +02001165 if (local->hw.queues < IEEE80211_NUM_ACS)
Johannes Berg7d257452012-07-06 17:37:43 +02001166 return false;
Johannes Berg3434fbd2008-05-03 00:59:37 +02001167
1168 if (!wmm_param)
Johannes Berg7d257452012-07-06 17:37:43 +02001169 return false;
Johannes Berg3434fbd2008-05-03 00:59:37 +02001170
Jiri Bencf0706e82007-05-05 11:45:53 -07001171 if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
Johannes Berg7d257452012-07-06 17:37:43 +02001172 return false;
Kalle Valoab133152010-01-12 10:42:31 +02001173
1174 if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
Eliad Pellerdc41e4d2012-03-14 16:15:03 +02001175 uapsd_queues = ifmgd->uapsd_queues;
Kalle Valoab133152010-01-12 10:42:31 +02001176
Jiri Bencf0706e82007-05-05 11:45:53 -07001177 count = wmm_param[6] & 0x0f;
Johannes Berg46900292009-02-15 12:44:28 +01001178 if (count == ifmgd->wmm_last_param_set)
Johannes Berg7d257452012-07-06 17:37:43 +02001179 return false;
Johannes Berg46900292009-02-15 12:44:28 +01001180 ifmgd->wmm_last_param_set = count;
Jiri Bencf0706e82007-05-05 11:45:53 -07001181
1182 pos = wmm_param + 8;
1183 left = wmm_param_len - 8;
1184
1185 memset(&params, 0, sizeof(params));
1186
Yoni Divinsky00e96de2012-06-20 15:39:13 +03001187 sdata->wmm_acm = 0;
Jiri Bencf0706e82007-05-05 11:45:53 -07001188 for (; left >= 4; left -= 4, pos += 4) {
1189 int aci = (pos[0] >> 5) & 0x03;
1190 int acm = (pos[0] >> 4) & 0x01;
Kalle Valoab133152010-01-12 10:42:31 +02001191 bool uapsd = false;
Jiri Bencf0706e82007-05-05 11:45:53 -07001192 int queue;
1193
1194 switch (aci) {
Jouni Malinen0eeb59f2009-03-05 17:23:46 +02001195 case 1: /* AC_BK */
Johannes Berge100bb62008-04-30 18:51:21 +02001196 queue = 3;
Johannes Berg988c0f72008-04-17 19:21:22 +02001197 if (acm)
Yoni Divinsky00e96de2012-06-20 15:39:13 +03001198 sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
Kalle Valoab133152010-01-12 10:42:31 +02001199 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
1200 uapsd = true;
Jiri Bencf0706e82007-05-05 11:45:53 -07001201 break;
Jouni Malinen0eeb59f2009-03-05 17:23:46 +02001202 case 2: /* AC_VI */
Johannes Berge100bb62008-04-30 18:51:21 +02001203 queue = 1;
Johannes Berg988c0f72008-04-17 19:21:22 +02001204 if (acm)
Yoni Divinsky00e96de2012-06-20 15:39:13 +03001205 sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
Kalle Valoab133152010-01-12 10:42:31 +02001206 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
1207 uapsd = true;
Jiri Bencf0706e82007-05-05 11:45:53 -07001208 break;
Jouni Malinen0eeb59f2009-03-05 17:23:46 +02001209 case 3: /* AC_VO */
Johannes Berge100bb62008-04-30 18:51:21 +02001210 queue = 0;
Johannes Berg988c0f72008-04-17 19:21:22 +02001211 if (acm)
Yoni Divinsky00e96de2012-06-20 15:39:13 +03001212 sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
Kalle Valoab133152010-01-12 10:42:31 +02001213 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
1214 uapsd = true;
Jiri Bencf0706e82007-05-05 11:45:53 -07001215 break;
Jouni Malinen0eeb59f2009-03-05 17:23:46 +02001216 case 0: /* AC_BE */
Jiri Bencf0706e82007-05-05 11:45:53 -07001217 default:
Johannes Berge100bb62008-04-30 18:51:21 +02001218 queue = 2;
Johannes Berg988c0f72008-04-17 19:21:22 +02001219 if (acm)
Yoni Divinsky00e96de2012-06-20 15:39:13 +03001220 sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
Kalle Valoab133152010-01-12 10:42:31 +02001221 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
1222 uapsd = true;
Jiri Bencf0706e82007-05-05 11:45:53 -07001223 break;
1224 }
1225
1226 params.aifs = pos[0] & 0x0f;
1227 params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
1228 params.cw_min = ecw2cw(pos[1] & 0x0f);
Johannes Bergf434b2d2008-07-10 11:22:31 +02001229 params.txop = get_unaligned_le16(pos + 2);
Kalle Valoab133152010-01-12 10:42:31 +02001230 params.uapsd = uapsd;
1231
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02001232 mlme_dbg(sdata,
1233 "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
1234 queue, aci, acm,
1235 params.aifs, params.cw_min, params.cw_max,
1236 params.txop, params.uapsd);
Eliad Pellerf6f3def2011-09-25 20:06:54 +03001237 sdata->tx_conf[queue] = params;
1238 if (drv_conf_tx(local, sdata, queue, &params))
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02001239 sdata_err(sdata,
1240 "failed to set TX queue parameters for queue %d\n",
1241 queue);
Jiri Bencf0706e82007-05-05 11:45:53 -07001242 }
Stanislaw Gruszkae1b3ec12010-03-29 12:18:34 +02001243
1244 /* enable WMM or activate new settings */
Johannes Berg4ced3f72010-07-19 16:39:04 +02001245 sdata->vif.bss_conf.qos = true;
Johannes Berg7d257452012-07-06 17:37:43 +02001246 return true;
Jiri Bencf0706e82007-05-05 11:45:53 -07001247}
1248
Stanislaw Gruszka925e64c2012-05-16 15:27:20 +02001249static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
1250{
1251 lockdep_assert_held(&sdata->local->mtx);
1252
1253 sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
1254 IEEE80211_STA_BEACON_POLL);
1255 ieee80211_run_deferred_scan(sdata->local);
1256}
1257
1258static void ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
1259{
1260 mutex_lock(&sdata->local->mtx);
1261 __ieee80211_stop_poll(sdata);
1262 mutex_unlock(&sdata->local->mtx);
1263}
1264
Johannes Berg7a5158e2008-10-08 10:59:33 +02001265static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
1266 u16 capab, bool erp_valid, u8 erp)
Daniel Drake56282212007-07-10 19:32:10 +02001267{
Johannes Bergbda39332008-10-11 01:51:51 +02001268 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
Johannes Berg471b3ef2007-12-28 14:32:58 +01001269 u32 changed = 0;
Johannes Berg7a5158e2008-10-08 10:59:33 +02001270 bool use_protection;
1271 bool use_short_preamble;
1272 bool use_short_slot;
1273
1274 if (erp_valid) {
1275 use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0;
1276 use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0;
1277 } else {
1278 use_protection = false;
1279 use_short_preamble = !!(capab & WLAN_CAPABILITY_SHORT_PREAMBLE);
1280 }
1281
1282 use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
Johannes Berg568d6e22012-07-23 14:29:21 +02001283 if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ)
Felix Fietkau43d35342010-01-15 03:00:48 +01001284 use_short_slot = true;
Daniel Drake56282212007-07-10 19:32:10 +02001285
Johannes Berg471b3ef2007-12-28 14:32:58 +01001286 if (use_protection != bss_conf->use_cts_prot) {
Johannes Berg471b3ef2007-12-28 14:32:58 +01001287 bss_conf->use_cts_prot = use_protection;
1288 changed |= BSS_CHANGED_ERP_CTS_PROT;
Daniel Drake56282212007-07-10 19:32:10 +02001289 }
Daniel Drake7e9ed182007-07-27 15:43:24 +02001290
Vladimir Koutnyd43c7b32008-03-31 17:05:03 +02001291 if (use_short_preamble != bss_conf->use_short_preamble) {
Vladimir Koutnyd43c7b32008-03-31 17:05:03 +02001292 bss_conf->use_short_preamble = use_short_preamble;
Johannes Berg471b3ef2007-12-28 14:32:58 +01001293 changed |= BSS_CHANGED_ERP_PREAMBLE;
Daniel Drake7e9ed182007-07-27 15:43:24 +02001294 }
Daniel Draked9430a32007-07-27 15:43:24 +02001295
Johannes Berg7a5158e2008-10-08 10:59:33 +02001296 if (use_short_slot != bss_conf->use_short_slot) {
Johannes Berg7a5158e2008-10-08 10:59:33 +02001297 bss_conf->use_short_slot = use_short_slot;
1298 changed |= BSS_CHANGED_ERP_SLOT;
John W. Linville50c4afb2008-04-15 14:09:27 -04001299 }
1300
1301 return changed;
1302}
1303
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +12001304static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01001305 struct cfg80211_bss *cbss,
Johannes Bergae5eb022008-10-14 16:58:37 +02001306 u32 bss_info_changed)
Jiri Bencf0706e82007-05-05 11:45:53 -07001307{
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01001308 struct ieee80211_bss *bss = (void *)cbss->priv;
Johannes Berg471b3ef2007-12-28 14:32:58 +01001309 struct ieee80211_local *local = sdata->local;
Juuso Oikarinen68542962010-06-09 13:43:26 +03001310 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001311
Johannes Bergae5eb022008-10-14 16:58:37 +02001312 bss_info_changed |= BSS_CHANGED_ASSOC;
Johannes Berg77fdaa12009-07-07 03:45:17 +02001313 bss_info_changed |= ieee80211_handle_bss_capability(sdata,
Luciano Coelho50ae34a2012-06-20 17:23:24 +03001314 bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value);
Tomas Winkler21c0cbe2008-03-28 16:33:34 -07001315
Felix Fietkau7ccc8bd2010-11-19 22:55:38 +01001316 sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(
1317 IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int));
1318
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01001319 sdata->u.mgd.associated = cbss;
1320 memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
Johannes Berg471b3ef2007-12-28 14:32:58 +01001321
Jouni Malinen17e4ec12010-03-29 23:28:30 -07001322 sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
1323
Johannes Bergb291ba12009-07-10 15:29:03 +02001324 /* just to be sure */
Stanislaw Gruszka925e64c2012-05-16 15:27:20 +02001325 ieee80211_stop_poll(sdata);
Johannes Bergb291ba12009-07-10 15:29:03 +02001326
Tomas Winklerf5e5bf22008-09-08 17:33:39 +02001327 ieee80211_led_assoc(local, 1);
1328
Johannes Berge5b900d2010-07-29 16:08:55 +02001329 if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
1330 bss_conf->dtim_period = bss->dtim_period;
1331 else
1332 bss_conf->dtim_period = 0;
1333
Juuso Oikarinen68542962010-06-09 13:43:26 +03001334 bss_conf->assoc = 1;
Johannes Berg9cef8732009-05-14 13:10:14 +02001335
Juuso Oikarinena97c13c2010-03-23 09:02:34 +02001336 /* Tell the driver to monitor connection quality (if supported) */
Johannes Bergea086352012-01-19 09:29:58 +01001337 if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI &&
Juuso Oikarinen68542962010-06-09 13:43:26 +03001338 bss_conf->cqm_rssi_thold)
Juuso Oikarinena97c13c2010-03-23 09:02:34 +02001339 bss_info_changed |= BSS_CHANGED_CQM;
1340
Juuso Oikarinen68542962010-06-09 13:43:26 +03001341 /* Enable ARP filtering */
1342 if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) {
1343 bss_conf->arp_filter_enabled = sdata->arp_filter_state;
1344 bss_info_changed |= BSS_CHANGED_ARP_FILTER;
1345 }
1346
Johannes Bergae5eb022008-10-14 16:58:37 +02001347 ieee80211_bss_info_change_notify(sdata, bss_info_changed);
Guy Cohen8db93692008-07-03 19:56:13 +03001348
Johannes Berg056508d2009-07-30 21:43:55 +02001349 mutex_lock(&local->iflist_mtx);
1350 ieee80211_recalc_ps(local, -1);
1351 mutex_unlock(&local->iflist_mtx);
Kalle Valoe0cb6862008-12-18 23:35:13 +02001352
Johannes Berg5d8e4232012-09-11 10:17:11 +02001353 ieee80211_recalc_smps(local);
Eliad Pellerab095872012-07-27 12:33:22 +03001354 ieee80211_recalc_ps_vif(sdata);
1355
John W. Linville8a5b33f2010-01-06 15:39:39 -05001356 netif_tx_start_all_queues(sdata->dev);
Tomas Winklerf5e5bf22008-09-08 17:33:39 +02001357 netif_carrier_on(sdata->dev);
Jiri Bencf0706e82007-05-05 11:45:53 -07001358}
1359
Jouni Malinene69e95d2010-03-29 23:29:31 -07001360static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
Johannes Berg37ad3882012-02-24 13:50:54 +01001361 u16 stype, u16 reason, bool tx,
1362 u8 *frame_buf)
Tomas Winkleraa458d12008-09-09 00:32:12 +03001363{
Johannes Berg46900292009-02-15 12:44:28 +01001364 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Tomas Winkleraa458d12008-09-09 00:32:12 +03001365 struct ieee80211_local *local = sdata->local;
1366 struct sta_info *sta;
Johannes Berg3cc52402012-03-09 13:12:35 +01001367 u32 changed = 0;
Tomas Winkleraa458d12008-09-09 00:32:12 +03001368
Johannes Berg77fdaa12009-07-07 03:45:17 +02001369 ASSERT_MGD_MTX(ifmgd);
1370
Johannes Berg37ad3882012-02-24 13:50:54 +01001371 if (WARN_ON_ONCE(tx && !frame_buf))
1372 return;
1373
Johannes Bergb291ba12009-07-10 15:29:03 +02001374 if (WARN_ON(!ifmgd->associated))
1375 return;
1376
David Spinadel79543d82012-06-12 09:59:45 +03001377 ieee80211_stop_poll(sdata);
1378
Johannes Berg77fdaa12009-07-07 03:45:17 +02001379 ifmgd->associated = NULL;
Johannes Berg77fdaa12009-07-07 03:45:17 +02001380
1381 /*
1382 * we need to commit the associated = NULL change because the
1383 * scan code uses that to determine whether this iface should
1384 * go to/wake up from powersave or not -- and could otherwise
1385 * wake the queues erroneously.
1386 */
1387 smp_mb();
1388
1389 /*
1390 * Thus, we can only afterwards stop the queues -- to account
1391 * for the case where another CPU is finishing a scan at this
1392 * time -- we don't want the scan code to enable queues.
1393 */
Tomas Winkleraa458d12008-09-09 00:32:12 +03001394
John W. Linville8a5b33f2010-01-06 15:39:39 -05001395 netif_tx_stop_all_queues(sdata->dev);
Tomas Winkleraa458d12008-09-09 00:32:12 +03001396 netif_carrier_off(sdata->dev);
1397
Johannes Berg2a419052010-06-10 10:21:29 +02001398 mutex_lock(&local->sta_mtx);
Eliad Peller88a9e312012-06-01 11:14:03 +03001399 sta = sta_info_get(sdata, ifmgd->bssid);
Sujith4cad6c72010-02-10 14:52:21 +05301400 if (sta) {
Johannes Bergc2c98fd2011-09-29 16:04:36 +02001401 set_sta_flag(sta, WLAN_STA_BLOCK_BA);
Johannes Berg7f161142012-07-18 12:53:34 +02001402 ieee80211_sta_tear_down_BA_sessions(sta, false);
Sujith4cad6c72010-02-10 14:52:21 +05301403 }
Johannes Berg2a419052010-06-10 10:21:29 +02001404 mutex_unlock(&local->sta_mtx);
Tomas Winkleraa458d12008-09-09 00:32:12 +03001405
Eliad Peller88bc40e2012-07-12 17:35:33 +03001406 /*
1407 * if we want to get out of ps before disassoc (why?) we have
1408 * to do it before sending disassoc, as otherwise the null-packet
1409 * won't be valid.
1410 */
1411 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
1412 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
1413 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
1414 }
1415 local->ps_sdata = NULL;
1416
Eliad Pellerab095872012-07-27 12:33:22 +03001417 /* disable per-vif ps */
1418 ieee80211_recalc_ps_vif(sdata);
1419
Eliad Pellerf8239812012-06-27 14:18:22 +03001420 /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
1421 if (tx)
1422 drv_flush(local, false);
1423
Johannes Berg37ad3882012-02-24 13:50:54 +01001424 /* deauthenticate/disassociate now */
1425 if (tx || frame_buf)
Eliad Peller88a9e312012-06-01 11:14:03 +03001426 ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype,
1427 reason, tx, frame_buf);
Johannes Berg37ad3882012-02-24 13:50:54 +01001428
1429 /* flush out frame */
1430 if (tx)
1431 drv_flush(local, false);
1432
Eliad Peller88a9e312012-06-01 11:14:03 +03001433 /* clear bssid only after building the needed mgmt frames */
1434 memset(ifmgd->bssid, 0, ETH_ALEN);
1435
Johannes Berg37ad3882012-02-24 13:50:54 +01001436 /* remove AP and TDLS peers */
1437 sta_info_flush(local, sdata);
1438
1439 /* finally reset all BSS / config parameters */
Tomas Winklerf5e5bf22008-09-08 17:33:39 +02001440 changed |= ieee80211_reset_erp_info(sdata);
1441
Tomas Winklerf5e5bf22008-09-08 17:33:39 +02001442 ieee80211_led_assoc(local, 0);
Johannes Bergae5eb022008-10-14 16:58:37 +02001443 changed |= BSS_CHANGED_ASSOC;
1444 sdata->vif.bss_conf.assoc = false;
Tomas Winklerf5e5bf22008-09-08 17:33:39 +02001445
Johannes Berg413ad502009-05-08 21:21:06 +02001446 /* on the next assoc, re-program HT parameters */
Ben Greearef96a8422011-11-18 11:32:00 -08001447 memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
1448 memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
Johannes Berg413ad502009-05-08 21:21:06 +02001449
Johannes Berg04b7b2f2012-09-05 13:41:37 +02001450 local->ap_power_level = 0;
Vasanthakumar Thiagarajana8302de2009-01-09 18:14:15 +05301451
Kalle Valo520eb822008-12-18 23:35:27 +02001452 del_timer_sync(&local->dynamic_ps_timer);
1453 cancel_work_sync(&local->dynamic_ps_enable_work);
1454
Juuso Oikarinen68542962010-06-09 13:43:26 +03001455 /* Disable ARP filtering */
1456 if (sdata->vif.bss_conf.arp_filter_enabled) {
1457 sdata->vif.bss_conf.arp_filter_enabled = false;
1458 changed |= BSS_CHANGED_ARP_FILTER;
1459 }
1460
Johannes Berg3abead52012-03-02 15:56:59 +01001461 sdata->vif.bss_conf.qos = false;
1462 changed |= BSS_CHANGED_QOS;
1463
Johannes Berg0aaffa92010-05-05 15:28:27 +02001464 /* The BSSID (not really interesting) and HT changed */
1465 changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
Johannes Bergae5eb022008-10-14 16:58:37 +02001466 ieee80211_bss_info_change_notify(sdata, changed);
Tomas Winkler8e268e42008-11-25 13:05:44 +02001467
Johannes Berg3cc52402012-03-09 13:12:35 +01001468 /* channel(_type) changes are handled by ieee80211_hw_config */
1469 WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
1470 ieee80211_hw_config(local, 0);
1471
Johannes Berg3abead52012-03-02 15:56:59 +01001472 /* disassociated - set to defaults now */
1473 ieee80211_set_wmm_default(sdata, false);
1474
Johannes Bergb9dcf712010-08-27 12:35:54 +02001475 del_timer_sync(&sdata->u.mgd.conn_mon_timer);
1476 del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
1477 del_timer_sync(&sdata->u.mgd.timer);
1478 del_timer_sync(&sdata->u.mgd.chswitch_timer);
Johannes Berg2d9957c2012-08-01 20:54:52 +02001479
1480 sdata->u.mgd.timers_running = 0;
Tomas Winkleraa458d12008-09-09 00:32:12 +03001481}
Jiri Bencf0706e82007-05-05 11:45:53 -07001482
Kalle Valo3cf335d2009-03-22 21:57:06 +02001483void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
1484 struct ieee80211_hdr *hdr)
1485{
1486 /*
1487 * We can postpone the mgd.timer whenever receiving unicast frames
1488 * from AP because we know that the connection is working both ways
1489 * at that time. But multicast frames (and hence also beacons) must
1490 * be ignored here, because we need to trigger the timer during
Johannes Bergb291ba12009-07-10 15:29:03 +02001491 * data idle periods for sending the periodic probe request to the
1492 * AP we're connected to.
Kalle Valo3cf335d2009-03-22 21:57:06 +02001493 */
Johannes Bergb291ba12009-07-10 15:29:03 +02001494 if (is_multicast_ether_addr(hdr->addr1))
1495 return;
1496
Luis R. Rodriguezbe099e82010-09-16 15:12:29 -04001497 ieee80211_sta_reset_conn_monitor(sdata);
Kalle Valo3cf335d2009-03-22 21:57:06 +02001498}
Jiri Bencf0706e82007-05-05 11:45:53 -07001499
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001500static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
1501{
1502 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001503 struct ieee80211_local *local = sdata->local;
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001504
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001505 mutex_lock(&local->mtx);
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001506 if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001507 IEEE80211_STA_CONNECTION_POLL))) {
1508 mutex_unlock(&local->mtx);
1509 return;
1510 }
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001511
Stanislaw Gruszka925e64c2012-05-16 15:27:20 +02001512 __ieee80211_stop_poll(sdata);
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001513
1514 mutex_lock(&local->iflist_mtx);
1515 ieee80211_recalc_ps(local, -1);
1516 mutex_unlock(&local->iflist_mtx);
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001517
1518 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001519 goto out;
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001520
1521 /*
1522 * We've received a probe response, but are not sure whether
1523 * we have or will be receiving any beacons or data, so let's
1524 * schedule the timers again, just in case.
1525 */
1526 ieee80211_sta_reset_beacon_monitor(sdata);
1527
1528 mod_timer(&ifmgd->conn_mon_timer,
1529 round_jiffies_up(jiffies +
1530 IEEE80211_CONNECTION_IDLE_TIME));
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001531out:
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001532 mutex_unlock(&local->mtx);
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001533}
1534
1535void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
Felix Fietkau04ac3c02010-12-02 21:01:08 +01001536 struct ieee80211_hdr *hdr, bool ack)
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001537{
Felix Fietkau75706d02010-12-02 21:01:07 +01001538 if (!ieee80211_is_data(hdr->frame_control))
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001539 return;
1540
Felix Fietkau04ac3c02010-12-02 21:01:08 +01001541 if (ack)
1542 ieee80211_sta_reset_conn_monitor(sdata);
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001543
1544 if (ieee80211_is_nullfunc(hdr->frame_control) &&
1545 sdata->u.mgd.probe_send_count > 0) {
Felix Fietkau04ac3c02010-12-02 21:01:08 +01001546 if (ack)
1547 sdata->u.mgd.probe_send_count = 0;
1548 else
1549 sdata->u.mgd.nullfunc_failed = true;
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001550 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
1551 }
1552}
1553
Maxim Levitskya43abf22009-07-31 18:54:12 +03001554static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
1555{
1556 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1557 const u8 *ssid;
Luis R. Rodriguezf01a0672010-09-16 15:12:34 -04001558 u8 *dst = ifmgd->associated->bssid;
Ben Greear180205b2011-02-04 15:30:24 -08001559 u8 unicast_limit = max(1, max_probe_tries - 3);
Luis R. Rodriguezf01a0672010-09-16 15:12:34 -04001560
1561 /*
1562 * Try sending broadcast probe requests for the last three
1563 * probe requests after the first ones failed since some
1564 * buggy APs only support broadcast probe requests.
1565 */
1566 if (ifmgd->probe_send_count >= unicast_limit)
1567 dst = NULL;
Maxim Levitskya43abf22009-07-31 18:54:12 +03001568
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001569 /*
1570 * When the hardware reports an accurate Tx ACK status, it's
1571 * better to send a nullfunc frame instead of a probe request,
1572 * as it will kick us off the AP quickly if we aren't associated
1573 * anymore. The timeout will be reset if the frame is ACKed by
1574 * the AP.
1575 */
Soumik Das992e68b2012-05-20 15:31:13 +05301576 ifmgd->probe_send_count++;
1577
Felix Fietkau04ac3c02010-12-02 21:01:08 +01001578 if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
1579 ifmgd->nullfunc_failed = false;
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001580 ieee80211_send_nullfunc(sdata->local, sdata, 0);
Felix Fietkau04ac3c02010-12-02 21:01:08 +01001581 } else {
Stanislaw Gruszka88c868c2012-03-29 16:30:41 +02001582 int ssid_len;
1583
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001584 ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
Stanislaw Gruszka88c868c2012-03-29 16:30:41 +02001585 if (WARN_ON_ONCE(ssid == NULL))
1586 ssid_len = 0;
1587 else
1588 ssid_len = ssid[1];
1589
1590 ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
Johannes Bergfe94fe02012-07-30 12:26:34 +02001591 0, (u32) -1, true, false,
1592 ifmgd->associated->channel);
Felix Fietkau4e5ff372010-11-23 03:10:31 +01001593 }
Maxim Levitskya43abf22009-07-31 18:54:12 +03001594
Ben Greear180205b2011-02-04 15:30:24 -08001595 ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
Maxim Levitskya43abf22009-07-31 18:54:12 +03001596 run_again(ifmgd, ifmgd->probe_timeout);
Rajkumar Manoharanf69b9c72012-03-15 06:15:26 +05301597 if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
1598 drv_flush(sdata->local, false);
Maxim Levitskya43abf22009-07-31 18:54:12 +03001599}
1600
Johannes Bergb291ba12009-07-10 15:29:03 +02001601static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
1602 bool beacon)
Kalle Valo04de8382009-03-22 21:57:35 +02001603{
Kalle Valo04de8382009-03-22 21:57:35 +02001604 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Johannes Bergb291ba12009-07-10 15:29:03 +02001605 bool already = false;
Johannes Berg34bfc412009-05-12 19:58:12 +02001606
Johannes Berg9607e6b2009-12-23 13:15:31 +01001607 if (!ieee80211_sdata_running(sdata))
Johannes Berg0e2b6282009-07-13 13:23:39 +02001608 return;
1609
Johannes Berg77fdaa12009-07-07 03:45:17 +02001610 mutex_lock(&ifmgd->mtx);
1611
1612 if (!ifmgd->associated)
1613 goto out;
1614
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001615 mutex_lock(&sdata->local->mtx);
1616
1617 if (sdata->local->tmp_channel || sdata->local->scanning) {
1618 mutex_unlock(&sdata->local->mtx);
1619 goto out;
1620 }
1621
Joe Perchese87cc472012-05-13 21:56:26 +00001622 if (beacon)
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02001623 mlme_dbg_ratelimited(sdata,
1624 "detected beacon loss from AP - sending probe request\n");
1625
Holger Schurig6efb71b2012-05-15 15:38:59 +02001626 ieee80211_cqm_rssi_notify(&sdata->vif,
1627 NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);
Kalle Valo04de8382009-03-22 21:57:35 +02001628
Johannes Bergb291ba12009-07-10 15:29:03 +02001629 /*
1630 * The driver/our work has already reported this event or the
1631 * connection monitoring has kicked in and we have already sent
1632 * a probe request. Or maybe the AP died and the driver keeps
1633 * reporting until we disassociate...
1634 *
1635 * In either case we have to ignore the current call to this
1636 * function (except for setting the correct probe reason bit)
1637 * because otherwise we would reset the timer every time and
1638 * never check whether we received a probe response!
1639 */
1640 if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
1641 IEEE80211_STA_CONNECTION_POLL))
1642 already = true;
1643
1644 if (beacon)
1645 ifmgd->flags |= IEEE80211_STA_BEACON_POLL;
1646 else
1647 ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
1648
Stanislaw Gruszka133d40f2012-03-28 16:01:19 +02001649 mutex_unlock(&sdata->local->mtx);
1650
Johannes Bergb291ba12009-07-10 15:29:03 +02001651 if (already)
1652 goto out;
1653
Johannes Berg4e751842009-06-10 15:16:52 +02001654 mutex_lock(&sdata->local->iflist_mtx);
1655 ieee80211_recalc_ps(sdata->local, -1);
1656 mutex_unlock(&sdata->local->iflist_mtx);
1657
Maxim Levitskya43abf22009-07-31 18:54:12 +03001658 ifmgd->probe_send_count = 0;
1659 ieee80211_mgd_probe_ap_send(sdata);
Johannes Berg77fdaa12009-07-07 03:45:17 +02001660 out:
1661 mutex_unlock(&ifmgd->mtx);
Kalle Valo04de8382009-03-22 21:57:35 +02001662}
1663
Juuso Oikarinena619a4c2010-11-11 08:50:18 +02001664struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
1665 struct ieee80211_vif *vif)
1666{
1667 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1668 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Eliad Pellerd9b3b282012-06-28 15:03:13 +03001669 struct cfg80211_bss *cbss;
Juuso Oikarinena619a4c2010-11-11 08:50:18 +02001670 struct sk_buff *skb;
1671 const u8 *ssid;
Stanislaw Gruszka88c868c2012-03-29 16:30:41 +02001672 int ssid_len;
Juuso Oikarinena619a4c2010-11-11 08:50:18 +02001673
1674 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
1675 return NULL;
1676
1677 ASSERT_MGD_MTX(ifmgd);
1678
Eliad Pellerd9b3b282012-06-28 15:03:13 +03001679 if (ifmgd->associated)
1680 cbss = ifmgd->associated;
1681 else if (ifmgd->auth_data)
1682 cbss = ifmgd->auth_data->bss;
1683 else if (ifmgd->assoc_data)
1684 cbss = ifmgd->assoc_data->bss;
1685 else
Juuso Oikarinena619a4c2010-11-11 08:50:18 +02001686 return NULL;
1687
Eliad Pellerd9b3b282012-06-28 15:03:13 +03001688 ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID);
Stanislaw Gruszka88c868c2012-03-29 16:30:41 +02001689 if (WARN_ON_ONCE(ssid == NULL))
1690 ssid_len = 0;
1691 else
1692 ssid_len = ssid[1];
1693
Eliad Pellerd9b3b282012-06-28 15:03:13 +03001694 skb = ieee80211_build_probe_req(sdata, cbss->bssid,
Johannes Berg6b778632012-07-23 14:53:27 +02001695 (u32) -1,
1696 sdata->local->oper_channel,
1697 ssid + 2, ssid_len,
Johannes Berg85a237f2011-07-18 18:08:36 +02001698 NULL, 0, true);
Juuso Oikarinena619a4c2010-11-11 08:50:18 +02001699
1700 return skb;
1701}
1702EXPORT_SYMBOL(ieee80211_ap_probereq_get);
1703
Johannes Berg882a7c62012-08-01 22:32:45 +02001704static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata,
1705 bool transmit_frame)
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001706{
1707 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1708 struct ieee80211_local *local = sdata->local;
Antonio Quartulli6ae16772012-09-07 13:28:52 +02001709 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001710
1711 mutex_lock(&ifmgd->mtx);
1712 if (!ifmgd->associated) {
1713 mutex_unlock(&ifmgd->mtx);
1714 return;
1715 }
1716
Johannes Berg37ad3882012-02-24 13:50:54 +01001717 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
1718 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
Johannes Berg882a7c62012-08-01 22:32:45 +02001719 transmit_frame, frame_buf);
1720 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001721 mutex_unlock(&ifmgd->mtx);
Johannes Berg7da7cc12010-08-05 17:02:38 +02001722
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001723 /*
1724 * must be outside lock due to cfg80211,
1725 * but that's not a problem.
1726 */
Antonio Quartulli6ae16772012-09-07 13:28:52 +02001727 cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
Felix Fietkaufcac4fb2011-11-16 13:34:55 +01001728
1729 mutex_lock(&local->mtx);
1730 ieee80211_recalc_idle(local);
1731 mutex_unlock(&local->mtx);
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001732}
1733
Johannes Bergcc74c0c2012-08-01 16:49:34 +02001734static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
Johannes Bergb291ba12009-07-10 15:29:03 +02001735{
1736 struct ieee80211_sub_if_data *sdata =
1737 container_of(work, struct ieee80211_sub_if_data,
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001738 u.mgd.beacon_connection_loss_work);
Paul Stewarta85e1d52011-12-09 11:01:49 -08001739 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1740 struct sta_info *sta;
1741
1742 if (ifmgd->associated) {
Mohammed Shafi Shajakhan30fa9042011-12-27 18:54:07 +05301743 rcu_read_lock();
Paul Stewarta85e1d52011-12-09 11:01:49 -08001744 sta = sta_info_get(sdata, ifmgd->bssid);
1745 if (sta)
1746 sta->beacon_loss_count++;
Mohammed Shafi Shajakhan30fa9042011-12-27 18:54:07 +05301747 rcu_read_unlock();
Paul Stewarta85e1d52011-12-09 11:01:49 -08001748 }
Johannes Bergb291ba12009-07-10 15:29:03 +02001749
Johannes Berg882a7c62012-08-01 22:32:45 +02001750 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) {
1751 sdata_info(sdata, "Connection to AP %pM lost\n",
1752 ifmgd->bssid);
1753 __ieee80211_disconnect(sdata, false);
1754 } else {
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001755 ieee80211_mgd_probe_ap(sdata, true);
Johannes Berg882a7c62012-08-01 22:32:45 +02001756 }
1757}
1758
1759static void ieee80211_csa_connection_drop_work(struct work_struct *work)
1760{
1761 struct ieee80211_sub_if_data *sdata =
1762 container_of(work, struct ieee80211_sub_if_data,
1763 u.mgd.csa_connection_drop_work);
1764
1765 ieee80211_wake_queues_by_reason(&sdata->local->hw,
1766 IEEE80211_QUEUE_STOP_REASON_CSA);
1767 __ieee80211_disconnect(sdata, true);
Johannes Bergb291ba12009-07-10 15:29:03 +02001768}
1769
Kalle Valo04de8382009-03-22 21:57:35 +02001770void ieee80211_beacon_loss(struct ieee80211_vif *vif)
1771{
1772 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001773 struct ieee80211_hw *hw = &sdata->local->hw;
Kalle Valo04de8382009-03-22 21:57:35 +02001774
Johannes Bergb5878a22010-04-07 16:48:40 +02001775 trace_api_beacon_loss(sdata);
1776
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001777 WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR);
1778 ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
Kalle Valo04de8382009-03-22 21:57:35 +02001779}
1780EXPORT_SYMBOL(ieee80211_beacon_loss);
1781
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001782void ieee80211_connection_loss(struct ieee80211_vif *vif)
1783{
1784 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1785 struct ieee80211_hw *hw = &sdata->local->hw;
1786
Johannes Bergb5878a22010-04-07 16:48:40 +02001787 trace_api_connection_loss(sdata);
1788
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02001789 WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR));
1790 ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
1791}
1792EXPORT_SYMBOL(ieee80211_connection_loss);
1793
1794
Johannes Berg66e67e42012-01-20 13:55:27 +01001795static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
1796 bool assoc)
1797{
1798 struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
1799
1800 lockdep_assert_held(&sdata->u.mgd.mtx);
1801
Johannes Berg66e67e42012-01-20 13:55:27 +01001802 if (!assoc) {
1803 sta_info_destroy_addr(sdata, auth_data->bss->bssid);
1804
1805 memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
1806 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
1807 }
1808
1809 cfg80211_put_bss(auth_data->bss);
1810 kfree(auth_data);
1811 sdata->u.mgd.auth_data = NULL;
1812}
1813
1814static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
1815 struct ieee80211_mgmt *mgmt, size_t len)
1816{
1817 struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
1818 u8 *pos;
1819 struct ieee802_11_elems elems;
1820
1821 pos = mgmt->u.auth.variable;
1822 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
1823 if (!elems.challenge)
1824 return;
1825 auth_data->expected_transaction = 4;
Johannes Berga1845fc2012-06-27 13:18:36 +02001826 drv_mgd_prepare_tx(sdata->local, sdata);
Johannes Berg66e67e42012-01-20 13:55:27 +01001827 ieee80211_send_auth(sdata, 3, auth_data->algorithm,
1828 elems.challenge - 2, elems.challenge_len + 2,
1829 auth_data->bss->bssid, auth_data->bss->bssid,
1830 auth_data->key, auth_data->key_len,
1831 auth_data->key_idx);
1832}
1833
1834static enum rx_mgmt_action __must_check
1835ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
1836 struct ieee80211_mgmt *mgmt, size_t len)
1837{
1838 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1839 u8 bssid[ETH_ALEN];
1840 u16 auth_alg, auth_transaction, status_code;
1841 struct sta_info *sta;
1842
1843 lockdep_assert_held(&ifmgd->mtx);
1844
1845 if (len < 24 + 6)
1846 return RX_MGMT_NONE;
1847
1848 if (!ifmgd->auth_data || ifmgd->auth_data->done)
1849 return RX_MGMT_NONE;
1850
1851 memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
1852
Joe Perchesb203ca32012-05-08 18:56:52 +00001853 if (!ether_addr_equal(bssid, mgmt->bssid))
Johannes Berg66e67e42012-01-20 13:55:27 +01001854 return RX_MGMT_NONE;
1855
1856 auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
1857 auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
1858 status_code = le16_to_cpu(mgmt->u.auth.status_code);
1859
1860 if (auth_alg != ifmgd->auth_data->algorithm ||
1861 auth_transaction != ifmgd->auth_data->expected_transaction)
1862 return RX_MGMT_NONE;
1863
1864 if (status_code != WLAN_STATUS_SUCCESS) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02001865 sdata_info(sdata, "%pM denied authentication (status %d)\n",
1866 mgmt->sa, status_code);
Eliad Pellerdac211e2012-05-13 18:07:04 +03001867 ieee80211_destroy_auth_data(sdata, false);
1868 return RX_MGMT_CFG80211_RX_AUTH;
Johannes Berg66e67e42012-01-20 13:55:27 +01001869 }
1870
1871 switch (ifmgd->auth_data->algorithm) {
1872 case WLAN_AUTH_OPEN:
1873 case WLAN_AUTH_LEAP:
1874 case WLAN_AUTH_FT:
1875 break;
1876 case WLAN_AUTH_SHARED_KEY:
1877 if (ifmgd->auth_data->expected_transaction != 4) {
1878 ieee80211_auth_challenge(sdata, mgmt, len);
1879 /* need another frame */
1880 return RX_MGMT_NONE;
1881 }
1882 break;
1883 default:
1884 WARN_ONCE(1, "invalid auth alg %d",
1885 ifmgd->auth_data->algorithm);
1886 return RX_MGMT_NONE;
1887 }
1888
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02001889 sdata_info(sdata, "authenticated\n");
Johannes Berg66e67e42012-01-20 13:55:27 +01001890 ifmgd->auth_data->done = true;
1891 ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
1892 run_again(ifmgd, ifmgd->auth_data->timeout);
1893
1894 /* move station state to auth */
1895 mutex_lock(&sdata->local->sta_mtx);
1896 sta = sta_info_get(sdata, bssid);
1897 if (!sta) {
1898 WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid);
1899 goto out_err;
1900 }
1901 if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02001902 sdata_info(sdata, "failed moving %pM to auth\n", bssid);
Johannes Berg66e67e42012-01-20 13:55:27 +01001903 goto out_err;
1904 }
1905 mutex_unlock(&sdata->local->sta_mtx);
1906
1907 return RX_MGMT_CFG80211_RX_AUTH;
1908 out_err:
1909 mutex_unlock(&sdata->local->sta_mtx);
1910 /* ignore frame -- wait for timeout */
1911 return RX_MGMT_NONE;
1912}
1913
1914
Johannes Berg77fdaa12009-07-07 03:45:17 +02001915static enum rx_mgmt_action __must_check
1916ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
Johannes Berg77fdaa12009-07-07 03:45:17 +02001917 struct ieee80211_mgmt *mgmt, size_t len)
Jiri Bencf0706e82007-05-05 11:45:53 -07001918{
Johannes Berg46900292009-02-15 12:44:28 +01001919 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Johannes Berg77fdaa12009-07-07 03:45:17 +02001920 const u8 *bssid = NULL;
Jiri Bencf0706e82007-05-05 11:45:53 -07001921 u16 reason_code;
1922
Johannes Berg66e67e42012-01-20 13:55:27 +01001923 lockdep_assert_held(&ifmgd->mtx);
1924
Johannes Bergf4ea83d2008-06-30 15:10:46 +02001925 if (len < 24 + 2)
Johannes Berg77fdaa12009-07-07 03:45:17 +02001926 return RX_MGMT_NONE;
Jiri Bencf0706e82007-05-05 11:45:53 -07001927
Johannes Berg66e67e42012-01-20 13:55:27 +01001928 if (!ifmgd->associated ||
Joe Perchesb203ca32012-05-08 18:56:52 +00001929 !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
Johannes Berg66e67e42012-01-20 13:55:27 +01001930 return RX_MGMT_NONE;
Johannes Berg77fdaa12009-07-07 03:45:17 +02001931
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01001932 bssid = ifmgd->associated->bssid;
Jiri Bencf0706e82007-05-05 11:45:53 -07001933
1934 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
1935
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02001936 sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n",
1937 bssid, reason_code);
Jiri Bencf0706e82007-05-05 11:45:53 -07001938
Johannes Berg37ad3882012-02-24 13:50:54 +01001939 ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
1940
Johannes Berg7da7cc12010-08-05 17:02:38 +02001941 mutex_lock(&sdata->local->mtx);
Johannes Berg63f170e2009-12-23 13:15:33 +01001942 ieee80211_recalc_idle(sdata->local);
Johannes Berg7da7cc12010-08-05 17:02:38 +02001943 mutex_unlock(&sdata->local->mtx);
Johannes Berg77fdaa12009-07-07 03:45:17 +02001944
1945 return RX_MGMT_CFG80211_DEAUTH;
Jiri Bencf0706e82007-05-05 11:45:53 -07001946}
1947
1948
Johannes Berg77fdaa12009-07-07 03:45:17 +02001949static enum rx_mgmt_action __must_check
1950ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
1951 struct ieee80211_mgmt *mgmt, size_t len)
Jiri Bencf0706e82007-05-05 11:45:53 -07001952{
Johannes Berg46900292009-02-15 12:44:28 +01001953 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Jiri Bencf0706e82007-05-05 11:45:53 -07001954 u16 reason_code;
1955
Johannes Berg66e67e42012-01-20 13:55:27 +01001956 lockdep_assert_held(&ifmgd->mtx);
1957
Johannes Bergf4ea83d2008-06-30 15:10:46 +02001958 if (len < 24 + 2)
Johannes Berg77fdaa12009-07-07 03:45:17 +02001959 return RX_MGMT_NONE;
Jiri Bencf0706e82007-05-05 11:45:53 -07001960
Johannes Berg66e67e42012-01-20 13:55:27 +01001961 if (!ifmgd->associated ||
Joe Perchesb203ca32012-05-08 18:56:52 +00001962 !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
Johannes Berg77fdaa12009-07-07 03:45:17 +02001963 return RX_MGMT_NONE;
Jiri Bencf0706e82007-05-05 11:45:53 -07001964
1965 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
1966
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02001967 sdata_info(sdata, "disassociated from %pM (Reason: %u)\n",
1968 mgmt->sa, reason_code);
Jiri Bencf0706e82007-05-05 11:45:53 -07001969
Johannes Berg37ad3882012-02-24 13:50:54 +01001970 ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
1971
Johannes Berg7da7cc12010-08-05 17:02:38 +02001972 mutex_lock(&sdata->local->mtx);
Johannes Bergbc83b682009-11-29 12:19:06 +01001973 ieee80211_recalc_idle(sdata->local);
Johannes Berg7da7cc12010-08-05 17:02:38 +02001974 mutex_unlock(&sdata->local->mtx);
Johannes Berg37ad3882012-02-24 13:50:54 +01001975
Johannes Berg77fdaa12009-07-07 03:45:17 +02001976 return RX_MGMT_CFG80211_DISASSOC;
Jiri Bencf0706e82007-05-05 11:45:53 -07001977}
1978
Christian Lamparterc74d0842011-10-15 00:14:49 +02001979static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
1980 u8 *supp_rates, unsigned int supp_rates_len,
1981 u32 *rates, u32 *basic_rates,
1982 bool *have_higher_than_11mbit,
1983 int *min_rate, int *min_rate_index)
1984{
1985 int i, j;
1986
1987 for (i = 0; i < supp_rates_len; i++) {
1988 int rate = (supp_rates[i] & 0x7f) * 5;
1989 bool is_basic = !!(supp_rates[i] & 0x80);
1990
1991 if (rate > 110)
1992 *have_higher_than_11mbit = true;
1993
1994 /*
1995 * BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009
1996 * 7.3.2.2 as a magic value instead of a rate. Hence, skip it.
1997 *
1998 * Note: Even through the membership selector and the basic
1999 * rate flag share the same bit, they are not exactly
2000 * the same.
2001 */
2002 if (!!(supp_rates[i] & 0x80) &&
2003 (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
2004 continue;
2005
2006 for (j = 0; j < sband->n_bitrates; j++) {
2007 if (sband->bitrates[j].bitrate == rate) {
2008 *rates |= BIT(j);
2009 if (is_basic)
2010 *basic_rates |= BIT(j);
2011 if (rate < *min_rate) {
2012 *min_rate = rate;
2013 *min_rate_index = j;
2014 }
2015 break;
2016 }
2017 }
2018 }
2019}
Jiri Bencf0706e82007-05-05 11:45:53 -07002020
Johannes Berg66e67e42012-01-20 13:55:27 +01002021static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
2022 bool assoc)
2023{
2024 struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
2025
2026 lockdep_assert_held(&sdata->u.mgd.mtx);
2027
Johannes Berg66e67e42012-01-20 13:55:27 +01002028 if (!assoc) {
2029 sta_info_destroy_addr(sdata, assoc_data->bss->bssid);
2030
2031 memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
2032 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
2033 }
2034
2035 kfree(assoc_data);
2036 sdata->u.mgd.assoc_data = NULL;
2037}
2038
2039static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
2040 struct cfg80211_bss *cbss,
Johannes Bergaf6b6372009-12-23 13:15:35 +01002041 struct ieee80211_mgmt *mgmt, size_t len)
Jiri Bencf0706e82007-05-05 11:45:53 -07002042{
Johannes Berg46900292009-02-15 12:44:28 +01002043 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Johannes Berg471b3ef2007-12-28 14:32:58 +01002044 struct ieee80211_local *local = sdata->local;
Johannes Berg8318d782008-01-24 19:38:38 +01002045 struct ieee80211_supported_band *sband;
Jiri Bencf0706e82007-05-05 11:45:53 -07002046 struct sta_info *sta;
Johannes Bergaf6b6372009-12-23 13:15:35 +01002047 u8 *pos;
Johannes Bergaf6b6372009-12-23 13:15:35 +01002048 u16 capab_info, aid;
Jiri Bencf0706e82007-05-05 11:45:53 -07002049 struct ieee802_11_elems elems;
Johannes Bergbda39332008-10-11 01:51:51 +02002050 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
Johannes Bergae5eb022008-10-14 16:58:37 +02002051 u32 changed = 0;
Christian Lamparterc74d0842011-10-15 00:14:49 +02002052 int err;
Jiri Bencf0706e82007-05-05 11:45:53 -07002053
Johannes Bergaf6b6372009-12-23 13:15:35 +01002054 /* AssocResp and ReassocResp have identical structure */
Jiri Bencf0706e82007-05-05 11:45:53 -07002055
Jiri Bencf0706e82007-05-05 11:45:53 -07002056 aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
Johannes Bergaf6b6372009-12-23 13:15:35 +01002057 capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
Jiri Bencf0706e82007-05-05 11:45:53 -07002058
Johannes Berg1dd84aa2007-10-10 12:03:41 +02002059 if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002060 sdata_info(sdata, "invalid AID value 0x%x; bits 15:14 not set\n",
2061 aid);
Johannes Berg1dd84aa2007-10-10 12:03:41 +02002062 aid &= ~(BIT(15) | BIT(14));
2063
Johannes Berg05cb9102011-10-28 11:59:47 +02002064 ifmgd->broken_ap = false;
2065
2066 if (aid == 0 || aid > IEEE80211_MAX_AID) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002067 sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n",
2068 aid);
Johannes Berg05cb9102011-10-28 11:59:47 +02002069 aid = 0;
2070 ifmgd->broken_ap = true;
2071 }
2072
Johannes Bergaf6b6372009-12-23 13:15:35 +01002073 pos = mgmt->u.assoc_resp.variable;
2074 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
2075
Jiri Bencf0706e82007-05-05 11:45:53 -07002076 if (!elems.supp_rates) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002077 sdata_info(sdata, "no SuppRates element in AssocResp\n");
Johannes Bergaf6b6372009-12-23 13:15:35 +01002078 return false;
Jiri Bencf0706e82007-05-05 11:45:53 -07002079 }
2080
Johannes Berg46900292009-02-15 12:44:28 +01002081 ifmgd->aid = aid;
Jiri Bencf0706e82007-05-05 11:45:53 -07002082
Guy Eilam2a33bee2011-08-17 15:18:15 +03002083 mutex_lock(&sdata->local->sta_mtx);
2084 /*
2085 * station info was already allocated and inserted before
2086 * the association and should be available to us
2087 */
Johannes Berg7852e362012-01-20 13:55:24 +01002088 sta = sta_info_get(sdata, cbss->bssid);
Guy Eilam2a33bee2011-08-17 15:18:15 +03002089 if (WARN_ON(!sta)) {
2090 mutex_unlock(&sdata->local->sta_mtx);
Johannes Bergaf6b6372009-12-23 13:15:35 +01002091 return false;
Jiri Bencf0706e82007-05-05 11:45:53 -07002092 }
2093
Johannes Berg66e67e42012-01-20 13:55:27 +01002094 sband = local->hw.wiphy->bands[local->oper_channel->band];
Johannes Berg8318d782008-01-24 19:38:38 +01002095
Johannes Bergab1faea2009-07-01 21:41:17 +02002096 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
Ben Greearef96a8422011-11-18 11:32:00 -08002097 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
Johannes Bergd9fe60d2008-10-09 12:13:49 +02002098 elems.ht_cap_elem, &sta->sta.ht_cap);
Johannes Bergae5eb022008-10-14 16:58:37 +02002099
Johannes Berg64f68e52012-03-28 10:58:37 +02002100 sta->supports_40mhz =
2101 sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
2102
Johannes Berg4b7679a2008-09-18 18:14:18 +02002103 rate_control_rate_init(sta);
Jiri Bencf0706e82007-05-05 11:45:53 -07002104
Johannes Berg46900292009-02-15 12:44:28 +01002105 if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
Johannes Bergc2c98fd2011-09-29 16:04:36 +02002106 set_sta_flag(sta, WLAN_STA_MFP);
Jouni Malinen5394af42009-01-08 13:31:59 +02002107
Johannes Bergddf4ac52008-10-22 11:41:38 +02002108 if (elems.wmm_param)
Johannes Bergc2c98fd2011-09-29 16:04:36 +02002109 set_sta_flag(sta, WLAN_STA_WME);
Johannes Bergddf4ac52008-10-22 11:41:38 +02002110
Johannes Bergc8987872012-01-20 13:55:17 +01002111 err = sta_info_move_state(sta, IEEE80211_STA_AUTH);
2112 if (!err)
2113 err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
2114 if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
2115 err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
2116 if (err) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002117 sdata_info(sdata,
2118 "failed to move station %pM to desired state\n",
2119 sta->sta.addr);
Johannes Bergc8987872012-01-20 13:55:17 +01002120 WARN_ON(__sta_info_destroy(sta));
2121 mutex_unlock(&sdata->local->sta_mtx);
2122 return false;
2123 }
2124
Johannes Berg7852e362012-01-20 13:55:24 +01002125 mutex_unlock(&sdata->local->sta_mtx);
Johannes Bergddf4ac52008-10-22 11:41:38 +02002126
Juuso Oikarinenf2176d72010-09-28 14:39:32 +03002127 /*
2128 * Always handle WMM once after association regardless
2129 * of the first value the AP uses. Setting -1 here has
2130 * that effect because the AP values is an unsigned
2131 * 4-bit value.
2132 */
2133 ifmgd->wmm_last_param_set = -1;
2134
Johannes Bergddf4ac52008-10-22 11:41:38 +02002135 if (elems.wmm_param)
Johannes Berg4ced3f72010-07-19 16:39:04 +02002136 ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
Jiri Bencf0706e82007-05-05 11:45:53 -07002137 elems.wmm_param_len);
Johannes Bergaa837e12009-05-07 16:16:24 +02002138 else
Johannes Berg3abead52012-03-02 15:56:59 +01002139 ieee80211_set_wmm_default(sdata, false);
2140 changed |= BSS_CHANGED_QOS;
Jiri Bencf0706e82007-05-05 11:45:53 -07002141
Johannes Berg074d46d2012-03-15 19:45:16 +01002142 if (elems.ht_operation && elems.wmm_param &&
Johannes Bergab1faea2009-07-01 21:41:17 +02002143 !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
Johannes Berg24398e32012-03-28 10:58:36 +02002144 changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
2145 cbss->bssid, false);
Johannes Bergae5eb022008-10-14 16:58:37 +02002146
Tomas Winkler21c0cbe2008-03-28 16:33:34 -07002147 /* set AID and assoc capability,
2148 * ieee80211_set_associated() will tell the driver */
Johannes Berg8318d782008-01-24 19:38:38 +01002149 bss_conf->aid = aid;
Tomas Winkler21c0cbe2008-03-28 16:33:34 -07002150 bss_conf->assoc_capability = capab_info;
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01002151 ieee80211_set_associated(sdata, cbss, changed);
Jiri Bencf0706e82007-05-05 11:45:53 -07002152
Kalle Valo15b7b062009-03-22 21:57:14 +02002153 /*
Felix Fietkaud5242152010-01-08 18:06:26 +01002154 * If we're using 4-addr mode, let the AP know that we're
2155 * doing so, so that it can create the STA VLAN on its side
2156 */
2157 if (ifmgd->use_4addr)
2158 ieee80211_send_4addr_nullfunc(local, sdata);
2159
2160 /*
Johannes Bergb291ba12009-07-10 15:29:03 +02002161 * Start timer to probe the connection to the AP now.
2162 * Also start the timer that will detect beacon loss.
Kalle Valo15b7b062009-03-22 21:57:14 +02002163 */
Johannes Bergb291ba12009-07-10 15:29:03 +02002164 ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
Luis R. Rodriguezd3a910a2010-09-16 15:12:32 -04002165 ieee80211_sta_reset_beacon_monitor(sdata);
Kalle Valo15b7b062009-03-22 21:57:14 +02002166
Johannes Bergaf6b6372009-12-23 13:15:35 +01002167 return true;
Jiri Bencf0706e82007-05-05 11:45:53 -07002168}
2169
Johannes Berg66e67e42012-01-20 13:55:27 +01002170static enum rx_mgmt_action __must_check
2171ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
2172 struct ieee80211_mgmt *mgmt, size_t len,
2173 struct cfg80211_bss **bss)
2174{
2175 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2176 struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
2177 u16 capab_info, status_code, aid;
2178 struct ieee802_11_elems elems;
2179 u8 *pos;
2180 bool reassoc;
Jiri Bencf0706e82007-05-05 11:45:53 -07002181
Johannes Berg66e67e42012-01-20 13:55:27 +01002182 lockdep_assert_held(&ifmgd->mtx);
2183
2184 if (!assoc_data)
2185 return RX_MGMT_NONE;
Joe Perchesb203ca32012-05-08 18:56:52 +00002186 if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid))
Johannes Berg66e67e42012-01-20 13:55:27 +01002187 return RX_MGMT_NONE;
2188
2189 /*
2190 * AssocResp and ReassocResp have identical structure, so process both
2191 * of them in this function.
2192 */
2193
2194 if (len < 24 + 6)
2195 return RX_MGMT_NONE;
2196
2197 reassoc = ieee80211_is_reassoc_req(mgmt->frame_control);
2198 capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
2199 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
2200 aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
2201
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002202 sdata_info(sdata,
2203 "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
2204 reassoc ? "Rea" : "A", mgmt->sa,
2205 capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
Johannes Berg66e67e42012-01-20 13:55:27 +01002206
2207 pos = mgmt->u.assoc_resp.variable;
2208 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
2209
2210 if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
2211 elems.timeout_int && elems.timeout_int_len == 5 &&
2212 elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
2213 u32 tu, ms;
2214 tu = get_unaligned_le32(elems.timeout_int + 1);
2215 ms = tu * 1024 / 1000;
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002216 sdata_info(sdata,
2217 "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
2218 mgmt->sa, tu, ms);
Johannes Berg66e67e42012-01-20 13:55:27 +01002219 assoc_data->timeout = jiffies + msecs_to_jiffies(ms);
2220 if (ms > IEEE80211_ASSOC_TIMEOUT)
2221 run_again(ifmgd, assoc_data->timeout);
2222 return RX_MGMT_NONE;
2223 }
2224
2225 *bss = assoc_data->bss;
2226
2227 if (status_code != WLAN_STATUS_SUCCESS) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002228 sdata_info(sdata, "%pM denied association (code=%d)\n",
2229 mgmt->sa, status_code);
Johannes Berg66e67e42012-01-20 13:55:27 +01002230 ieee80211_destroy_assoc_data(sdata, false);
2231 } else {
Johannes Berg66e67e42012-01-20 13:55:27 +01002232 if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
2233 /* oops -- internal error -- send timeout for now */
Eliad Peller10a91092012-07-02 14:42:03 +03002234 ieee80211_destroy_assoc_data(sdata, false);
Johannes Berg66e67e42012-01-20 13:55:27 +01002235 cfg80211_put_bss(*bss);
2236 return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
2237 }
John W. Linville635d9992012-07-09 16:34:34 -04002238 sdata_info(sdata, "associated\n");
Johannes Berg79ebfb82012-02-20 14:19:58 +01002239
2240 /*
2241 * destroy assoc_data afterwards, as otherwise an idle
2242 * recalc after assoc_data is NULL but before associated
2243 * is set can cause the interface to go idle
2244 */
2245 ieee80211_destroy_assoc_data(sdata, true);
Johannes Berg66e67e42012-01-20 13:55:27 +01002246 }
2247
2248 return RX_MGMT_CFG80211_RX_ASSOC;
2249}
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +12002250static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
Jiri Bencf0706e82007-05-05 11:45:53 -07002251 struct ieee80211_mgmt *mgmt,
2252 size_t len,
2253 struct ieee80211_rx_status *rx_status,
Johannes Berg98c8fcc2008-09-08 17:44:26 +02002254 struct ieee802_11_elems *elems,
2255 bool beacon)
Jiri Bencf0706e82007-05-05 11:45:53 -07002256{
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +12002257 struct ieee80211_local *local = sdata->local;
Johannes Berg98c8fcc2008-09-08 17:44:26 +02002258 int freq;
Johannes Bergc2b13452008-09-11 00:01:55 +02002259 struct ieee80211_bss *bss;
Johannes Bergfab7d4a2008-03-16 18:42:44 +01002260 struct ieee80211_channel *channel;
Johannes Berg56007a02010-01-26 14:19:52 +01002261 bool need_ps = false;
2262
Johannes Berg66e67e42012-01-20 13:55:27 +01002263 if (sdata->u.mgd.associated &&
Joe Perchesb203ca32012-05-08 18:56:52 +00002264 ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) {
Johannes Berg56007a02010-01-26 14:19:52 +01002265 bss = (void *)sdata->u.mgd.associated->priv;
2266 /* not previously set so we may need to recalc */
2267 need_ps = !bss->dtim_period;
2268 }
Jiri Bencf0706e82007-05-05 11:45:53 -07002269
Johannes Berg5bda6172008-09-08 11:05:10 +02002270 if (elems->ds_params && elems->ds_params_len == 1)
Bruno Randolf59eb21a2011-01-17 13:37:28 +09002271 freq = ieee80211_channel_to_frequency(elems->ds_params[0],
2272 rx_status->band);
Johannes Berg5bda6172008-09-08 11:05:10 +02002273 else
2274 freq = rx_status->freq;
2275
2276 channel = ieee80211_get_channel(local->hw.wiphy, freq);
2277
2278 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
2279 return;
Jiri Bencf0706e82007-05-05 11:45:53 -07002280
Johannes Berg98c8fcc2008-09-08 17:44:26 +02002281 bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
Johannes Berg2a519312009-02-10 21:25:55 +01002282 channel, beacon);
Johannes Berg77fdaa12009-07-07 03:45:17 +02002283 if (bss)
2284 ieee80211_rx_bss_put(local, bss);
2285
2286 if (!sdata->u.mgd.associated)
Johannes Berg98c8fcc2008-09-08 17:44:26 +02002287 return;
Jiri Bencf0706e82007-05-05 11:45:53 -07002288
Johannes Berg56007a02010-01-26 14:19:52 +01002289 if (need_ps) {
2290 mutex_lock(&local->iflist_mtx);
2291 ieee80211_recalc_ps(local, -1);
2292 mutex_unlock(&local->iflist_mtx);
2293 }
2294
Johannes Berg5bc14202012-08-01 16:13:02 +02002295 if (elems->ch_switch_ie &&
2296 memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0)
2297 ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie,
Johannes Berg5ce6e432010-05-11 16:20:57 +02002298 bss, rx_status->mactime);
Jiri Bencf0706e82007-05-05 11:45:53 -07002299}
2300
2301
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +12002302static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
Johannes Bergaf6b6372009-12-23 13:15:35 +01002303 struct sk_buff *skb)
Jiri Bencf0706e82007-05-05 11:45:53 -07002304{
Johannes Bergaf6b6372009-12-23 13:15:35 +01002305 struct ieee80211_mgmt *mgmt = (void *)skb->data;
Kalle Valo15b7b062009-03-22 21:57:14 +02002306 struct ieee80211_if_managed *ifmgd;
Johannes Bergaf6b6372009-12-23 13:15:35 +01002307 struct ieee80211_rx_status *rx_status = (void *) skb->cb;
2308 size_t baselen, len = skb->len;
Ester Kummerae6a44e2008-06-27 18:54:48 +03002309 struct ieee802_11_elems elems;
2310
Kalle Valo15b7b062009-03-22 21:57:14 +02002311 ifmgd = &sdata->u.mgd;
2312
Johannes Berg77fdaa12009-07-07 03:45:17 +02002313 ASSERT_MGD_MTX(ifmgd);
2314
Joe Perchesb203ca32012-05-08 18:56:52 +00002315 if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
Tomas Winkler8e7cdbb2008-08-03 14:32:01 +03002316 return; /* ignore ProbeResp to foreign address */
2317
Ester Kummerae6a44e2008-06-27 18:54:48 +03002318 baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
2319 if (baselen > len)
2320 return;
2321
2322 ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
2323 &elems);
2324
Johannes Berg98c8fcc2008-09-08 17:44:26 +02002325 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
Ron Rindjunsky9859b812008-08-09 03:02:19 +03002326
Johannes Berg77fdaa12009-07-07 03:45:17 +02002327 if (ifmgd->associated &&
Joe Perchesb203ca32012-05-08 18:56:52 +00002328 ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
Felix Fietkau4e5ff372010-11-23 03:10:31 +01002329 ieee80211_reset_ap_probe(sdata);
Johannes Berg66e67e42012-01-20 13:55:27 +01002330
2331 if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
Joe Perchesb203ca32012-05-08 18:56:52 +00002332 ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
Johannes Berg66e67e42012-01-20 13:55:27 +01002333 /* got probe response, continue with auth */
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002334 sdata_info(sdata, "direct probe responded\n");
Johannes Berg66e67e42012-01-20 13:55:27 +01002335 ifmgd->auth_data->tries = 0;
2336 ifmgd->auth_data->timeout = jiffies;
2337 run_again(ifmgd, ifmgd->auth_data->timeout);
2338 }
Jiri Bencf0706e82007-05-05 11:45:53 -07002339}
2340
Johannes Bergd91f36d2009-04-16 13:17:26 +02002341/*
2342 * This is the canonical list of information elements we care about,
2343 * the filter code also gives us all changes to the Microsoft OUI
2344 * (00:50:F2) vendor IE which is used for WMM which we need to track.
2345 *
2346 * We implement beacon filtering in software since that means we can
2347 * avoid processing the frame here and in cfg80211, and userspace
2348 * will not be able to tell whether the hardware supports it or not.
2349 *
2350 * XXX: This list needs to be dynamic -- userspace needs to be able to
2351 * add items it requires. It also needs to be able to tell us to
2352 * look out for other vendor IEs.
2353 */
2354static const u64 care_about_ies =
Johannes Berg1d4df3a2009-04-22 11:25:43 +02002355 (1ULL << WLAN_EID_COUNTRY) |
2356 (1ULL << WLAN_EID_ERP_INFO) |
2357 (1ULL << WLAN_EID_CHANNEL_SWITCH) |
2358 (1ULL << WLAN_EID_PWR_CONSTRAINT) |
2359 (1ULL << WLAN_EID_HT_CAPABILITY) |
Johannes Berg074d46d2012-03-15 19:45:16 +01002360 (1ULL << WLAN_EID_HT_OPERATION);
Johannes Bergd91f36d2009-04-16 13:17:26 +02002361
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +12002362static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
Jiri Bencf0706e82007-05-05 11:45:53 -07002363 struct ieee80211_mgmt *mgmt,
2364 size_t len,
2365 struct ieee80211_rx_status *rx_status)
2366{
Johannes Bergd91f36d2009-04-16 13:17:26 +02002367 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Jouni Malinen17e4ec12010-03-29 23:28:30 -07002368 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
Jiri Bencf0706e82007-05-05 11:45:53 -07002369 size_t baselen;
2370 struct ieee802_11_elems elems;
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +12002371 struct ieee80211_local *local = sdata->local;
Johannes Berg471b3ef2007-12-28 14:32:58 +01002372 u32 changed = 0;
Johannes Bergd91f36d2009-04-16 13:17:26 +02002373 bool erp_valid, directed_tim = false;
Johannes Berg7a5158e2008-10-08 10:59:33 +02002374 u8 erp_value = 0;
Johannes Bergd91f36d2009-04-16 13:17:26 +02002375 u32 ncrc;
Johannes Berg77fdaa12009-07-07 03:45:17 +02002376 u8 *bssid;
2377
Johannes Berg66e67e42012-01-20 13:55:27 +01002378 lockdep_assert_held(&ifmgd->mtx);
Jiri Bencf0706e82007-05-05 11:45:53 -07002379
Ester Kummerae6a44e2008-06-27 18:54:48 +03002380 /* Process beacon from the current BSS */
2381 baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
2382 if (baselen > len)
2383 return;
2384
Johannes Berg568d6e22012-07-23 14:29:21 +02002385 if (rx_status->freq != local->oper_channel->center_freq)
Jiri Bencf0706e82007-05-05 11:45:53 -07002386 return;
Jiri Bencf0706e82007-05-05 11:45:53 -07002387
Johannes Berg66e67e42012-01-20 13:55:27 +01002388 if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
Joe Perchesb203ca32012-05-08 18:56:52 +00002389 ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
Johannes Berg66e67e42012-01-20 13:55:27 +01002390 ieee802_11_parse_elems(mgmt->u.beacon.variable,
2391 len - baselen, &elems);
Johannes Berg77fdaa12009-07-07 03:45:17 +02002392
Johannes Berg66e67e42012-01-20 13:55:27 +01002393 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
2394 false);
2395 ifmgd->assoc_data->have_beacon = true;
2396 ifmgd->assoc_data->sent_assoc = false;
2397 /* continue assoc process */
2398 ifmgd->assoc_data->timeout = jiffies;
2399 run_again(ifmgd, ifmgd->assoc_data->timeout);
2400 return;
2401 }
2402
2403 if (!ifmgd->associated ||
Joe Perchesb203ca32012-05-08 18:56:52 +00002404 !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
Johannes Berg66e67e42012-01-20 13:55:27 +01002405 return;
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01002406 bssid = ifmgd->associated->bssid;
Johannes Berg77fdaa12009-07-07 03:45:17 +02002407
Jouni Malinen17e4ec12010-03-29 23:28:30 -07002408 /* Track average RSSI from the Beacon frames of the current AP */
2409 ifmgd->last_beacon_signal = rx_status->signal;
2410 if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
2411 ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
Jouni Malinen3ba06c62010-08-27 22:21:13 +03002412 ifmgd->ave_beacon_signal = rx_status->signal * 16;
Jouni Malinen17e4ec12010-03-29 23:28:30 -07002413 ifmgd->last_cqm_event_signal = 0;
Jouni Malinen391a2002010-08-27 22:22:00 +03002414 ifmgd->count_beacon_signal = 1;
Meenakshi Venkataraman615f7b92011-07-08 08:46:22 -07002415 ifmgd->last_ave_beacon_signal = 0;
Jouni Malinen17e4ec12010-03-29 23:28:30 -07002416 } else {
2417 ifmgd->ave_beacon_signal =
2418 (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
2419 (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
2420 ifmgd->ave_beacon_signal) / 16;
Jouni Malinen391a2002010-08-27 22:22:00 +03002421 ifmgd->count_beacon_signal++;
Jouni Malinen17e4ec12010-03-29 23:28:30 -07002422 }
Meenakshi Venkataraman615f7b92011-07-08 08:46:22 -07002423
2424 if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
2425 ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
2426 int sig = ifmgd->ave_beacon_signal;
2427 int last_sig = ifmgd->last_ave_beacon_signal;
2428
2429 /*
2430 * if signal crosses either of the boundaries, invoke callback
2431 * with appropriate parameters
2432 */
2433 if (sig > ifmgd->rssi_max_thold &&
2434 (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
2435 ifmgd->last_ave_beacon_signal = sig;
2436 drv_rssi_callback(local, RSSI_EVENT_HIGH);
2437 } else if (sig < ifmgd->rssi_min_thold &&
2438 (last_sig >= ifmgd->rssi_max_thold ||
2439 last_sig == 0)) {
2440 ifmgd->last_ave_beacon_signal = sig;
2441 drv_rssi_callback(local, RSSI_EVENT_LOW);
2442 }
2443 }
2444
Jouni Malinen17e4ec12010-03-29 23:28:30 -07002445 if (bss_conf->cqm_rssi_thold &&
Jouni Malinen391a2002010-08-27 22:22:00 +03002446 ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
Johannes Bergea086352012-01-19 09:29:58 +01002447 !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) {
Jouni Malinen17e4ec12010-03-29 23:28:30 -07002448 int sig = ifmgd->ave_beacon_signal / 16;
2449 int last_event = ifmgd->last_cqm_event_signal;
2450 int thold = bss_conf->cqm_rssi_thold;
2451 int hyst = bss_conf->cqm_rssi_hyst;
2452 if (sig < thold &&
2453 (last_event == 0 || sig < last_event - hyst)) {
2454 ifmgd->last_cqm_event_signal = sig;
2455 ieee80211_cqm_rssi_notify(
2456 &sdata->vif,
2457 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
2458 GFP_KERNEL);
2459 } else if (sig > thold &&
2460 (last_event == 0 || sig > last_event + hyst)) {
2461 ifmgd->last_cqm_event_signal = sig;
2462 ieee80211_cqm_rssi_notify(
2463 &sdata->vif,
2464 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
2465 GFP_KERNEL);
2466 }
2467 }
2468
Johannes Bergb291ba12009-07-10 15:29:03 +02002469 if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002470 mlme_dbg_ratelimited(sdata,
2471 "cancelling probereq poll due to a received beacon\n");
Stanislaw Gruszka925e64c2012-05-16 15:27:20 +02002472 mutex_lock(&local->mtx);
Johannes Bergb291ba12009-07-10 15:29:03 +02002473 ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
Stanislaw Gruszka925e64c2012-05-16 15:27:20 +02002474 ieee80211_run_deferred_scan(local);
2475 mutex_unlock(&local->mtx);
2476
Johannes Berg4e751842009-06-10 15:16:52 +02002477 mutex_lock(&local->iflist_mtx);
2478 ieee80211_recalc_ps(local, -1);
2479 mutex_unlock(&local->iflist_mtx);
Jouni Malinen92778182009-05-14 21:15:36 +03002480 }
2481
Johannes Bergb291ba12009-07-10 15:29:03 +02002482 /*
2483 * Push the beacon loss detection into the future since
2484 * we are processing a beacon from the AP just now.
2485 */
Luis R. Rodriguezd3a910a2010-09-16 15:12:32 -04002486 ieee80211_sta_reset_beacon_monitor(sdata);
Johannes Bergb291ba12009-07-10 15:29:03 +02002487
Johannes Bergd91f36d2009-04-16 13:17:26 +02002488 ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
2489 ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
2490 len - baselen, &elems,
2491 care_about_ies, ncrc);
2492
2493 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
Johannes Berge7ec86f2009-04-18 17:33:24 +02002494 directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
2495 ifmgd->aid);
Johannes Bergd91f36d2009-04-16 13:17:26 +02002496
Vivek Natarajan25c9c872009-03-02 20:20:30 +05302497 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
Kalle Valo1fb36062009-02-10 17:09:24 +02002498 if (directed_tim) {
Kalle Valo572e0012009-02-10 17:09:31 +02002499 if (local->hw.conf.dynamic_ps_timeout > 0) {
Ronald Wahl70b12f22012-03-19 14:37:20 +01002500 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
2501 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
2502 ieee80211_hw_config(local,
2503 IEEE80211_CONF_CHANGE_PS);
2504 }
Kalle Valo572e0012009-02-10 17:09:31 +02002505 ieee80211_send_nullfunc(local, sdata, 0);
Rajkumar Manoharan6f0756a2012-03-15 05:50:36 +05302506 } else if (!local->pspolling && sdata->u.mgd.powersave) {
Kalle Valo572e0012009-02-10 17:09:31 +02002507 local->pspolling = true;
2508
2509 /*
2510 * Here is assumed that the driver will be
2511 * able to send ps-poll frame and receive a
2512 * response even though power save mode is
2513 * enabled, but some drivers might require
2514 * to disable power save here. This needs
2515 * to be investigated.
2516 */
2517 ieee80211_send_pspoll(local, sdata);
2518 }
Vivek Natarajana97b77b2008-12-23 18:39:02 -08002519 }
2520 }
Johannes Berg7a5158e2008-10-08 10:59:33 +02002521
Juuso Oikarinend8ec4432010-10-01 16:02:31 +03002522 if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
Jouni Malinen30196672009-05-19 17:01:43 +03002523 return;
2524 ifmgd->beacon_crc = ncrc;
Juuso Oikarinend8ec4432010-10-01 16:02:31 +03002525 ifmgd->beacon_crc_valid = true;
Jouni Malinen30196672009-05-19 17:01:43 +03002526
Johannes Berg7d257452012-07-06 17:37:43 +02002527 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
2528 true);
2529
2530 if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
2531 elems.wmm_param_len))
2532 changed |= BSS_CHANGED_QOS;
2533
Johannes Berg7a5158e2008-10-08 10:59:33 +02002534 if (elems.erp_info && elems.erp_info_len >= 1) {
2535 erp_valid = true;
2536 erp_value = elems.erp_info[0];
2537 } else {
2538 erp_valid = false;
John W. Linville50c4afb2008-04-15 14:09:27 -04002539 }
Johannes Berg7a5158e2008-10-08 10:59:33 +02002540 changed |= ieee80211_handle_bss_capability(sdata,
2541 le16_to_cpu(mgmt->u.beacon.capab_info),
2542 erp_valid, erp_value);
Jiri Bencf0706e82007-05-05 11:45:53 -07002543
Ron Rindjunskyd3c990f2007-11-26 16:14:34 +02002544
Johannes Berg074d46d2012-03-15 19:45:16 +01002545 if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param &&
Johannes Bergab1faea2009-07-01 21:41:17 +02002546 !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
Johannes Bergae5eb022008-10-14 16:58:37 +02002547 struct ieee80211_supported_band *sband;
Johannes Bergae5eb022008-10-14 16:58:37 +02002548
Johannes Berg568d6e22012-07-23 14:29:21 +02002549 sband = local->hw.wiphy->bands[local->oper_channel->band];
Johannes Bergae5eb022008-10-14 16:58:37 +02002550
Johannes Berg24398e32012-03-28 10:58:36 +02002551 changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
2552 bssid, true);
Ron Rindjunskyd3c990f2007-11-26 16:14:34 +02002553 }
2554
Johannes Berg04b7b2f2012-09-05 13:41:37 +02002555 if (elems.country_elem && elems.pwr_constr_elem &&
2556 mgmt->u.probe_resp.capab_info &
2557 cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
2558 ieee80211_handle_pwr_constr(sdata, local->oper_channel,
2559 elems.country_elem,
2560 elems.country_elem_len,
2561 elems.pwr_constr_elem);
Luis R. Rodriguez3f2355c2008-11-12 14:22:02 -08002562
Johannes Berg471b3ef2007-12-28 14:32:58 +01002563 ieee80211_bss_info_change_notify(sdata, changed);
Jiri Bencf0706e82007-05-05 11:45:53 -07002564}
2565
Johannes Berg1fa57d02010-06-10 10:21:32 +02002566void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
2567 struct sk_buff *skb)
Jiri Bencf0706e82007-05-05 11:45:53 -07002568{
Johannes Berg77fdaa12009-07-07 03:45:17 +02002569 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Jiri Bencf0706e82007-05-05 11:45:53 -07002570 struct ieee80211_rx_status *rx_status;
Jiri Bencf0706e82007-05-05 11:45:53 -07002571 struct ieee80211_mgmt *mgmt;
Johannes Berg66e67e42012-01-20 13:55:27 +01002572 struct cfg80211_bss *bss = NULL;
Johannes Berg77fdaa12009-07-07 03:45:17 +02002573 enum rx_mgmt_action rma = RX_MGMT_NONE;
Jiri Bencf0706e82007-05-05 11:45:53 -07002574 u16 fc;
2575
Jiri Bencf0706e82007-05-05 11:45:53 -07002576 rx_status = (struct ieee80211_rx_status *) skb->cb;
2577 mgmt = (struct ieee80211_mgmt *) skb->data;
2578 fc = le16_to_cpu(mgmt->frame_control);
2579
Johannes Berg77fdaa12009-07-07 03:45:17 +02002580 mutex_lock(&ifmgd->mtx);
2581
Johannes Berg66e67e42012-01-20 13:55:27 +01002582 switch (fc & IEEE80211_FCTL_STYPE) {
2583 case IEEE80211_STYPE_BEACON:
2584 ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
2585 break;
2586 case IEEE80211_STYPE_PROBE_RESP:
2587 ieee80211_rx_mgmt_probe_resp(sdata, skb);
2588 break;
2589 case IEEE80211_STYPE_AUTH:
2590 rma = ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
2591 break;
2592 case IEEE80211_STYPE_DEAUTH:
2593 rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
2594 break;
2595 case IEEE80211_STYPE_DISASSOC:
2596 rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
2597 break;
2598 case IEEE80211_STYPE_ASSOC_RESP:
2599 case IEEE80211_STYPE_REASSOC_RESP:
2600 rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss);
2601 break;
2602 case IEEE80211_STYPE_ACTION:
2603 switch (mgmt->u.action.category) {
2604 case WLAN_CATEGORY_SPECTRUM_MGMT:
2605 ieee80211_sta_process_chanswitch(sdata,
2606 &mgmt->u.action.u.chan_switch.sw_elem,
2607 (void *)ifmgd->associated->priv,
2608 rx_status->mactime);
Johannes Berg77fdaa12009-07-07 03:45:17 +02002609 break;
Johannes Berg77fdaa12009-07-07 03:45:17 +02002610 }
Johannes Berg77fdaa12009-07-07 03:45:17 +02002611 }
Johannes Berg77fdaa12009-07-07 03:45:17 +02002612 mutex_unlock(&ifmgd->mtx);
2613
Johannes Berg66e67e42012-01-20 13:55:27 +01002614 switch (rma) {
2615 case RX_MGMT_NONE:
2616 /* no action */
2617 break;
2618 case RX_MGMT_CFG80211_DEAUTH:
Holger Schurigce470612009-10-13 13:28:13 +02002619 cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
Johannes Berg66e67e42012-01-20 13:55:27 +01002620 break;
2621 case RX_MGMT_CFG80211_DISASSOC:
2622 cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
2623 break;
2624 case RX_MGMT_CFG80211_RX_AUTH:
2625 cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, skb->len);
2626 break;
2627 case RX_MGMT_CFG80211_RX_ASSOC:
2628 cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, skb->len);
2629 break;
2630 case RX_MGMT_CFG80211_ASSOC_TIMEOUT:
2631 cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
2632 break;
2633 default:
2634 WARN(1, "unexpected: %d", rma);
Johannes Bergb054b742010-06-07 21:50:07 +02002635 }
Jiri Bencf0706e82007-05-05 11:45:53 -07002636}
2637
Johannes Berg9c6bd792008-09-11 00:01:52 +02002638static void ieee80211_sta_timer(unsigned long data)
Jiri Bencf0706e82007-05-05 11:45:53 -07002639{
2640 struct ieee80211_sub_if_data *sdata =
2641 (struct ieee80211_sub_if_data *) data;
Johannes Berg46900292009-02-15 12:44:28 +01002642 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +12002643 struct ieee80211_local *local = sdata->local;
Jiri Bencf0706e82007-05-05 11:45:53 -07002644
Johannes Berg5bb644a2009-05-17 11:40:42 +02002645 if (local->quiescing) {
2646 set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
2647 return;
2648 }
2649
Johannes Berg64592c82010-06-10 10:21:31 +02002650 ieee80211_queue_work(&local->hw, &sdata->work);
Jiri Bencf0706e82007-05-05 11:45:53 -07002651}
2652
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002653static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
Johannes Berg95acac62011-07-12 12:30:59 +02002654 u8 *bssid, u8 reason)
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002655{
2656 struct ieee80211_local *local = sdata->local;
2657 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Antonio Quartulli6ae16772012-09-07 13:28:52 +02002658 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002659
Johannes Berg37ad3882012-02-24 13:50:54 +01002660 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
2661 false, frame_buf);
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002662 mutex_unlock(&ifmgd->mtx);
Johannes Berg37ad3882012-02-24 13:50:54 +01002663
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002664 /*
2665 * must be outside lock due to cfg80211,
2666 * but that's not a problem.
2667 */
Antonio Quartulli6ae16772012-09-07 13:28:52 +02002668 cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
Felix Fietkaufcac4fb2011-11-16 13:34:55 +01002669
2670 mutex_lock(&local->mtx);
2671 ieee80211_recalc_idle(local);
2672 mutex_unlock(&local->mtx);
2673
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002674 mutex_lock(&ifmgd->mtx);
2675}
2676
Johannes Berg66e67e42012-01-20 13:55:27 +01002677static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
2678{
2679 struct ieee80211_local *local = sdata->local;
2680 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2681 struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data;
2682
2683 lockdep_assert_held(&ifmgd->mtx);
2684
2685 if (WARN_ON_ONCE(!auth_data))
2686 return -EINVAL;
2687
Johannes Berg66e67e42012-01-20 13:55:27 +01002688 auth_data->tries++;
2689
2690 if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002691 sdata_info(sdata, "authentication with %pM timed out\n",
2692 auth_data->bss->bssid);
Johannes Berg66e67e42012-01-20 13:55:27 +01002693
2694 /*
2695 * Most likely AP is not in the range so remove the
2696 * bss struct for that AP.
2697 */
2698 cfg80211_unlink_bss(local->hw.wiphy, auth_data->bss);
2699
2700 return -ETIMEDOUT;
2701 }
2702
Johannes Berga1845fc2012-06-27 13:18:36 +02002703 drv_mgd_prepare_tx(local, sdata);
2704
Johannes Berg66e67e42012-01-20 13:55:27 +01002705 if (auth_data->bss->proberesp_ies) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002706 sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
2707 auth_data->bss->bssid, auth_data->tries,
2708 IEEE80211_AUTH_MAX_TRIES);
Johannes Berg66e67e42012-01-20 13:55:27 +01002709
2710 auth_data->expected_transaction = 2;
2711 ieee80211_send_auth(sdata, 1, auth_data->algorithm,
2712 auth_data->ie, auth_data->ie_len,
2713 auth_data->bss->bssid,
2714 auth_data->bss->bssid, NULL, 0, 0);
2715 } else {
2716 const u8 *ssidie;
2717
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002718 sdata_info(sdata, "direct probe to %pM (try %d/%i)\n",
2719 auth_data->bss->bssid, auth_data->tries,
2720 IEEE80211_AUTH_MAX_TRIES);
Johannes Berg66e67e42012-01-20 13:55:27 +01002721
2722 ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
2723 if (!ssidie)
2724 return -EINVAL;
2725 /*
2726 * Direct probe is sent to broadcast address as some APs
2727 * will not answer to direct packet in unassociated state.
2728 */
2729 ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
Johannes Bergfe94fe02012-07-30 12:26:34 +02002730 NULL, 0, (u32) -1, true, false,
2731 auth_data->bss->channel);
Johannes Berg66e67e42012-01-20 13:55:27 +01002732 }
2733
2734 auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
2735 run_again(ifmgd, auth_data->timeout);
2736
2737 return 0;
2738}
2739
2740static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
2741{
2742 struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
2743 struct ieee80211_local *local = sdata->local;
2744
2745 lockdep_assert_held(&sdata->u.mgd.mtx);
2746
Johannes Berg66e67e42012-01-20 13:55:27 +01002747 assoc_data->tries++;
2748 if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002749 sdata_info(sdata, "association with %pM timed out\n",
2750 assoc_data->bss->bssid);
Johannes Berg66e67e42012-01-20 13:55:27 +01002751
2752 /*
2753 * Most likely AP is not in the range so remove the
2754 * bss struct for that AP.
2755 */
2756 cfg80211_unlink_bss(local->hw.wiphy, assoc_data->bss);
2757
2758 return -ETIMEDOUT;
2759 }
2760
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002761 sdata_info(sdata, "associate with %pM (try %d/%d)\n",
2762 assoc_data->bss->bssid, assoc_data->tries,
2763 IEEE80211_ASSOC_MAX_TRIES);
Johannes Berg66e67e42012-01-20 13:55:27 +01002764 ieee80211_send_assoc(sdata);
2765
2766 assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
2767 run_again(&sdata->u.mgd, assoc_data->timeout);
2768
2769 return 0;
2770}
2771
Johannes Berg1fa57d02010-06-10 10:21:32 +02002772void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
Johannes Berg60f8b392008-09-08 17:44:22 +02002773{
Johannes Berg60f8b392008-09-08 17:44:22 +02002774 struct ieee80211_local *local = sdata->local;
Johannes Berg1fa57d02010-06-10 10:21:32 +02002775 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Johannes Berg60f8b392008-09-08 17:44:22 +02002776
Johannes Berg77fdaa12009-07-07 03:45:17 +02002777 mutex_lock(&ifmgd->mtx);
Johannes Berg60f8b392008-09-08 17:44:22 +02002778
Johannes Berg66e67e42012-01-20 13:55:27 +01002779 if (ifmgd->auth_data &&
2780 time_after(jiffies, ifmgd->auth_data->timeout)) {
2781 if (ifmgd->auth_data->done) {
2782 /*
2783 * ok ... we waited for assoc but userspace didn't,
2784 * so let's just kill the auth data
2785 */
2786 ieee80211_destroy_auth_data(sdata, false);
2787 } else if (ieee80211_probe_auth(sdata)) {
2788 u8 bssid[ETH_ALEN];
2789
2790 memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
2791
2792 ieee80211_destroy_auth_data(sdata, false);
2793
2794 mutex_unlock(&ifmgd->mtx);
2795 cfg80211_send_auth_timeout(sdata->dev, bssid);
2796 mutex_lock(&ifmgd->mtx);
2797 }
2798 } else if (ifmgd->auth_data)
2799 run_again(ifmgd, ifmgd->auth_data->timeout);
2800
2801 if (ifmgd->assoc_data &&
2802 time_after(jiffies, ifmgd->assoc_data->timeout)) {
2803 if (!ifmgd->assoc_data->have_beacon ||
2804 ieee80211_do_assoc(sdata)) {
2805 u8 bssid[ETH_ALEN];
2806
2807 memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN);
2808
2809 ieee80211_destroy_assoc_data(sdata, false);
2810
2811 mutex_unlock(&ifmgd->mtx);
2812 cfg80211_send_assoc_timeout(sdata->dev, bssid);
2813 mutex_lock(&ifmgd->mtx);
2814 }
2815 } else if (ifmgd->assoc_data)
2816 run_again(ifmgd, ifmgd->assoc_data->timeout);
2817
Johannes Bergb291ba12009-07-10 15:29:03 +02002818 if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
2819 IEEE80211_STA_CONNECTION_POLL) &&
2820 ifmgd->associated) {
Maxim Levitskya43abf22009-07-31 18:54:12 +03002821 u8 bssid[ETH_ALEN];
Felix Fietkau72a8a3e2010-11-23 03:10:32 +01002822 int max_tries;
Maxim Levitskya43abf22009-07-31 18:54:12 +03002823
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01002824 memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
Felix Fietkau4e5ff372010-11-23 03:10:31 +01002825
Felix Fietkau72a8a3e2010-11-23 03:10:32 +01002826 if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
Ben Greear180205b2011-02-04 15:30:24 -08002827 max_tries = max_nullfunc_tries;
Felix Fietkau72a8a3e2010-11-23 03:10:32 +01002828 else
Ben Greear180205b2011-02-04 15:30:24 -08002829 max_tries = max_probe_tries;
Felix Fietkau72a8a3e2010-11-23 03:10:32 +01002830
Felix Fietkau4e5ff372010-11-23 03:10:31 +01002831 /* ACK received for nullfunc probing frame */
2832 if (!ifmgd->probe_send_count)
2833 ieee80211_reset_ap_probe(sdata);
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002834 else if (ifmgd->nullfunc_failed) {
2835 if (ifmgd->probe_send_count < max_tries) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002836 mlme_dbg(sdata,
2837 "No ack for nullfunc frame to AP %pM, try %d/%i\n",
2838 bssid, ifmgd->probe_send_count,
2839 max_tries);
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002840 ieee80211_mgd_probe_ap_send(sdata);
2841 } else {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002842 mlme_dbg(sdata,
2843 "No ack for nullfunc frame to AP %pM, disconnecting.\n",
2844 bssid);
Johannes Berg95acac62011-07-12 12:30:59 +02002845 ieee80211_sta_connection_lost(sdata, bssid,
2846 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002847 }
2848 } else if (time_is_after_jiffies(ifmgd->probe_timeout))
Johannes Bergb291ba12009-07-10 15:29:03 +02002849 run_again(ifmgd, ifmgd->probe_timeout);
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002850 else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002851 mlme_dbg(sdata,
2852 "Failed to send nullfunc to AP %pM after %dms, disconnecting\n",
2853 bssid, probe_wait_ms);
Johannes Berg95acac62011-07-12 12:30:59 +02002854 ieee80211_sta_connection_lost(sdata, bssid,
2855 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002856 } else if (ifmgd->probe_send_count < max_tries) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002857 mlme_dbg(sdata,
2858 "No probe response from AP %pM after %dms, try %d/%i\n",
2859 bssid, probe_wait_ms,
2860 ifmgd->probe_send_count, max_tries);
Maxim Levitskya43abf22009-07-31 18:54:12 +03002861 ieee80211_mgd_probe_ap_send(sdata);
2862 } else {
Johannes Bergb291ba12009-07-10 15:29:03 +02002863 /*
2864 * We actually lost the connection ... or did we?
2865 * Let's make sure!
2866 */
Ben Greearb38afa82010-10-07 16:12:06 -07002867 wiphy_debug(local->hw.wiphy,
2868 "%s: No probe response from AP %pM"
2869 " after %dms, disconnecting.\n",
2870 sdata->name,
Ben Greear180205b2011-02-04 15:30:24 -08002871 bssid, probe_wait_ms);
Felix Fietkau04ac3c02010-12-02 21:01:08 +01002872
Johannes Berg95acac62011-07-12 12:30:59 +02002873 ieee80211_sta_connection_lost(sdata, bssid,
2874 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
Johannes Bergb291ba12009-07-10 15:29:03 +02002875 }
2876 }
2877
Johannes Berg77fdaa12009-07-07 03:45:17 +02002878 mutex_unlock(&ifmgd->mtx);
Johannes Berg66e67e42012-01-20 13:55:27 +01002879
2880 mutex_lock(&local->mtx);
2881 ieee80211_recalc_idle(local);
2882 mutex_unlock(&local->mtx);
Johannes Berg60f8b392008-09-08 17:44:22 +02002883}
Johannes Berg0a51b272008-09-08 17:44:25 +02002884
Johannes Bergb291ba12009-07-10 15:29:03 +02002885static void ieee80211_sta_bcn_mon_timer(unsigned long data)
2886{
2887 struct ieee80211_sub_if_data *sdata =
2888 (struct ieee80211_sub_if_data *) data;
2889 struct ieee80211_local *local = sdata->local;
2890
2891 if (local->quiescing)
2892 return;
2893
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02002894 ieee80211_queue_work(&sdata->local->hw,
2895 &sdata->u.mgd.beacon_connection_loss_work);
Johannes Bergb291ba12009-07-10 15:29:03 +02002896}
2897
2898static void ieee80211_sta_conn_mon_timer(unsigned long data)
2899{
2900 struct ieee80211_sub_if_data *sdata =
2901 (struct ieee80211_sub_if_data *) data;
2902 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2903 struct ieee80211_local *local = sdata->local;
2904
2905 if (local->quiescing)
2906 return;
2907
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002908 ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
Johannes Bergb291ba12009-07-10 15:29:03 +02002909}
2910
2911static void ieee80211_sta_monitor_work(struct work_struct *work)
2912{
2913 struct ieee80211_sub_if_data *sdata =
2914 container_of(work, struct ieee80211_sub_if_data,
2915 u.mgd.monitor_work);
2916
2917 ieee80211_mgd_probe_ap(sdata, false);
2918}
2919
Johannes Berga1678f82008-09-11 00:01:47 +02002920static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
2921{
Eliad Peller494f1fe2012-02-19 15:26:09 +02002922 u32 flags;
2923
Kalle Vaload935682009-04-19 08:47:19 +03002924 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
Stanislaw Gruszka925e64c2012-05-16 15:27:20 +02002925 __ieee80211_stop_poll(sdata);
Kalle Vaload935682009-04-19 08:47:19 +03002926
Johannes Bergb291ba12009-07-10 15:29:03 +02002927 /* let's probe the connection once */
Eliad Peller494f1fe2012-02-19 15:26:09 +02002928 flags = sdata->local->hw.flags;
2929 if (!(flags & IEEE80211_HW_CONNECTION_MONITOR))
2930 ieee80211_queue_work(&sdata->local->hw,
2931 &sdata->u.mgd.monitor_work);
Johannes Bergb291ba12009-07-10 15:29:03 +02002932 /* and do all the other regular work too */
Johannes Berg64592c82010-06-10 10:21:31 +02002933 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
Kalle Vaload935682009-04-19 08:47:19 +03002934 }
Johannes Berga1678f82008-09-11 00:01:47 +02002935}
2936
Johannes Berg5bb644a2009-05-17 11:40:42 +02002937#ifdef CONFIG_PM
2938void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
2939{
2940 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2941
2942 /*
2943 * we need to use atomic bitops for the running bits
2944 * only because both timers might fire at the same
2945 * time -- the code here is properly synchronised.
2946 */
2947
Johannes Bergd1f5b7a2010-08-05 17:05:55 +02002948 cancel_work_sync(&ifmgd->request_smps_work);
2949
Johannes Berg0ecfe8062011-11-09 12:14:16 +01002950 cancel_work_sync(&ifmgd->monitor_work);
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02002951 cancel_work_sync(&ifmgd->beacon_connection_loss_work);
Johannes Berg882a7c62012-08-01 22:32:45 +02002952 cancel_work_sync(&ifmgd->csa_connection_drop_work);
Johannes Berg5bb644a2009-05-17 11:40:42 +02002953 if (del_timer_sync(&ifmgd->timer))
2954 set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
2955
2956 cancel_work_sync(&ifmgd->chswitch_work);
2957 if (del_timer_sync(&ifmgd->chswitch_timer))
2958 set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
Johannes Bergb291ba12009-07-10 15:29:03 +02002959
Johannes Bergb291ba12009-07-10 15:29:03 +02002960 /* these will just be re-established on connection */
2961 del_timer_sync(&ifmgd->conn_mon_timer);
2962 del_timer_sync(&ifmgd->bcn_mon_timer);
Johannes Berg5bb644a2009-05-17 11:40:42 +02002963}
2964
2965void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
2966{
2967 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2968
Rajkumar Manoharan676b58c2011-07-07 23:33:39 +05302969 if (!ifmgd->associated)
2970 return;
2971
Johannes Berg95acac62011-07-12 12:30:59 +02002972 if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
2973 sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
2974 mutex_lock(&ifmgd->mtx);
2975 if (ifmgd->associated) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02002976 mlme_dbg(sdata,
2977 "driver requested disconnect after resume\n");
Johannes Berg95acac62011-07-12 12:30:59 +02002978 ieee80211_sta_connection_lost(sdata,
2979 ifmgd->associated->bssid,
2980 WLAN_REASON_UNSPECIFIED);
2981 mutex_unlock(&ifmgd->mtx);
2982 return;
2983 }
2984 mutex_unlock(&ifmgd->mtx);
2985 }
2986
Johannes Berg5bb644a2009-05-17 11:40:42 +02002987 if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
2988 add_timer(&ifmgd->timer);
2989 if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
2990 add_timer(&ifmgd->chswitch_timer);
Felix Fietkauc8a79722010-11-19 22:55:37 +01002991 ieee80211_sta_reset_beacon_monitor(sdata);
Stanislaw Gruszka925e64c2012-05-16 15:27:20 +02002992
2993 mutex_lock(&sdata->local->mtx);
Felix Fietkau46090972010-11-23 20:28:03 +01002994 ieee80211_restart_sta_timer(sdata);
Stanislaw Gruszka925e64c2012-05-16 15:27:20 +02002995 mutex_unlock(&sdata->local->mtx);
Johannes Berg5bb644a2009-05-17 11:40:42 +02002996}
2997#endif
2998
Johannes Berg9c6bd792008-09-11 00:01:52 +02002999/* interface setup */
3000void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
3001{
Johannes Berg46900292009-02-15 12:44:28 +01003002 struct ieee80211_if_managed *ifmgd;
Johannes Berg9c6bd792008-09-11 00:01:52 +02003003
Johannes Berg46900292009-02-15 12:44:28 +01003004 ifmgd = &sdata->u.mgd;
Johannes Bergb291ba12009-07-10 15:29:03 +02003005 INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
Johannes Berg46900292009-02-15 12:44:28 +01003006 INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
Juuso Oikarinen1e4dcd02010-03-19 07:14:53 +02003007 INIT_WORK(&ifmgd->beacon_connection_loss_work,
3008 ieee80211_beacon_connection_loss_work);
Johannes Berg882a7c62012-08-01 22:32:45 +02003009 INIT_WORK(&ifmgd->csa_connection_drop_work,
3010 ieee80211_csa_connection_drop_work);
Johannes Bergd1f5b7a2010-08-05 17:05:55 +02003011 INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
Johannes Berg46900292009-02-15 12:44:28 +01003012 setup_timer(&ifmgd->timer, ieee80211_sta_timer,
Johannes Berg9c6bd792008-09-11 00:01:52 +02003013 (unsigned long) sdata);
Johannes Bergb291ba12009-07-10 15:29:03 +02003014 setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
3015 (unsigned long) sdata);
3016 setup_timer(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer,
3017 (unsigned long) sdata);
Johannes Berg46900292009-02-15 12:44:28 +01003018 setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
Sujithc481ec92009-01-06 09:28:37 +05303019 (unsigned long) sdata);
Johannes Berg9c6bd792008-09-11 00:01:52 +02003020
Johannes Bergab1faea2009-07-01 21:41:17 +02003021 ifmgd->flags = 0;
Mohammed Shafi Shajakhan1478acb2011-12-14 19:46:08 +05303022 ifmgd->powersave = sdata->wdev.ps;
Eliad Pellerdc41e4d2012-03-14 16:15:03 +02003023 ifmgd->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
3024 ifmgd->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
Johannes Bergbbbdff92009-04-16 13:27:42 +02003025
Johannes Berg77fdaa12009-07-07 03:45:17 +02003026 mutex_init(&ifmgd->mtx);
Johannes Berg0f782312009-12-01 13:37:02 +01003027
3028 if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
3029 ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC;
3030 else
3031 ifmgd->req_smps = IEEE80211_SMPS_OFF;
Johannes Berg9c6bd792008-09-11 00:01:52 +02003032}
3033
3034/* scan finished notification */
Johannes Berg0a51b272008-09-08 17:44:25 +02003035void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
3036{
Johannes Berg31ee67a2012-07-06 21:18:24 +02003037 struct ieee80211_sub_if_data *sdata;
Johannes Berga1678f82008-09-11 00:01:47 +02003038
3039 /* Restart STA timers */
3040 rcu_read_lock();
3041 list_for_each_entry_rcu(sdata, &local->interfaces, list)
3042 ieee80211_restart_sta_timer(sdata);
3043 rcu_read_unlock();
Johannes Berg0a51b272008-09-08 17:44:25 +02003044}
Johannes Berg10f644a2009-04-16 13:17:25 +02003045
3046int ieee80211_max_network_latency(struct notifier_block *nb,
3047 unsigned long data, void *dummy)
3048{
3049 s32 latency_usec = (s32) data;
3050 struct ieee80211_local *local =
3051 container_of(nb, struct ieee80211_local,
3052 network_latency_notifier);
3053
3054 mutex_lock(&local->iflist_mtx);
3055 ieee80211_recalc_ps(local, latency_usec);
3056 mutex_unlock(&local->iflist_mtx);
3057
3058 return 0;
3059}
Johannes Berg77fdaa12009-07-07 03:45:17 +02003060
Johannes Bergb17166a2012-07-27 11:41:27 +02003061static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3062 struct cfg80211_bss *cbss)
Johannes Berga1cf7752012-03-08 15:02:07 +01003063{
3064 struct ieee80211_local *local = sdata->local;
3065 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Johannes Berg24398e32012-03-28 10:58:36 +02003066 int ht_cfreq;
3067 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
3068 const u8 *ht_oper_ie;
3069 const struct ieee80211_ht_operation *ht_oper = NULL;
3070 struct ieee80211_supported_band *sband;
Johannes Berga1cf7752012-03-08 15:02:07 +01003071
Johannes Berg24398e32012-03-28 10:58:36 +02003072 sband = local->hw.wiphy->bands[cbss->channel->band];
3073
3074 ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ;
3075
3076 if (sband->ht_cap.ht_supported) {
3077 ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION,
3078 cbss->information_elements,
3079 cbss->len_information_elements);
3080 if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
3081 ht_oper = (void *)(ht_oper_ie + 2);
3082 }
3083
3084 if (ht_oper) {
3085 ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
3086 cbss->channel->band);
3087 /* check that channel matches the right operating channel */
3088 if (cbss->channel->center_freq != ht_cfreq) {
3089 /*
3090 * It's possible that some APs are confused here;
3091 * Netgear WNDR3700 sometimes reports 4 higher than
3092 * the actual channel in association responses, but
3093 * since we look at probe response/beacon data here
3094 * it should be OK.
3095 */
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003096 sdata_info(sdata,
3097 "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
3098 cbss->channel->center_freq,
3099 ht_cfreq, ht_oper->primary_chan,
3100 cbss->channel->band);
Johannes Berg24398e32012-03-28 10:58:36 +02003101 ht_oper = NULL;
3102 }
3103 }
3104
3105 if (ht_oper) {
3106 channel_type = NL80211_CHAN_HT20;
3107
3108 if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
3109 switch (ht_oper->ht_param &
3110 IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
3111 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
3112 channel_type = NL80211_CHAN_HT40PLUS;
3113 break;
3114 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
3115 channel_type = NL80211_CHAN_HT40MINUS;
3116 break;
3117 }
3118 }
3119 }
3120
3121 if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
3122 /* can only fail due to HT40+/- mismatch */
3123 channel_type = NL80211_CHAN_HT20;
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003124 sdata_info(sdata,
3125 "disabling 40 MHz due to multi-vif mismatch\n");
Johannes Berg24398e32012-03-28 10:58:36 +02003126 ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
3127 WARN_ON(!ieee80211_set_channel_type(local, sdata,
3128 channel_type));
3129 }
3130
Johannes Berg5d6a1b02012-03-08 15:02:08 +01003131 local->oper_channel = cbss->channel;
Stanislaw Gruszka6aee4ca2012-06-07 14:47:21 +02003132 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
Johannes Berga1cf7752012-03-08 15:02:07 +01003133
Johannes Bergb17166a2012-07-27 11:41:27 +02003134 return 0;
3135}
3136
3137static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
3138 struct cfg80211_bss *cbss, bool assoc)
3139{
3140 struct ieee80211_local *local = sdata->local;
3141 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3142 struct ieee80211_bss *bss = (void *)cbss->priv;
3143 struct sta_info *new_sta = NULL;
3144 bool have_sta = false;
3145 int err;
3146
3147 if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
3148 return -EINVAL;
3149
3150 if (assoc) {
3151 rcu_read_lock();
3152 have_sta = sta_info_get(sdata, cbss->bssid);
3153 rcu_read_unlock();
3154 }
3155
3156 if (!have_sta) {
3157 new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
3158 if (!new_sta)
3159 return -ENOMEM;
3160 }
3161
3162 mutex_lock(&local->mtx);
3163 ieee80211_recalc_idle(sdata->local);
3164 mutex_unlock(&local->mtx);
3165
Johannes Berg13e0c8e2012-07-27 10:43:16 +02003166 if (new_sta) {
Johannes Berg5d6a1b02012-03-08 15:02:08 +01003167 u32 rates = 0, basic_rates = 0;
3168 bool have_higher_than_11mbit;
3169 int min_rate = INT_MAX, min_rate_index = -1;
Johannes Bergb17166a2012-07-27 11:41:27 +02003170 struct ieee80211_supported_band *sband;
3171
3172 sband = local->hw.wiphy->bands[cbss->channel->band];
3173
3174 err = ieee80211_prep_channel(sdata, cbss);
3175 if (err) {
3176 sta_info_free(local, new_sta);
3177 return err;
3178 }
Johannes Berg5d6a1b02012-03-08 15:02:08 +01003179
Johannes Berg5d6a1b02012-03-08 15:02:08 +01003180 ieee80211_get_rates(sband, bss->supp_rates,
3181 bss->supp_rates_len,
3182 &rates, &basic_rates,
3183 &have_higher_than_11mbit,
3184 &min_rate, &min_rate_index);
3185
3186 /*
3187 * This used to be a workaround for basic rates missing
3188 * in the association response frame. Now that we no
3189 * longer use the basic rates from there, it probably
3190 * doesn't happen any more, but keep the workaround so
3191 * in case some *other* APs are buggy in different ways
3192 * we can connect -- with a warning.
3193 */
3194 if (!basic_rates && min_rate_index >= 0) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003195 sdata_info(sdata,
3196 "No basic rates, using min rate instead\n");
Johannes Berg5d6a1b02012-03-08 15:02:08 +01003197 basic_rates = BIT(min_rate_index);
3198 }
3199
Johannes Berg13e0c8e2012-07-27 10:43:16 +02003200 new_sta->sta.supp_rates[cbss->channel->band] = rates;
Johannes Berg5d6a1b02012-03-08 15:02:08 +01003201 sdata->vif.bss_conf.basic_rates = basic_rates;
3202
3203 /* cf. IEEE 802.11 9.2.12 */
3204 if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
3205 have_higher_than_11mbit)
3206 sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
3207 else
3208 sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
3209
3210 memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN);
3211
Johannes Berg8c358bc2012-05-22 22:13:05 +02003212 /* set timing information */
3213 sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
3214 sdata->vif.bss_conf.sync_tsf = cbss->tsf;
3215 sdata->vif.bss_conf.sync_device_ts = bss->device_ts;
3216
3217 /* tell driver about BSSID, basic rates and timing */
Johannes Berg5d6a1b02012-03-08 15:02:08 +01003218 ieee80211_bss_info_change_notify(sdata,
Johannes Berg8c358bc2012-05-22 22:13:05 +02003219 BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES |
3220 BSS_CHANGED_BEACON_INT);
Johannes Berga1cf7752012-03-08 15:02:07 +01003221
3222 if (assoc)
Johannes Berg13e0c8e2012-07-27 10:43:16 +02003223 sta_info_pre_move_state(new_sta, IEEE80211_STA_AUTH);
Johannes Berga1cf7752012-03-08 15:02:07 +01003224
Johannes Berg13e0c8e2012-07-27 10:43:16 +02003225 err = sta_info_insert(new_sta);
3226 new_sta = NULL;
Johannes Berga1cf7752012-03-08 15:02:07 +01003227 if (err) {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003228 sdata_info(sdata,
3229 "failed to insert STA entry for the AP (error %d)\n",
3230 err);
Johannes Berga1cf7752012-03-08 15:02:07 +01003231 return err;
3232 }
3233 } else
Joe Perchesb203ca32012-05-08 18:56:52 +00003234 WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid));
Johannes Berga1cf7752012-03-08 15:02:07 +01003235
3236 return 0;
3237}
3238
Johannes Berg77fdaa12009-07-07 03:45:17 +02003239/* config hooks */
3240int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
3241 struct cfg80211_auth_request *req)
3242{
Johannes Berg66e67e42012-01-20 13:55:27 +01003243 struct ieee80211_local *local = sdata->local;
3244 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3245 struct ieee80211_mgd_auth_data *auth_data;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003246 u16 auth_alg;
Johannes Berg66e67e42012-01-20 13:55:27 +01003247 int err;
3248
3249 /* prepare auth data structure */
Johannes Berg77fdaa12009-07-07 03:45:17 +02003250
3251 switch (req->auth_type) {
3252 case NL80211_AUTHTYPE_OPEN_SYSTEM:
3253 auth_alg = WLAN_AUTH_OPEN;
3254 break;
3255 case NL80211_AUTHTYPE_SHARED_KEY:
Johannes Berg66e67e42012-01-20 13:55:27 +01003256 if (IS_ERR(local->wep_tx_tfm))
Johannes Berg9dca9c42010-07-21 10:09:25 +02003257 return -EOPNOTSUPP;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003258 auth_alg = WLAN_AUTH_SHARED_KEY;
3259 break;
3260 case NL80211_AUTHTYPE_FT:
3261 auth_alg = WLAN_AUTH_FT;
3262 break;
3263 case NL80211_AUTHTYPE_NETWORK_EAP:
3264 auth_alg = WLAN_AUTH_LEAP;
3265 break;
3266 default:
3267 return -EOPNOTSUPP;
3268 }
3269
Johannes Berg66e67e42012-01-20 13:55:27 +01003270 auth_data = kzalloc(sizeof(*auth_data) + req->ie_len, GFP_KERNEL);
3271 if (!auth_data)
Johannes Berg77fdaa12009-07-07 03:45:17 +02003272 return -ENOMEM;
3273
Johannes Berg66e67e42012-01-20 13:55:27 +01003274 auth_data->bss = req->bss;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003275
3276 if (req->ie && req->ie_len) {
Johannes Berg66e67e42012-01-20 13:55:27 +01003277 memcpy(auth_data->ie, req->ie, req->ie_len);
3278 auth_data->ie_len = req->ie_len;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003279 }
3280
Johannes Bergfffd0932009-07-08 14:22:54 +02003281 if (req->key && req->key_len) {
Johannes Berg66e67e42012-01-20 13:55:27 +01003282 auth_data->key_len = req->key_len;
3283 auth_data->key_idx = req->key_idx;
3284 memcpy(auth_data->key, req->key, req->key_len);
Johannes Bergfffd0932009-07-08 14:22:54 +02003285 }
3286
Johannes Berg66e67e42012-01-20 13:55:27 +01003287 auth_data->algorithm = auth_alg;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003288
Johannes Berg66e67e42012-01-20 13:55:27 +01003289 /* try to authenticate/probe */
Johannes Bergf679f652009-12-23 13:15:34 +01003290
Johannes Berg66e67e42012-01-20 13:55:27 +01003291 mutex_lock(&ifmgd->mtx);
Johannes Berg77fdaa12009-07-07 03:45:17 +02003292
Johannes Berg66e67e42012-01-20 13:55:27 +01003293 if ((ifmgd->auth_data && !ifmgd->auth_data->done) ||
3294 ifmgd->assoc_data) {
3295 err = -EBUSY;
3296 goto err_free;
3297 }
Johannes Berg77fdaa12009-07-07 03:45:17 +02003298
Johannes Berg66e67e42012-01-20 13:55:27 +01003299 if (ifmgd->auth_data)
3300 ieee80211_destroy_auth_data(sdata, false);
Guy Eilam2a33bee2011-08-17 15:18:15 +03003301
Johannes Berg66e67e42012-01-20 13:55:27 +01003302 /* prep auth_data so we don't go into idle on disassoc */
3303 ifmgd->auth_data = auth_data;
3304
3305 if (ifmgd->associated)
Johannes Berg37ad3882012-02-24 13:50:54 +01003306 ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
Johannes Berg66e67e42012-01-20 13:55:27 +01003307
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003308 sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
Johannes Berg66e67e42012-01-20 13:55:27 +01003309
Johannes Berga1cf7752012-03-08 15:02:07 +01003310 err = ieee80211_prep_connection(sdata, req->bss, false);
3311 if (err)
Johannes Berg66e67e42012-01-20 13:55:27 +01003312 goto err_clear;
Guy Eilam2a33bee2011-08-17 15:18:15 +03003313
Johannes Berg66e67e42012-01-20 13:55:27 +01003314 err = ieee80211_probe_auth(sdata);
3315 if (err) {
Johannes Berg66e67e42012-01-20 13:55:27 +01003316 sta_info_destroy_addr(sdata, req->bss->bssid);
3317 goto err_clear;
Johannes Bergaf6b6372009-12-23 13:15:35 +01003318 }
3319
Johannes Berg66e67e42012-01-20 13:55:27 +01003320 /* hold our own reference */
3321 cfg80211_ref_bss(auth_data->bss);
3322 err = 0;
3323 goto out_unlock;
Johannes Berge5b900d2010-07-29 16:08:55 +02003324
Johannes Berg66e67e42012-01-20 13:55:27 +01003325 err_clear:
Eliad Peller3d2abdf2012-09-04 17:44:45 +03003326 memset(ifmgd->bssid, 0, ETH_ALEN);
3327 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
Johannes Berg66e67e42012-01-20 13:55:27 +01003328 ifmgd->auth_data = NULL;
3329 err_free:
3330 kfree(auth_data);
3331 out_unlock:
3332 mutex_unlock(&ifmgd->mtx);
Johannes Berge5b900d2010-07-29 16:08:55 +02003333
Johannes Berg66e67e42012-01-20 13:55:27 +01003334 return err;
Johannes Bergaf6b6372009-12-23 13:15:35 +01003335}
3336
Johannes Berg77fdaa12009-07-07 03:45:17 +02003337int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
3338 struct cfg80211_assoc_request *req)
3339{
Johannes Berg66e67e42012-01-20 13:55:27 +01003340 struct ieee80211_local *local = sdata->local;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003341 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01003342 struct ieee80211_bss *bss = (void *)req->bss->priv;
Johannes Berg66e67e42012-01-20 13:55:27 +01003343 struct ieee80211_mgd_assoc_data *assoc_data;
Johannes Berg4e74bfd2012-03-08 15:02:04 +01003344 struct ieee80211_supported_band *sband;
Johannes Berg9dde6422012-05-16 23:43:19 +02003345 const u8 *ssidie, *ht_ie;
Guy Eilam2a33bee2011-08-17 15:18:15 +03003346 int i, err;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003347
Johannes Berg66e67e42012-01-20 13:55:27 +01003348 ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
3349 if (!ssidie)
3350 return -EINVAL;
Jouni Malinen9c87ba62010-02-28 12:13:46 +02003351
Johannes Berg66e67e42012-01-20 13:55:27 +01003352 assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL);
3353 if (!assoc_data)
Johannes Bergaf6b6372009-12-23 13:15:35 +01003354 return -ENOMEM;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003355
Johannes Berg66e67e42012-01-20 13:55:27 +01003356 mutex_lock(&ifmgd->mtx);
3357
3358 if (ifmgd->associated)
Johannes Berg37ad3882012-02-24 13:50:54 +01003359 ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
Johannes Berg66e67e42012-01-20 13:55:27 +01003360
3361 if (ifmgd->auth_data && !ifmgd->auth_data->done) {
3362 err = -EBUSY;
3363 goto err_free;
Guy Eilam2a33bee2011-08-17 15:18:15 +03003364 }
3365
Johannes Berg66e67e42012-01-20 13:55:27 +01003366 if (ifmgd->assoc_data) {
3367 err = -EBUSY;
3368 goto err_free;
3369 }
3370
3371 if (ifmgd->auth_data) {
3372 bool match;
3373
3374 /* keep sta info, bssid if matching */
Joe Perchesb203ca32012-05-08 18:56:52 +00003375 match = ether_addr_equal(ifmgd->bssid, req->bss->bssid);
Johannes Berg66e67e42012-01-20 13:55:27 +01003376 ieee80211_destroy_auth_data(sdata, match);
3377 }
3378
3379 /* prepare assoc data */
Johannes Berg19c3b832012-08-01 20:13:36 +02003380
3381 /*
3382 * keep only the 40 MHz disable bit set as it might have
3383 * been set during authentication already, all other bits
3384 * should be reset for a new connection
3385 */
3386 ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003387
Juuso Oikarinend8ec4432010-10-01 16:02:31 +03003388 ifmgd->beacon_crc_valid = false;
3389
Johannes Bergde5036a2012-03-08 15:02:03 +01003390 /*
3391 * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode.
3392 * We still associate in non-HT mode (11a/b/g) if any one of these
3393 * ciphers is configured as pairwise.
3394 * We can set this to true for non-11n hardware, that'll be checked
3395 * separately along with the peer capabilities.
3396 */
Johannes Berg1c4cb922012-05-30 15:57:00 +02003397 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) {
Johannes Berg77fdaa12009-07-07 03:45:17 +02003398 if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
3399 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
Johannes Berg1c4cb922012-05-30 15:57:00 +02003400 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
Johannes Berg77fdaa12009-07-07 03:45:17 +02003401 ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
Mahesh Palivelad545dab2012-07-24 03:33:10 +00003402 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
Johannes Berg1c4cb922012-05-30 15:57:00 +02003403 netdev_info(sdata->dev,
Mahesh Palivelad545dab2012-07-24 03:33:10 +00003404 "disabling HT/VHT due to WEP/TKIP use\n");
Johannes Berg1c4cb922012-05-30 15:57:00 +02003405 }
3406 }
Johannes Berg77fdaa12009-07-07 03:45:17 +02003407
Mahesh Palivelad545dab2012-07-24 03:33:10 +00003408 if (req->flags & ASSOC_REQ_DISABLE_HT) {
Ben Greearef96a8422011-11-18 11:32:00 -08003409 ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
Mahesh Palivelad545dab2012-07-24 03:33:10 +00003410 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
3411 }
Ben Greearef96a8422011-11-18 11:32:00 -08003412
Johannes Berg4e74bfd2012-03-08 15:02:04 +01003413 /* Also disable HT if we don't support it or the AP doesn't use WMM */
3414 sband = local->hw.wiphy->bands[req->bss->channel->band];
3415 if (!sband->ht_cap.ht_supported ||
Johannes Berg1c4cb922012-05-30 15:57:00 +02003416 local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
Johannes Berg4e74bfd2012-03-08 15:02:04 +01003417 ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
Johannes Berg1b49de22012-07-27 10:29:14 +02003418 if (!bss->wmm_used)
3419 netdev_info(sdata->dev,
3420 "disabling HT as WMM/QoS is not supported by the AP\n");
Johannes Berg1c4cb922012-05-30 15:57:00 +02003421 }
Johannes Berg4e74bfd2012-03-08 15:02:04 +01003422
Mahesh Palivelad545dab2012-07-24 03:33:10 +00003423 /* disable VHT if we don't support it or the AP doesn't use WMM */
3424 if (!sband->vht_cap.vht_supported ||
3425 local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
3426 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
Johannes Berg1b49de22012-07-27 10:29:14 +02003427 if (!bss->wmm_used)
3428 netdev_info(sdata->dev,
3429 "disabling VHT as WMM/QoS is not supported by the AP\n");
Mahesh Palivelad545dab2012-07-24 03:33:10 +00003430 }
3431
Ben Greearef96a8422011-11-18 11:32:00 -08003432 memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
3433 memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
3434 sizeof(ifmgd->ht_capa_mask));
3435
Johannes Berg77fdaa12009-07-07 03:45:17 +02003436 if (req->ie && req->ie_len) {
Johannes Berg66e67e42012-01-20 13:55:27 +01003437 memcpy(assoc_data->ie, req->ie, req->ie_len);
3438 assoc_data->ie_len = req->ie_len;
3439 }
Johannes Berg77fdaa12009-07-07 03:45:17 +02003440
Johannes Berg66e67e42012-01-20 13:55:27 +01003441 assoc_data->bss = req->bss;
Johannes Bergf679f652009-12-23 13:15:34 +01003442
Johannes Bergaf6b6372009-12-23 13:15:35 +01003443 if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
3444 if (ifmgd->powersave)
3445 ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
3446 else
3447 ifmgd->ap_smps = IEEE80211_SMPS_OFF;
3448 } else
3449 ifmgd->ap_smps = ifmgd->req_smps;
3450
Johannes Berg66e67e42012-01-20 13:55:27 +01003451 assoc_data->capability = req->bss->capability;
Johannes Berg32c50572012-03-28 11:04:29 +02003452 assoc_data->wmm = bss->wmm_used &&
3453 (local->hw.queues >= IEEE80211_NUM_ACS);
Johannes Berg66e67e42012-01-20 13:55:27 +01003454 assoc_data->supp_rates = bss->supp_rates;
3455 assoc_data->supp_rates_len = bss->supp_rates_len;
Johannes Berg9dde6422012-05-16 23:43:19 +02003456
3457 ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
3458 if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
3459 assoc_data->ap_ht_param =
3460 ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
3461 else
3462 ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
Johannes Berg63f170e2009-12-23 13:15:33 +01003463
Kalle Valoab133152010-01-12 10:42:31 +02003464 if (bss->wmm_used && bss->uapsd_supported &&
3465 (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
Johannes Berg76f03032012-03-08 15:02:05 +01003466 assoc_data->uapsd = true;
Kalle Valoab133152010-01-12 10:42:31 +02003467 ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
3468 } else {
Johannes Berg76f03032012-03-08 15:02:05 +01003469 assoc_data->uapsd = false;
Kalle Valoab133152010-01-12 10:42:31 +02003470 ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED;
3471 }
3472
Johannes Berg66e67e42012-01-20 13:55:27 +01003473 memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]);
3474 assoc_data->ssid_len = ssidie[1];
Johannes Berg63f170e2009-12-23 13:15:33 +01003475
Johannes Berg77fdaa12009-07-07 03:45:17 +02003476 if (req->prev_bssid)
Johannes Berg66e67e42012-01-20 13:55:27 +01003477 memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN);
Johannes Berg77fdaa12009-07-07 03:45:17 +02003478
3479 if (req->use_mfp) {
3480 ifmgd->mfp = IEEE80211_MFP_REQUIRED;
3481 ifmgd->flags |= IEEE80211_STA_MFP_ENABLED;
3482 } else {
3483 ifmgd->mfp = IEEE80211_MFP_DISABLED;
3484 ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED;
3485 }
3486
3487 if (req->crypto.control_port)
3488 ifmgd->flags |= IEEE80211_STA_CONTROL_PORT;
3489 else
3490 ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
3491
Johannes Berga621fa42010-08-27 14:26:54 +03003492 sdata->control_port_protocol = req->crypto.control_port_ethertype;
3493 sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
3494
Johannes Berg66e67e42012-01-20 13:55:27 +01003495 /* kick off associate process */
3496
3497 ifmgd->assoc_data = assoc_data;
3498
Johannes Berga1cf7752012-03-08 15:02:07 +01003499 err = ieee80211_prep_connection(sdata, req->bss, true);
3500 if (err)
3501 goto err_clear;
Johannes Berg66e67e42012-01-20 13:55:27 +01003502
3503 if (!bss->dtim_period &&
3504 sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
3505 /*
3506 * Wait up to one beacon interval ...
3507 * should this be more if we miss one?
3508 */
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003509 sdata_info(sdata, "waiting for beacon from %pM\n",
3510 ifmgd->bssid);
Johannes Berg3f9768a2012-03-28 21:02:46 +02003511 assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
Johannes Berg66e67e42012-01-20 13:55:27 +01003512 } else {
3513 assoc_data->have_beacon = true;
3514 assoc_data->sent_assoc = false;
3515 assoc_data->timeout = jiffies;
3516 }
3517 run_again(ifmgd, assoc_data->timeout);
3518
Paul Stewartfcff4f12012-02-23 17:59:53 -08003519 if (bss->corrupt_data) {
3520 char *corrupt_type = "data";
3521 if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) {
3522 if (bss->corrupt_data &
3523 IEEE80211_BSS_CORRUPT_PROBE_RESP)
3524 corrupt_type = "beacon and probe response";
3525 else
3526 corrupt_type = "beacon";
3527 } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
3528 corrupt_type = "probe response";
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003529 sdata_info(sdata, "associating with AP with corrupt %s\n",
3530 corrupt_type);
Paul Stewartfcff4f12012-02-23 17:59:53 -08003531 }
3532
Johannes Berg66e67e42012-01-20 13:55:27 +01003533 err = 0;
3534 goto out;
3535 err_clear:
Eliad Peller3d2abdf2012-09-04 17:44:45 +03003536 memset(ifmgd->bssid, 0, ETH_ALEN);
3537 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
Johannes Berg66e67e42012-01-20 13:55:27 +01003538 ifmgd->assoc_data = NULL;
3539 err_free:
3540 kfree(assoc_data);
3541 out:
3542 mutex_unlock(&ifmgd->mtx);
3543
3544 return err;
Johannes Berg77fdaa12009-07-07 03:45:17 +02003545}
3546
3547int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
Johannes Berg63c9c5e2012-02-24 13:50:51 +01003548 struct cfg80211_deauth_request *req)
Johannes Berg77fdaa12009-07-07 03:45:17 +02003549{
3550 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Antonio Quartulli6ae16772012-09-07 13:28:52 +02003551 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
Johannes Berg77fdaa12009-07-07 03:45:17 +02003552
Johannes Berg77fdaa12009-07-07 03:45:17 +02003553 mutex_lock(&ifmgd->mtx);
3554
Johannes Berg37ad3882012-02-24 13:50:54 +01003555 if (ifmgd->auth_data) {
Johannes Berg66e67e42012-01-20 13:55:27 +01003556 ieee80211_destroy_auth_data(sdata, false);
Johannes Bergaf6b6372009-12-23 13:15:35 +01003557 mutex_unlock(&ifmgd->mtx);
Johannes Berg66e67e42012-01-20 13:55:27 +01003558 return 0;
Johannes Bergaf6b6372009-12-23 13:15:35 +01003559 }
Johannes Berg77fdaa12009-07-07 03:45:17 +02003560
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003561 sdata_info(sdata,
3562 "deauthenticating from %pM by local choice (reason=%d)\n",
3563 req->bssid, req->reason_code);
Johannes Berg0ff71612009-09-26 14:45:41 +02003564
Johannes Berg37ad3882012-02-24 13:50:54 +01003565 if (ifmgd->associated &&
Emmanuel Grumbach8c7d8572012-07-25 01:42:36 +03003566 ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
Johannes Berg37ad3882012-02-24 13:50:54 +01003567 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
Johannes Berg5fef7db2012-02-24 13:50:52 +01003568 req->reason_code, true, frame_buf);
Emmanuel Grumbach8c7d8572012-07-25 01:42:36 +03003569 } else {
3570 drv_mgd_prepare_tx(sdata->local, sdata);
Johannes Berg37ad3882012-02-24 13:50:54 +01003571 ieee80211_send_deauth_disassoc(sdata, req->bssid,
3572 IEEE80211_STYPE_DEAUTH,
3573 req->reason_code, true,
3574 frame_buf);
Emmanuel Grumbach8c7d8572012-07-25 01:42:36 +03003575 }
3576
Johannes Berg37ad3882012-02-24 13:50:54 +01003577 mutex_unlock(&ifmgd->mtx);
3578
Antonio Quartulli6ae16772012-09-07 13:28:52 +02003579 __cfg80211_send_deauth(sdata->dev, frame_buf,
3580 IEEE80211_DEAUTH_FRAME_LEN);
Johannes Berg77fdaa12009-07-07 03:45:17 +02003581
Johannes Berg7da7cc12010-08-05 17:02:38 +02003582 mutex_lock(&sdata->local->mtx);
Johannes Bergbc83b682009-11-29 12:19:06 +01003583 ieee80211_recalc_idle(sdata->local);
Johannes Berg7da7cc12010-08-05 17:02:38 +02003584 mutex_unlock(&sdata->local->mtx);
Johannes Bergbc83b682009-11-29 12:19:06 +01003585
Johannes Berg77fdaa12009-07-07 03:45:17 +02003586 return 0;
3587}
3588
3589int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
Johannes Berg63c9c5e2012-02-24 13:50:51 +01003590 struct cfg80211_disassoc_request *req)
Johannes Berg77fdaa12009-07-07 03:45:17 +02003591{
3592 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Jouni Malinene69e95d2010-03-29 23:29:31 -07003593 u8 bssid[ETH_ALEN];
Antonio Quartulli6ae16772012-09-07 13:28:52 +02003594 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
Johannes Berg77fdaa12009-07-07 03:45:17 +02003595
Johannes Berg77fdaa12009-07-07 03:45:17 +02003596 mutex_lock(&ifmgd->mtx);
3597
Johannes Berg8d8b2612009-07-25 11:58:36 +02003598 /*
3599 * cfg80211 should catch this ... but it's racy since
3600 * we can receive a disassoc frame, process it, hand it
3601 * to cfg80211 while that's in a locked section already
3602 * trying to tell us that the user wants to disconnect.
3603 */
Johannes Berg0c1ad2c2009-12-23 13:15:39 +01003604 if (ifmgd->associated != req->bss) {
Johannes Berg77fdaa12009-07-07 03:45:17 +02003605 mutex_unlock(&ifmgd->mtx);
3606 return -ENOLINK;
3607 }
3608
Johannes Bergbdcbd8e2012-06-22 11:29:50 +02003609 sdata_info(sdata,
3610 "disassociating from %pM by local choice (reason=%d)\n",
3611 req->bss->bssid, req->reason_code);
Johannes Berg0ff71612009-09-26 14:45:41 +02003612
Jouni Malinene69e95d2010-03-29 23:29:31 -07003613 memcpy(bssid, req->bss->bssid, ETH_ALEN);
Johannes Berg37ad3882012-02-24 13:50:54 +01003614 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
3615 req->reason_code, !req->local_state_change,
3616 frame_buf);
Johannes Berg77fdaa12009-07-07 03:45:17 +02003617 mutex_unlock(&ifmgd->mtx);
3618
Antonio Quartulli6ae16772012-09-07 13:28:52 +02003619 __cfg80211_send_disassoc(sdata->dev, frame_buf,
3620 IEEE80211_DEAUTH_FRAME_LEN);
Johannes Bergbc83b682009-11-29 12:19:06 +01003621
Johannes Berg7da7cc12010-08-05 17:02:38 +02003622 mutex_lock(&sdata->local->mtx);
Johannes Bergbc83b682009-11-29 12:19:06 +01003623 ieee80211_recalc_idle(sdata->local);
Johannes Berg7da7cc12010-08-05 17:02:38 +02003624 mutex_unlock(&sdata->local->mtx);
Johannes Bergbc83b682009-11-29 12:19:06 +01003625
Johannes Berg77fdaa12009-07-07 03:45:17 +02003626 return 0;
3627}
Jouni Malinen026331c2010-02-15 12:53:10 +02003628
Eliad Pellerafa762f2012-04-23 14:45:15 +03003629void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
Johannes Berg54e4ffb2012-02-25 21:48:08 +01003630{
3631 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3632
3633 mutex_lock(&ifmgd->mtx);
3634 if (ifmgd->assoc_data)
3635 ieee80211_destroy_assoc_data(sdata, false);
3636 if (ifmgd->auth_data)
3637 ieee80211_destroy_auth_data(sdata, false);
3638 del_timer_sync(&ifmgd->timer);
3639 mutex_unlock(&ifmgd->mtx);
3640}
3641
Juuso Oikarinena97c13c2010-03-23 09:02:34 +02003642void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
3643 enum nl80211_cqm_rssi_threshold_event rssi_event,
3644 gfp_t gfp)
3645{
3646 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
3647
Johannes Bergb5878a22010-04-07 16:48:40 +02003648 trace_api_cqm_rssi_notify(sdata, rssi_event);
3649
Juuso Oikarinena97c13c2010-03-23 09:02:34 +02003650 cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
3651}
3652EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);