diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 1030 |
1 files changed, 500 insertions, 530 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d889e2a89e4b..67c38235a3c5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -26,9 +26,8 @@ | |||
26 | #include <linux/etherdevice.h> | 26 | #include <linux/etherdevice.h> |
27 | #include <linux/rtnetlink.h> | 27 | #include <linux/rtnetlink.h> |
28 | #include <net/iw_handler.h> | 28 | #include <net/iw_handler.h> |
29 | #include <asm/types.h> | ||
30 | |||
31 | #include <net/mac80211.h> | 29 | #include <net/mac80211.h> |
30 | |||
32 | #include "ieee80211_i.h" | 31 | #include "ieee80211_i.h" |
33 | #include "rate.h" | 32 | #include "rate.h" |
34 | #include "led.h" | 33 | #include "led.h" |
@@ -58,8 +57,6 @@ | |||
58 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 57 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
59 | 58 | ||
60 | 59 | ||
61 | #define ERP_INFO_USE_PROTECTION BIT(1) | ||
62 | |||
63 | /* mgmt header + 1 byte category code */ | 60 | /* mgmt header + 1 byte category code */ |
64 | #define IEEE80211_MIN_ACTION_SIZE (24 + 1) | 61 | #define IEEE80211_MIN_ACTION_SIZE (24 + 1) |
65 | 62 | ||
@@ -74,24 +71,199 @@ | |||
74 | #define IEEE80211_MIN_AMPDU_BUF 0x8 | 71 | #define IEEE80211_MIN_AMPDU_BUF 0x8 |
75 | #define IEEE80211_MAX_AMPDU_BUF 0x40 | 72 | #define IEEE80211_MAX_AMPDU_BUF 0x40 |
76 | 73 | ||
77 | static void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 74 | /* BSS handling */ |
78 | u8 *ssid, size_t ssid_len); | ||
79 | static struct ieee80211_sta_bss * | 75 | static struct ieee80211_sta_bss * |
80 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | 76 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, |
81 | u8 *ssid, u8 ssid_len); | 77 | u8 *ssid, u8 ssid_len) |
78 | { | ||
79 | struct ieee80211_sta_bss *bss; | ||
80 | |||
81 | spin_lock_bh(&local->sta_bss_lock); | ||
82 | bss = local->sta_bss_hash[STA_HASH(bssid)]; | ||
83 | while (bss) { | ||
84 | if (!bss_mesh_cfg(bss) && | ||
85 | !memcmp(bss->bssid, bssid, ETH_ALEN) && | ||
86 | bss->freq == freq && | ||
87 | bss->ssid_len == ssid_len && | ||
88 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { | ||
89 | atomic_inc(&bss->users); | ||
90 | break; | ||
91 | } | ||
92 | bss = bss->hnext; | ||
93 | } | ||
94 | spin_unlock_bh(&local->sta_bss_lock); | ||
95 | return bss; | ||
96 | } | ||
97 | |||
98 | /* Caller must hold local->sta_bss_lock */ | ||
99 | static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local, | ||
100 | struct ieee80211_sta_bss *bss) | ||
101 | { | ||
102 | u8 hash_idx; | ||
103 | |||
104 | if (bss_mesh_cfg(bss)) | ||
105 | hash_idx = mesh_id_hash(bss_mesh_id(bss), | ||
106 | bss_mesh_id_len(bss)); | ||
107 | else | ||
108 | hash_idx = STA_HASH(bss->bssid); | ||
109 | |||
110 | bss->hnext = local->sta_bss_hash[hash_idx]; | ||
111 | local->sta_bss_hash[hash_idx] = bss; | ||
112 | } | ||
113 | |||
114 | /* Caller must hold local->sta_bss_lock */ | ||
115 | static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local, | ||
116 | struct ieee80211_sta_bss *bss) | ||
117 | { | ||
118 | struct ieee80211_sta_bss *b, *prev = NULL; | ||
119 | b = local->sta_bss_hash[STA_HASH(bss->bssid)]; | ||
120 | while (b) { | ||
121 | if (b == bss) { | ||
122 | if (!prev) | ||
123 | local->sta_bss_hash[STA_HASH(bss->bssid)] = | ||
124 | bss->hnext; | ||
125 | else | ||
126 | prev->hnext = bss->hnext; | ||
127 | break; | ||
128 | } | ||
129 | prev = b; | ||
130 | b = b->hnext; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static struct ieee80211_sta_bss * | ||
135 | ieee80211_rx_bss_add(struct ieee80211_sub_if_data *sdata, u8 *bssid, int freq, | ||
136 | u8 *ssid, u8 ssid_len) | ||
137 | { | ||
138 | struct ieee80211_local *local = sdata->local; | ||
139 | struct ieee80211_sta_bss *bss; | ||
140 | |||
141 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
142 | if (!bss) | ||
143 | return NULL; | ||
144 | atomic_inc(&bss->users); | ||
145 | atomic_inc(&bss->users); | ||
146 | memcpy(bss->bssid, bssid, ETH_ALEN); | ||
147 | bss->freq = freq; | ||
148 | if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { | ||
149 | memcpy(bss->ssid, ssid, ssid_len); | ||
150 | bss->ssid_len = ssid_len; | ||
151 | } | ||
152 | |||
153 | spin_lock_bh(&local->sta_bss_lock); | ||
154 | /* TODO: order by RSSI? */ | ||
155 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
156 | __ieee80211_rx_bss_hash_add(local, bss); | ||
157 | spin_unlock_bh(&local->sta_bss_lock); | ||
158 | return bss; | ||
159 | } | ||
160 | |||
161 | #ifdef CONFIG_MAC80211_MESH | ||
162 | static struct ieee80211_sta_bss * | ||
163 | ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
164 | u8 *mesh_cfg, int freq) | ||
165 | { | ||
166 | struct ieee80211_sta_bss *bss; | ||
167 | |||
168 | spin_lock_bh(&local->sta_bss_lock); | ||
169 | bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; | ||
170 | while (bss) { | ||
171 | if (bss_mesh_cfg(bss) && | ||
172 | !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && | ||
173 | bss->freq == freq && | ||
174 | mesh_id_len == bss->mesh_id_len && | ||
175 | (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, | ||
176 | mesh_id_len))) { | ||
177 | atomic_inc(&bss->users); | ||
178 | break; | ||
179 | } | ||
180 | bss = bss->hnext; | ||
181 | } | ||
182 | spin_unlock_bh(&local->sta_bss_lock); | ||
183 | return bss; | ||
184 | } | ||
185 | |||
186 | static struct ieee80211_sta_bss * | ||
187 | ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
188 | u8 *mesh_cfg, int mesh_config_len, int freq) | ||
189 | { | ||
190 | struct ieee80211_sta_bss *bss; | ||
191 | |||
192 | if (mesh_config_len != MESH_CFG_LEN) | ||
193 | return NULL; | ||
194 | |||
195 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
196 | if (!bss) | ||
197 | return NULL; | ||
198 | |||
199 | bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); | ||
200 | if (!bss->mesh_cfg) { | ||
201 | kfree(bss); | ||
202 | return NULL; | ||
203 | } | ||
204 | |||
205 | if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { | ||
206 | bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); | ||
207 | if (!bss->mesh_id) { | ||
208 | kfree(bss->mesh_cfg); | ||
209 | kfree(bss); | ||
210 | return NULL; | ||
211 | } | ||
212 | memcpy(bss->mesh_id, mesh_id, mesh_id_len); | ||
213 | } | ||
214 | |||
215 | atomic_inc(&bss->users); | ||
216 | atomic_inc(&bss->users); | ||
217 | memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); | ||
218 | bss->mesh_id_len = mesh_id_len; | ||
219 | bss->freq = freq; | ||
220 | spin_lock_bh(&local->sta_bss_lock); | ||
221 | /* TODO: order by RSSI? */ | ||
222 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
223 | __ieee80211_rx_bss_hash_add(local, bss); | ||
224 | spin_unlock_bh(&local->sta_bss_lock); | ||
225 | return bss; | ||
226 | } | ||
227 | #endif | ||
228 | |||
229 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | ||
230 | { | ||
231 | kfree(bss->ies); | ||
232 | kfree(bss_mesh_id(bss)); | ||
233 | kfree(bss_mesh_cfg(bss)); | ||
234 | kfree(bss); | ||
235 | } | ||
236 | |||
82 | static void ieee80211_rx_bss_put(struct ieee80211_local *local, | 237 | static void ieee80211_rx_bss_put(struct ieee80211_local *local, |
83 | struct ieee80211_sta_bss *bss); | 238 | struct ieee80211_sta_bss *bss) |
84 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | 239 | { |
85 | struct ieee80211_if_sta *ifsta); | 240 | local_bh_disable(); |
86 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata); | 241 | if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { |
87 | static int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *sdata, | 242 | local_bh_enable(); |
88 | u8 *ssid, size_t ssid_len); | 243 | return; |
89 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | 244 | } |
90 | struct ieee80211_if_sta *ifsta); | 245 | |
91 | static void sta_rx_agg_session_timer_expired(unsigned long data); | 246 | __ieee80211_rx_bss_hash_del(local, bss); |
247 | list_del(&bss->list); | ||
248 | spin_unlock_bh(&local->sta_bss_lock); | ||
249 | ieee80211_rx_bss_free(bss); | ||
250 | } | ||
92 | 251 | ||
252 | void ieee80211_rx_bss_list_init(struct ieee80211_local *local) | ||
253 | { | ||
254 | spin_lock_init(&local->sta_bss_lock); | ||
255 | INIT_LIST_HEAD(&local->sta_bss_list); | ||
256 | } | ||
93 | 257 | ||
94 | static u8 * ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie) | 258 | void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local) |
259 | { | ||
260 | struct ieee80211_sta_bss *bss, *tmp; | ||
261 | |||
262 | list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) | ||
263 | ieee80211_rx_bss_put(local, bss); | ||
264 | } | ||
265 | |||
266 | static u8 *ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie) | ||
95 | { | 267 | { |
96 | u8 *end, *pos; | 268 | u8 *end, *pos; |
97 | 269 | ||
@@ -111,13 +283,125 @@ static u8 * ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie) | |||
111 | return NULL; | 283 | return NULL; |
112 | } | 284 | } |
113 | 285 | ||
114 | 286 | /* utils */ | |
115 | static int ecw2cw(int ecw) | 287 | static int ecw2cw(int ecw) |
116 | { | 288 | { |
117 | return (1 << ecw) - 1; | 289 | return (1 << ecw) - 1; |
118 | } | 290 | } |
119 | 291 | ||
292 | /* frame sending functions */ | ||
293 | void ieee80211_sta_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
294 | int encrypt) | ||
295 | { | ||
296 | skb->dev = sdata->local->mdev; | ||
297 | skb_set_mac_header(skb, 0); | ||
298 | skb_set_network_header(skb, 0); | ||
299 | skb_set_transport_header(skb, 0); | ||
300 | |||
301 | skb->iif = sdata->dev->ifindex; | ||
302 | skb->do_not_encrypt = !encrypt; | ||
303 | |||
304 | dev_queue_xmit(skb); | ||
305 | } | ||
306 | |||
307 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
308 | struct ieee80211_if_sta *ifsta, | ||
309 | int transaction, u8 *extra, size_t extra_len, | ||
310 | int encrypt) | ||
311 | { | ||
312 | struct ieee80211_local *local = sdata->local; | ||
313 | struct sk_buff *skb; | ||
314 | struct ieee80211_mgmt *mgmt; | ||
120 | 315 | ||
316 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
317 | sizeof(*mgmt) + 6 + extra_len); | ||
318 | if (!skb) { | ||
319 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
320 | "frame\n", sdata->dev->name); | ||
321 | return; | ||
322 | } | ||
323 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
324 | |||
325 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
326 | memset(mgmt, 0, 24 + 6); | ||
327 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
328 | IEEE80211_STYPE_AUTH); | ||
329 | if (encrypt) | ||
330 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
331 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
332 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
333 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
334 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | ||
335 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
336 | ifsta->auth_transaction = transaction + 1; | ||
337 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
338 | if (extra) | ||
339 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
340 | |||
341 | ieee80211_sta_tx(sdata, skb, encrypt); | ||
342 | } | ||
343 | |||
344 | static void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
345 | u8 *ssid, size_t ssid_len) | ||
346 | { | ||
347 | struct ieee80211_local *local = sdata->local; | ||
348 | struct ieee80211_supported_band *sband; | ||
349 | struct sk_buff *skb; | ||
350 | struct ieee80211_mgmt *mgmt; | ||
351 | u8 *pos, *supp_rates, *esupp_rates = NULL; | ||
352 | int i; | ||
353 | |||
354 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); | ||
355 | if (!skb) { | ||
356 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
357 | "request\n", sdata->dev->name); | ||
358 | return; | ||
359 | } | ||
360 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
361 | |||
362 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
363 | memset(mgmt, 0, 24); | ||
364 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
365 | IEEE80211_STYPE_PROBE_REQ); | ||
366 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
367 | if (dst) { | ||
368 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
369 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
370 | } else { | ||
371 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
372 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
373 | } | ||
374 | pos = skb_put(skb, 2 + ssid_len); | ||
375 | *pos++ = WLAN_EID_SSID; | ||
376 | *pos++ = ssid_len; | ||
377 | memcpy(pos, ssid, ssid_len); | ||
378 | |||
379 | supp_rates = skb_put(skb, 2); | ||
380 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
381 | supp_rates[1] = 0; | ||
382 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
383 | |||
384 | for (i = 0; i < sband->n_bitrates; i++) { | ||
385 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
386 | if (esupp_rates) { | ||
387 | pos = skb_put(skb, 1); | ||
388 | esupp_rates[1]++; | ||
389 | } else if (supp_rates[1] == 8) { | ||
390 | esupp_rates = skb_put(skb, 3); | ||
391 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
392 | esupp_rates[1] = 1; | ||
393 | pos = &esupp_rates[2]; | ||
394 | } else { | ||
395 | pos = skb_put(skb, 1); | ||
396 | supp_rates[1]++; | ||
397 | } | ||
398 | *pos = rate->bitrate / 5; | ||
399 | } | ||
400 | |||
401 | ieee80211_sta_tx(sdata, skb, 0); | ||
402 | } | ||
403 | |||
404 | /* MLME */ | ||
121 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 405 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
122 | struct ieee80211_sta_bss *bss, | 406 | struct ieee80211_sta_bss *bss, |
123 | int ibss) | 407 | int ibss) |
@@ -434,58 +718,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
434 | ieee80211_sta_send_apinfo(sdata, ifsta); | 718 | ieee80211_sta_send_apinfo(sdata, ifsta); |
435 | } | 719 | } |
436 | 720 | ||
437 | void ieee80211_sta_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
438 | int encrypt) | ||
439 | { | ||
440 | skb->dev = sdata->local->mdev; | ||
441 | skb_set_mac_header(skb, 0); | ||
442 | skb_set_network_header(skb, 0); | ||
443 | skb_set_transport_header(skb, 0); | ||
444 | |||
445 | skb->iif = sdata->dev->ifindex; | ||
446 | skb->do_not_encrypt = !encrypt; | ||
447 | |||
448 | dev_queue_xmit(skb); | ||
449 | } | ||
450 | |||
451 | |||
452 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
453 | struct ieee80211_if_sta *ifsta, | ||
454 | int transaction, u8 *extra, size_t extra_len, | ||
455 | int encrypt) | ||
456 | { | ||
457 | struct ieee80211_local *local = sdata->local; | ||
458 | struct sk_buff *skb; | ||
459 | struct ieee80211_mgmt *mgmt; | ||
460 | |||
461 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
462 | sizeof(*mgmt) + 6 + extra_len); | ||
463 | if (!skb) { | ||
464 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
465 | "frame\n", sdata->dev->name); | ||
466 | return; | ||
467 | } | ||
468 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
469 | |||
470 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
471 | memset(mgmt, 0, 24 + 6); | ||
472 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
473 | IEEE80211_STYPE_AUTH); | ||
474 | if (encrypt) | ||
475 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
476 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
477 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
478 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
479 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | ||
480 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
481 | ifsta->auth_transaction = transaction + 1; | ||
482 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
483 | if (extra) | ||
484 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
485 | |||
486 | ieee80211_sta_tx(sdata, skb, encrypt); | ||
487 | } | ||
488 | |||
489 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | 721 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, |
490 | struct ieee80211_if_sta *ifsta) | 722 | struct ieee80211_if_sta *ifsta) |
491 | { | 723 | { |
@@ -798,6 +1030,13 @@ static void ieee80211_send_deauth(struct ieee80211_sub_if_data *sdata, | |||
798 | ieee80211_sta_tx(sdata, skb, 0); | 1030 | ieee80211_sta_tx(sdata, skb, 0); |
799 | } | 1031 | } |
800 | 1032 | ||
1033 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | ||
1034 | { | ||
1035 | if (!sdata || !sdata->default_key || | ||
1036 | sdata->default_key->conf.alg != ALG_WEP) | ||
1037 | return 0; | ||
1038 | return 1; | ||
1039 | } | ||
801 | 1040 | ||
802 | static void ieee80211_send_disassoc(struct ieee80211_sub_if_data *sdata, | 1041 | static void ieee80211_send_disassoc(struct ieee80211_sub_if_data *sdata, |
803 | struct ieee80211_if_sta *ifsta, u16 reason) | 1042 | struct ieee80211_if_sta *ifsta, u16 reason) |
@@ -917,7 +1156,6 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | |||
917 | return 1; | 1156 | return 1; |
918 | } | 1157 | } |
919 | 1158 | ||
920 | |||
921 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, | 1159 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, |
922 | struct ieee80211_if_sta *ifsta) | 1160 | struct ieee80211_if_sta *ifsta) |
923 | { | 1161 | { |
@@ -1008,76 +1246,6 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1008 | } | 1246 | } |
1009 | 1247 | ||
1010 | 1248 | ||
1011 | static void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
1012 | u8 *ssid, size_t ssid_len) | ||
1013 | { | ||
1014 | struct ieee80211_local *local = sdata->local; | ||
1015 | struct ieee80211_supported_band *sband; | ||
1016 | struct sk_buff *skb; | ||
1017 | struct ieee80211_mgmt *mgmt; | ||
1018 | u8 *pos, *supp_rates, *esupp_rates = NULL; | ||
1019 | int i; | ||
1020 | |||
1021 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); | ||
1022 | if (!skb) { | ||
1023 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
1024 | "request\n", sdata->dev->name); | ||
1025 | return; | ||
1026 | } | ||
1027 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1028 | |||
1029 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
1030 | memset(mgmt, 0, 24); | ||
1031 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1032 | IEEE80211_STYPE_PROBE_REQ); | ||
1033 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1034 | if (dst) { | ||
1035 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
1036 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
1037 | } else { | ||
1038 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1039 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
1040 | } | ||
1041 | pos = skb_put(skb, 2 + ssid_len); | ||
1042 | *pos++ = WLAN_EID_SSID; | ||
1043 | *pos++ = ssid_len; | ||
1044 | memcpy(pos, ssid, ssid_len); | ||
1045 | |||
1046 | supp_rates = skb_put(skb, 2); | ||
1047 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
1048 | supp_rates[1] = 0; | ||
1049 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1050 | |||
1051 | for (i = 0; i < sband->n_bitrates; i++) { | ||
1052 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
1053 | if (esupp_rates) { | ||
1054 | pos = skb_put(skb, 1); | ||
1055 | esupp_rates[1]++; | ||
1056 | } else if (supp_rates[1] == 8) { | ||
1057 | esupp_rates = skb_put(skb, 3); | ||
1058 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
1059 | esupp_rates[1] = 1; | ||
1060 | pos = &esupp_rates[2]; | ||
1061 | } else { | ||
1062 | pos = skb_put(skb, 1); | ||
1063 | supp_rates[1]++; | ||
1064 | } | ||
1065 | *pos = rate->bitrate / 5; | ||
1066 | } | ||
1067 | |||
1068 | ieee80211_sta_tx(sdata, skb, 0); | ||
1069 | } | ||
1070 | |||
1071 | |||
1072 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | ||
1073 | { | ||
1074 | if (!sdata || !sdata->default_key || | ||
1075 | sdata->default_key->conf.alg != ALG_WEP) | ||
1076 | return 0; | ||
1077 | return 1; | ||
1078 | } | ||
1079 | |||
1080 | |||
1081 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | 1249 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, |
1082 | struct ieee80211_if_sta *ifsta) | 1250 | struct ieee80211_if_sta *ifsta) |
1083 | { | 1251 | { |
@@ -1200,6 +1368,30 @@ void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, const u8 | |||
1200 | ieee80211_sta_tx(sdata, skb, 0); | 1368 | ieee80211_sta_tx(sdata, skb, 0); |
1201 | } | 1369 | } |
1202 | 1370 | ||
1371 | /* | ||
1372 | * After accepting the AddBA Request we activated a timer, | ||
1373 | * resetting it after each frame that arrives from the originator. | ||
1374 | * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. | ||
1375 | */ | ||
1376 | static void sta_rx_agg_session_timer_expired(unsigned long data) | ||
1377 | { | ||
1378 | /* not an elegant detour, but there is no choice as the timer passes | ||
1379 | * only one argument, and various sta_info are needed here, so init | ||
1380 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
1381 | * array gives the sta through container_of */ | ||
1382 | u8 *ptid = (u8 *)data; | ||
1383 | u8 *timer_to_id = ptid - *ptid; | ||
1384 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | ||
1385 | timer_to_tid[0]); | ||
1386 | |||
1387 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1388 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | ||
1389 | #endif | ||
1390 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->addr, | ||
1391 | (u16)*ptid, WLAN_BACK_TIMER, | ||
1392 | WLAN_REASON_QSTA_TIMEOUT); | ||
1393 | } | ||
1394 | |||
1203 | static void ieee80211_sta_process_addba_request(struct ieee80211_local *local, | 1395 | static void ieee80211_sta_process_addba_request(struct ieee80211_local *local, |
1204 | struct ieee80211_mgmt *mgmt, | 1396 | struct ieee80211_mgmt *mgmt, |
1205 | size_t len) | 1397 | size_t len) |
@@ -1646,30 +1838,6 @@ timer_expired_exit: | |||
1646 | rcu_read_unlock(); | 1838 | rcu_read_unlock(); |
1647 | } | 1839 | } |
1648 | 1840 | ||
1649 | /* | ||
1650 | * After accepting the AddBA Request we activated a timer, | ||
1651 | * resetting it after each frame that arrives from the originator. | ||
1652 | * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. | ||
1653 | */ | ||
1654 | static void sta_rx_agg_session_timer_expired(unsigned long data) | ||
1655 | { | ||
1656 | /* not an elegant detour, but there is no choice as the timer passes | ||
1657 | * only one argument, and various sta_info are needed here, so init | ||
1658 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
1659 | * array gives the sta through container_of */ | ||
1660 | u8 *ptid = (u8 *)data; | ||
1661 | u8 *timer_to_id = ptid - *ptid; | ||
1662 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | ||
1663 | timer_to_tid[0]); | ||
1664 | |||
1665 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1666 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | ||
1667 | #endif | ||
1668 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->addr, | ||
1669 | (u16)*ptid, WLAN_BACK_TIMER, | ||
1670 | WLAN_REASON_QSTA_TIMEOUT); | ||
1671 | } | ||
1672 | |||
1673 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr) | 1841 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr) |
1674 | { | 1842 | { |
1675 | struct ieee80211_local *local = sdata->local; | 1843 | struct ieee80211_local *local = sdata->local; |
@@ -2099,203 +2267,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2099 | } | 2267 | } |
2100 | 2268 | ||
2101 | 2269 | ||
2102 | /* Caller must hold local->sta_bss_lock */ | ||
2103 | static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local, | ||
2104 | struct ieee80211_sta_bss *bss) | ||
2105 | { | ||
2106 | u8 hash_idx; | ||
2107 | |||
2108 | if (bss_mesh_cfg(bss)) | ||
2109 | hash_idx = mesh_id_hash(bss_mesh_id(bss), | ||
2110 | bss_mesh_id_len(bss)); | ||
2111 | else | ||
2112 | hash_idx = STA_HASH(bss->bssid); | ||
2113 | |||
2114 | bss->hnext = local->sta_bss_hash[hash_idx]; | ||
2115 | local->sta_bss_hash[hash_idx] = bss; | ||
2116 | } | ||
2117 | |||
2118 | |||
2119 | /* Caller must hold local->sta_bss_lock */ | ||
2120 | static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local, | ||
2121 | struct ieee80211_sta_bss *bss) | ||
2122 | { | ||
2123 | struct ieee80211_sta_bss *b, *prev = NULL; | ||
2124 | b = local->sta_bss_hash[STA_HASH(bss->bssid)]; | ||
2125 | while (b) { | ||
2126 | if (b == bss) { | ||
2127 | if (!prev) | ||
2128 | local->sta_bss_hash[STA_HASH(bss->bssid)] = | ||
2129 | bss->hnext; | ||
2130 | else | ||
2131 | prev->hnext = bss->hnext; | ||
2132 | break; | ||
2133 | } | ||
2134 | prev = b; | ||
2135 | b = b->hnext; | ||
2136 | } | ||
2137 | } | ||
2138 | |||
2139 | |||
2140 | static struct ieee80211_sta_bss * | ||
2141 | ieee80211_rx_bss_add(struct ieee80211_sub_if_data *sdata, u8 *bssid, int freq, | ||
2142 | u8 *ssid, u8 ssid_len) | ||
2143 | { | ||
2144 | struct ieee80211_local *local = sdata->local; | ||
2145 | struct ieee80211_sta_bss *bss; | ||
2146 | |||
2147 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
2148 | if (!bss) | ||
2149 | return NULL; | ||
2150 | atomic_inc(&bss->users); | ||
2151 | atomic_inc(&bss->users); | ||
2152 | memcpy(bss->bssid, bssid, ETH_ALEN); | ||
2153 | bss->freq = freq; | ||
2154 | if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { | ||
2155 | memcpy(bss->ssid, ssid, ssid_len); | ||
2156 | bss->ssid_len = ssid_len; | ||
2157 | } | ||
2158 | |||
2159 | spin_lock_bh(&local->sta_bss_lock); | ||
2160 | /* TODO: order by RSSI? */ | ||
2161 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
2162 | __ieee80211_rx_bss_hash_add(local, bss); | ||
2163 | spin_unlock_bh(&local->sta_bss_lock); | ||
2164 | return bss; | ||
2165 | } | ||
2166 | |||
2167 | static struct ieee80211_sta_bss * | ||
2168 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | ||
2169 | u8 *ssid, u8 ssid_len) | ||
2170 | { | ||
2171 | struct ieee80211_sta_bss *bss; | ||
2172 | |||
2173 | spin_lock_bh(&local->sta_bss_lock); | ||
2174 | bss = local->sta_bss_hash[STA_HASH(bssid)]; | ||
2175 | while (bss) { | ||
2176 | if (!bss_mesh_cfg(bss) && | ||
2177 | !memcmp(bss->bssid, bssid, ETH_ALEN) && | ||
2178 | bss->freq == freq && | ||
2179 | bss->ssid_len == ssid_len && | ||
2180 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { | ||
2181 | atomic_inc(&bss->users); | ||
2182 | break; | ||
2183 | } | ||
2184 | bss = bss->hnext; | ||
2185 | } | ||
2186 | spin_unlock_bh(&local->sta_bss_lock); | ||
2187 | return bss; | ||
2188 | } | ||
2189 | |||
2190 | #ifdef CONFIG_MAC80211_MESH | ||
2191 | static struct ieee80211_sta_bss * | ||
2192 | ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
2193 | u8 *mesh_cfg, int freq) | ||
2194 | { | ||
2195 | struct ieee80211_sta_bss *bss; | ||
2196 | |||
2197 | spin_lock_bh(&local->sta_bss_lock); | ||
2198 | bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; | ||
2199 | while (bss) { | ||
2200 | if (bss_mesh_cfg(bss) && | ||
2201 | !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && | ||
2202 | bss->freq == freq && | ||
2203 | mesh_id_len == bss->mesh_id_len && | ||
2204 | (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, | ||
2205 | mesh_id_len))) { | ||
2206 | atomic_inc(&bss->users); | ||
2207 | break; | ||
2208 | } | ||
2209 | bss = bss->hnext; | ||
2210 | } | ||
2211 | spin_unlock_bh(&local->sta_bss_lock); | ||
2212 | return bss; | ||
2213 | } | ||
2214 | |||
2215 | static struct ieee80211_sta_bss * | ||
2216 | ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
2217 | u8 *mesh_cfg, int mesh_config_len, int freq) | ||
2218 | { | ||
2219 | struct ieee80211_sta_bss *bss; | ||
2220 | |||
2221 | if (mesh_config_len != MESH_CFG_LEN) | ||
2222 | return NULL; | ||
2223 | |||
2224 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
2225 | if (!bss) | ||
2226 | return NULL; | ||
2227 | |||
2228 | bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); | ||
2229 | if (!bss->mesh_cfg) { | ||
2230 | kfree(bss); | ||
2231 | return NULL; | ||
2232 | } | ||
2233 | |||
2234 | if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { | ||
2235 | bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); | ||
2236 | if (!bss->mesh_id) { | ||
2237 | kfree(bss->mesh_cfg); | ||
2238 | kfree(bss); | ||
2239 | return NULL; | ||
2240 | } | ||
2241 | memcpy(bss->mesh_id, mesh_id, mesh_id_len); | ||
2242 | } | ||
2243 | |||
2244 | atomic_inc(&bss->users); | ||
2245 | atomic_inc(&bss->users); | ||
2246 | memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); | ||
2247 | bss->mesh_id_len = mesh_id_len; | ||
2248 | bss->freq = freq; | ||
2249 | spin_lock_bh(&local->sta_bss_lock); | ||
2250 | /* TODO: order by RSSI? */ | ||
2251 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
2252 | __ieee80211_rx_bss_hash_add(local, bss); | ||
2253 | spin_unlock_bh(&local->sta_bss_lock); | ||
2254 | return bss; | ||
2255 | } | ||
2256 | #endif | ||
2257 | |||
2258 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | ||
2259 | { | ||
2260 | kfree(bss->ies); | ||
2261 | kfree(bss_mesh_id(bss)); | ||
2262 | kfree(bss_mesh_cfg(bss)); | ||
2263 | kfree(bss); | ||
2264 | } | ||
2265 | |||
2266 | |||
2267 | static void ieee80211_rx_bss_put(struct ieee80211_local *local, | ||
2268 | struct ieee80211_sta_bss *bss) | ||
2269 | { | ||
2270 | local_bh_disable(); | ||
2271 | if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { | ||
2272 | local_bh_enable(); | ||
2273 | return; | ||
2274 | } | ||
2275 | |||
2276 | __ieee80211_rx_bss_hash_del(local, bss); | ||
2277 | list_del(&bss->list); | ||
2278 | spin_unlock_bh(&local->sta_bss_lock); | ||
2279 | ieee80211_rx_bss_free(bss); | ||
2280 | } | ||
2281 | |||
2282 | |||
2283 | void ieee80211_rx_bss_list_init(struct ieee80211_local *local) | ||
2284 | { | ||
2285 | spin_lock_init(&local->sta_bss_lock); | ||
2286 | INIT_LIST_HEAD(&local->sta_bss_list); | ||
2287 | } | ||
2288 | |||
2289 | |||
2290 | void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local) | ||
2291 | { | ||
2292 | struct ieee80211_sta_bss *bss, *tmp; | ||
2293 | |||
2294 | list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) | ||
2295 | ieee80211_rx_bss_put(local, bss); | ||
2296 | } | ||
2297 | |||
2298 | |||
2299 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 2270 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
2300 | struct ieee80211_if_sta *ifsta, | 2271 | struct ieee80211_if_sta *ifsta, |
2301 | struct ieee80211_sta_bss *bss) | 2272 | struct ieee80211_sta_bss *bss) |
@@ -3154,95 +3125,6 @@ void ieee80211_sta_timer(unsigned long data) | |||
3154 | queue_work(local->hw.workqueue, &ifsta->work); | 3125 | queue_work(local->hw.workqueue, &ifsta->work); |
3155 | } | 3126 | } |
3156 | 3127 | ||
3157 | void ieee80211_sta_work(struct work_struct *work) | ||
3158 | { | ||
3159 | struct ieee80211_sub_if_data *sdata = | ||
3160 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | ||
3161 | struct ieee80211_local *local = sdata->local; | ||
3162 | struct ieee80211_if_sta *ifsta; | ||
3163 | struct sk_buff *skb; | ||
3164 | |||
3165 | if (!netif_running(sdata->dev)) | ||
3166 | return; | ||
3167 | |||
3168 | if (local->sta_sw_scanning || local->sta_hw_scanning) | ||
3169 | return; | ||
3170 | |||
3171 | if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA && | ||
3172 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | ||
3173 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) | ||
3174 | return; | ||
3175 | ifsta = &sdata->u.sta; | ||
3176 | |||
3177 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | ||
3178 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | ||
3179 | |||
3180 | #ifdef CONFIG_MAC80211_MESH | ||
3181 | if (ifsta->preq_queue_len && | ||
3182 | time_after(jiffies, | ||
3183 | ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) | ||
3184 | mesh_path_start_discovery(sdata); | ||
3185 | #endif | ||
3186 | |||
3187 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && | ||
3188 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | ||
3189 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | ||
3190 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | ||
3191 | if (ifsta->scan_ssid_len) | ||
3192 | ieee80211_sta_start_scan(sdata, ifsta->scan_ssid, ifsta->scan_ssid_len); | ||
3193 | else | ||
3194 | ieee80211_sta_start_scan(sdata, NULL, 0); | ||
3195 | return; | ||
3196 | } | ||
3197 | |||
3198 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { | ||
3199 | if (ieee80211_sta_config_auth(sdata, ifsta)) | ||
3200 | return; | ||
3201 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | ||
3202 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) | ||
3203 | return; | ||
3204 | |||
3205 | switch (ifsta->state) { | ||
3206 | case IEEE80211_STA_MLME_DISABLED: | ||
3207 | break; | ||
3208 | case IEEE80211_STA_MLME_DIRECT_PROBE: | ||
3209 | ieee80211_direct_probe(sdata, ifsta); | ||
3210 | break; | ||
3211 | case IEEE80211_STA_MLME_AUTHENTICATE: | ||
3212 | ieee80211_authenticate(sdata, ifsta); | ||
3213 | break; | ||
3214 | case IEEE80211_STA_MLME_ASSOCIATE: | ||
3215 | ieee80211_associate(sdata, ifsta); | ||
3216 | break; | ||
3217 | case IEEE80211_STA_MLME_ASSOCIATED: | ||
3218 | ieee80211_associated(sdata, ifsta); | ||
3219 | break; | ||
3220 | case IEEE80211_STA_MLME_IBSS_SEARCH: | ||
3221 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
3222 | break; | ||
3223 | case IEEE80211_STA_MLME_IBSS_JOINED: | ||
3224 | ieee80211_sta_merge_ibss(sdata, ifsta); | ||
3225 | break; | ||
3226 | #ifdef CONFIG_MAC80211_MESH | ||
3227 | case IEEE80211_STA_MLME_MESH_UP: | ||
3228 | ieee80211_mesh_housekeeping(sdata, ifsta); | ||
3229 | break; | ||
3230 | #endif | ||
3231 | default: | ||
3232 | WARN_ON(1); | ||
3233 | break; | ||
3234 | } | ||
3235 | |||
3236 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | ||
3237 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " | ||
3238 | "mixed-cell disabled - disassociate\n", sdata->dev->name); | ||
3239 | |||
3240 | ieee80211_set_disassoc(sdata, ifsta, false, true, | ||
3241 | WLAN_REASON_UNSPECIFIED); | ||
3242 | } | ||
3243 | } | ||
3244 | |||
3245 | |||
3246 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | 3128 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, |
3247 | struct ieee80211_if_sta *ifsta) | 3129 | struct ieee80211_if_sta *ifsta) |
3248 | { | 3130 | { |
@@ -3327,85 +3209,6 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, | |||
3327 | return 0; | 3209 | return 0; |
3328 | } | 3210 | } |
3329 | 3211 | ||
3330 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | ||
3331 | struct ieee80211_if_sta *ifsta) | ||
3332 | { | ||
3333 | struct ieee80211_local *local = sdata->local; | ||
3334 | struct ieee80211_sta_bss *bss, *selected = NULL; | ||
3335 | int top_rssi = 0, freq; | ||
3336 | |||
3337 | spin_lock_bh(&local->sta_bss_lock); | ||
3338 | freq = local->oper_channel->center_freq; | ||
3339 | list_for_each_entry(bss, &local->sta_bss_list, list) { | ||
3340 | if (!(bss->capability & WLAN_CAPABILITY_ESS)) | ||
3341 | continue; | ||
3342 | |||
3343 | if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | ||
3344 | IEEE80211_STA_AUTO_BSSID_SEL | | ||
3345 | IEEE80211_STA_AUTO_CHANNEL_SEL)) && | ||
3346 | (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ | ||
3347 | !!sdata->default_key)) | ||
3348 | continue; | ||
3349 | |||
3350 | if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && | ||
3351 | bss->freq != freq) | ||
3352 | continue; | ||
3353 | |||
3354 | if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && | ||
3355 | memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) | ||
3356 | continue; | ||
3357 | |||
3358 | if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && | ||
3359 | !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) | ||
3360 | continue; | ||
3361 | |||
3362 | if (!selected || top_rssi < bss->signal) { | ||
3363 | selected = bss; | ||
3364 | top_rssi = bss->signal; | ||
3365 | } | ||
3366 | } | ||
3367 | if (selected) | ||
3368 | atomic_inc(&selected->users); | ||
3369 | spin_unlock_bh(&local->sta_bss_lock); | ||
3370 | |||
3371 | if (selected) { | ||
3372 | ieee80211_set_freq(sdata, selected->freq); | ||
3373 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | ||
3374 | ieee80211_sta_set_ssid(sdata, selected->ssid, | ||
3375 | selected->ssid_len); | ||
3376 | ieee80211_sta_set_bssid(sdata, selected->bssid); | ||
3377 | ieee80211_sta_def_wmm_params(sdata, selected, 0); | ||
3378 | |||
3379 | /* Send out direct probe if no probe resp was received or | ||
3380 | * the one we have is outdated | ||
3381 | */ | ||
3382 | if (!selected->last_probe_resp || | ||
3383 | time_after(jiffies, selected->last_probe_resp | ||
3384 | + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
3385 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | ||
3386 | else | ||
3387 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
3388 | |||
3389 | ieee80211_rx_bss_put(local, selected); | ||
3390 | ieee80211_sta_reset_auth(sdata, ifsta); | ||
3391 | return 0; | ||
3392 | } else { | ||
3393 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | ||
3394 | ifsta->assoc_scan_tries++; | ||
3395 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | ||
3396 | ieee80211_sta_start_scan(sdata, NULL, 0); | ||
3397 | else | ||
3398 | ieee80211_sta_start_scan(sdata, ifsta->ssid, | ||
3399 | ifsta->ssid_len); | ||
3400 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
3401 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | ||
3402 | } else | ||
3403 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | ||
3404 | } | ||
3405 | return -1; | ||
3406 | } | ||
3407 | |||
3408 | |||
3409 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | 3212 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, |
3410 | struct ieee80211_if_sta *ifsta) | 3213 | struct ieee80211_if_sta *ifsta) |
3411 | { | 3214 | { |
@@ -4273,6 +4076,85 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
4273 | } | 4076 | } |
4274 | 4077 | ||
4275 | 4078 | ||
4079 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | ||
4080 | struct ieee80211_if_sta *ifsta) | ||
4081 | { | ||
4082 | struct ieee80211_local *local = sdata->local; | ||
4083 | struct ieee80211_sta_bss *bss, *selected = NULL; | ||
4084 | int top_rssi = 0, freq; | ||
4085 | |||
4086 | spin_lock_bh(&local->sta_bss_lock); | ||
4087 | freq = local->oper_channel->center_freq; | ||
4088 | list_for_each_entry(bss, &local->sta_bss_list, list) { | ||
4089 | if (!(bss->capability & WLAN_CAPABILITY_ESS)) | ||
4090 | continue; | ||
4091 | |||
4092 | if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | ||
4093 | IEEE80211_STA_AUTO_BSSID_SEL | | ||
4094 | IEEE80211_STA_AUTO_CHANNEL_SEL)) && | ||
4095 | (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ | ||
4096 | !!sdata->default_key)) | ||
4097 | continue; | ||
4098 | |||
4099 | if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && | ||
4100 | bss->freq != freq) | ||
4101 | continue; | ||
4102 | |||
4103 | if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && | ||
4104 | memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) | ||
4105 | continue; | ||
4106 | |||
4107 | if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && | ||
4108 | !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) | ||
4109 | continue; | ||
4110 | |||
4111 | if (!selected || top_rssi < bss->signal) { | ||
4112 | selected = bss; | ||
4113 | top_rssi = bss->signal; | ||
4114 | } | ||
4115 | } | ||
4116 | if (selected) | ||
4117 | atomic_inc(&selected->users); | ||
4118 | spin_unlock_bh(&local->sta_bss_lock); | ||
4119 | |||
4120 | if (selected) { | ||
4121 | ieee80211_set_freq(sdata, selected->freq); | ||
4122 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | ||
4123 | ieee80211_sta_set_ssid(sdata, selected->ssid, | ||
4124 | selected->ssid_len); | ||
4125 | ieee80211_sta_set_bssid(sdata, selected->bssid); | ||
4126 | ieee80211_sta_def_wmm_params(sdata, selected, 0); | ||
4127 | |||
4128 | /* Send out direct probe if no probe resp was received or | ||
4129 | * the one we have is outdated | ||
4130 | */ | ||
4131 | if (!selected->last_probe_resp || | ||
4132 | time_after(jiffies, selected->last_probe_resp | ||
4133 | + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
4134 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | ||
4135 | else | ||
4136 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
4137 | |||
4138 | ieee80211_rx_bss_put(local, selected); | ||
4139 | ieee80211_sta_reset_auth(sdata, ifsta); | ||
4140 | return 0; | ||
4141 | } else { | ||
4142 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | ||
4143 | ifsta->assoc_scan_tries++; | ||
4144 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | ||
4145 | ieee80211_sta_start_scan(sdata, NULL, 0); | ||
4146 | else | ||
4147 | ieee80211_sta_start_scan(sdata, ifsta->ssid, | ||
4148 | ifsta->ssid_len); | ||
4149 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
4150 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | ||
4151 | } else | ||
4152 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | ||
4153 | } | ||
4154 | return -1; | ||
4155 | } | ||
4156 | |||
4157 | |||
4276 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | 4158 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) |
4277 | { | 4159 | { |
4278 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 4160 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
@@ -4326,3 +4208,91 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw, | |||
4326 | } | 4208 | } |
4327 | } | 4209 | } |
4328 | EXPORT_SYMBOL(ieee80211_notify_mac); | 4210 | EXPORT_SYMBOL(ieee80211_notify_mac); |
4211 | |||
4212 | void ieee80211_sta_work(struct work_struct *work) | ||
4213 | { | ||
4214 | struct ieee80211_sub_if_data *sdata = | ||
4215 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | ||
4216 | struct ieee80211_local *local = sdata->local; | ||
4217 | struct ieee80211_if_sta *ifsta; | ||
4218 | struct sk_buff *skb; | ||
4219 | |||
4220 | if (!netif_running(sdata->dev)) | ||
4221 | return; | ||
4222 | |||
4223 | if (local->sta_sw_scanning || local->sta_hw_scanning) | ||
4224 | return; | ||
4225 | |||
4226 | if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA && | ||
4227 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | ||
4228 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) | ||
4229 | return; | ||
4230 | ifsta = &sdata->u.sta; | ||
4231 | |||
4232 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | ||
4233 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | ||
4234 | |||
4235 | #ifdef CONFIG_MAC80211_MESH | ||
4236 | if (ifsta->preq_queue_len && | ||
4237 | time_after(jiffies, | ||
4238 | ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) | ||
4239 | mesh_path_start_discovery(sdata); | ||
4240 | #endif | ||
4241 | |||
4242 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && | ||
4243 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | ||
4244 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | ||
4245 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | ||
4246 | if (ifsta->scan_ssid_len) | ||
4247 | ieee80211_sta_start_scan(sdata, ifsta->scan_ssid, ifsta->scan_ssid_len); | ||
4248 | else | ||
4249 | ieee80211_sta_start_scan(sdata, NULL, 0); | ||
4250 | return; | ||
4251 | } | ||
4252 | |||
4253 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { | ||
4254 | if (ieee80211_sta_config_auth(sdata, ifsta)) | ||
4255 | return; | ||
4256 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | ||
4257 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) | ||
4258 | return; | ||
4259 | |||
4260 | switch (ifsta->state) { | ||
4261 | case IEEE80211_STA_MLME_DISABLED: | ||
4262 | break; | ||
4263 | case IEEE80211_STA_MLME_DIRECT_PROBE: | ||
4264 | ieee80211_direct_probe(sdata, ifsta); | ||
4265 | break; | ||
4266 | case IEEE80211_STA_MLME_AUTHENTICATE: | ||
4267 | ieee80211_authenticate(sdata, ifsta); | ||
4268 | break; | ||
4269 | case IEEE80211_STA_MLME_ASSOCIATE: | ||
4270 | ieee80211_associate(sdata, ifsta); | ||
4271 | break; | ||
4272 | case IEEE80211_STA_MLME_ASSOCIATED: | ||
4273 | ieee80211_associated(sdata, ifsta); | ||
4274 | break; | ||
4275 | case IEEE80211_STA_MLME_IBSS_SEARCH: | ||
4276 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
4277 | break; | ||
4278 | case IEEE80211_STA_MLME_IBSS_JOINED: | ||
4279 | ieee80211_sta_merge_ibss(sdata, ifsta); | ||
4280 | break; | ||
4281 | #ifdef CONFIG_MAC80211_MESH | ||
4282 | case IEEE80211_STA_MLME_MESH_UP: | ||
4283 | ieee80211_mesh_housekeeping(sdata, ifsta); | ||
4284 | break; | ||
4285 | #endif | ||
4286 | default: | ||
4287 | WARN_ON(1); | ||
4288 | break; | ||
4289 | } | ||
4290 | |||
4291 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | ||
4292 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " | ||
4293 | "mixed-cell disabled - disassociate\n", sdata->dev->name); | ||
4294 | |||
4295 | ieee80211_set_disassoc(sdata, ifsta, false, true, | ||
4296 | WLAN_REASON_UNSPECIFIED); | ||
4297 | } | ||
4298 | } | ||