diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-03-30 17:53:32 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-30 17:53:32 -0400 |
commit | 65fb0d23fcddd8697c871047b700c78817bdaa43 (patch) | |
tree | 119e6e5f276622c4c862f6c9b6d795264ba1603a /net/mac80211/mlme.c | |
parent | 8c083f081d0014057901c68a0a3e0f8ca7ac8d23 (diff) | |
parent | dfbbe89e197a77f2c8046a51c74e33e35f878080 (diff) |
Merge branch 'linus' into cpumask-for-linus
Conflicts:
arch/x86/kernel/cpu/common.c
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 2026 |
1 files changed, 772 insertions, 1254 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2b890af01ba4..7ecda9d59d8a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * BSS client mode implementation | 2 | * BSS client mode implementation |
3 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | 3 | * Copyright 2003-2008, Jouni Malinen <j@w1.fi> |
4 | * Copyright 2004, Instant802 Networks, Inc. | 4 | * Copyright 2004, Instant802 Networks, Inc. |
5 | * Copyright 2005, Devicescape Software, Inc. | 5 | * Copyright 2005, Devicescape Software, Inc. |
6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
@@ -15,11 +15,8 @@ | |||
15 | #include <linux/if_ether.h> | 15 | #include <linux/if_ether.h> |
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/if_arp.h> | 17 | #include <linux/if_arp.h> |
18 | #include <linux/wireless.h> | ||
19 | #include <linux/random.h> | ||
20 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
21 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
22 | #include <net/iw_handler.h> | ||
23 | #include <net/mac80211.h> | 20 | #include <net/mac80211.h> |
24 | #include <asm/unaligned.h> | 21 | #include <asm/unaligned.h> |
25 | 22 | ||
@@ -33,17 +30,8 @@ | |||
33 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 30 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
34 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 31 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 32 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
36 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) | 33 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) |
37 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 34 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
38 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | ||
39 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) | ||
40 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | ||
41 | |||
42 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | ||
43 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | ||
44 | |||
45 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | ||
46 | |||
47 | 35 | ||
48 | /* utils */ | 36 | /* utils */ |
49 | static int ecw2cw(int ecw) | 37 | static int ecw2cw(int ecw) |
@@ -55,10 +43,10 @@ static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie) | |||
55 | { | 43 | { |
56 | u8 *end, *pos; | 44 | u8 *end, *pos; |
57 | 45 | ||
58 | pos = bss->ies; | 46 | pos = bss->cbss.information_elements; |
59 | if (pos == NULL) | 47 | if (pos == NULL) |
60 | return NULL; | 48 | return NULL; |
61 | end = pos + bss->ies_len; | 49 | end = pos + bss->cbss.len_information_elements; |
62 | 50 | ||
63 | while (pos + 1 < end) { | 51 | while (pos + 1 < end) { |
64 | if (pos + 2 + pos[1] > end) | 52 | if (pos + 2 + pos[1] > end) |
@@ -73,7 +61,7 @@ static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie) | |||
73 | 61 | ||
74 | static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | 62 | static int ieee80211_compatible_rates(struct ieee80211_bss *bss, |
75 | struct ieee80211_supported_band *sband, | 63 | struct ieee80211_supported_band *sband, |
76 | u64 *rates) | 64 | u32 *rates) |
77 | { | 65 | { |
78 | int i, j, count; | 66 | int i, j, count; |
79 | *rates = 0; | 67 | *rates = 0; |
@@ -92,146 +80,11 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | |||
92 | return count; | 80 | return count; |
93 | } | 81 | } |
94 | 82 | ||
95 | /* also used by mesh code */ | ||
96 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
97 | struct ieee802_11_elems *elems, | ||
98 | enum ieee80211_band band) | ||
99 | { | ||
100 | struct ieee80211_supported_band *sband; | ||
101 | struct ieee80211_rate *bitrates; | ||
102 | size_t num_rates; | ||
103 | u64 supp_rates; | ||
104 | int i, j; | ||
105 | sband = local->hw.wiphy->bands[band]; | ||
106 | |||
107 | if (!sband) { | ||
108 | WARN_ON(1); | ||
109 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
110 | } | ||
111 | |||
112 | bitrates = sband->bitrates; | ||
113 | num_rates = sband->n_bitrates; | ||
114 | supp_rates = 0; | ||
115 | for (i = 0; i < elems->supp_rates_len + | ||
116 | elems->ext_supp_rates_len; i++) { | ||
117 | u8 rate = 0; | ||
118 | int own_rate; | ||
119 | if (i < elems->supp_rates_len) | ||
120 | rate = elems->supp_rates[i]; | ||
121 | else if (elems->ext_supp_rates) | ||
122 | rate = elems->ext_supp_rates | ||
123 | [i - elems->supp_rates_len]; | ||
124 | own_rate = 5 * (rate & 0x7f); | ||
125 | for (j = 0; j < num_rates; j++) | ||
126 | if (bitrates[j].bitrate == own_rate) | ||
127 | supp_rates |= BIT(j); | ||
128 | } | ||
129 | return supp_rates; | ||
130 | } | ||
131 | |||
132 | /* frame sending functions */ | 83 | /* frame sending functions */ |
133 | 84 | ||
134 | /* also used by scanning code */ | 85 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) |
135 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
136 | u8 *ssid, size_t ssid_len) | ||
137 | { | ||
138 | struct ieee80211_local *local = sdata->local; | ||
139 | struct ieee80211_supported_band *sband; | ||
140 | struct sk_buff *skb; | ||
141 | struct ieee80211_mgmt *mgmt; | ||
142 | u8 *pos, *supp_rates, *esupp_rates = NULL; | ||
143 | int i; | ||
144 | |||
145 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); | ||
146 | if (!skb) { | ||
147 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
148 | "request\n", sdata->dev->name); | ||
149 | return; | ||
150 | } | ||
151 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
152 | |||
153 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
154 | memset(mgmt, 0, 24); | ||
155 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
156 | IEEE80211_STYPE_PROBE_REQ); | ||
157 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
158 | if (dst) { | ||
159 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
160 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
161 | } else { | ||
162 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
163 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
164 | } | ||
165 | pos = skb_put(skb, 2 + ssid_len); | ||
166 | *pos++ = WLAN_EID_SSID; | ||
167 | *pos++ = ssid_len; | ||
168 | memcpy(pos, ssid, ssid_len); | ||
169 | |||
170 | supp_rates = skb_put(skb, 2); | ||
171 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
172 | supp_rates[1] = 0; | ||
173 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
174 | |||
175 | for (i = 0; i < sband->n_bitrates; i++) { | ||
176 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
177 | if (esupp_rates) { | ||
178 | pos = skb_put(skb, 1); | ||
179 | esupp_rates[1]++; | ||
180 | } else if (supp_rates[1] == 8) { | ||
181 | esupp_rates = skb_put(skb, 3); | ||
182 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
183 | esupp_rates[1] = 1; | ||
184 | pos = &esupp_rates[2]; | ||
185 | } else { | ||
186 | pos = skb_put(skb, 1); | ||
187 | supp_rates[1]++; | ||
188 | } | ||
189 | *pos = rate->bitrate / 5; | ||
190 | } | ||
191 | |||
192 | ieee80211_tx_skb(sdata, skb, 0); | ||
193 | } | ||
194 | |||
195 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
196 | struct ieee80211_if_sta *ifsta, | ||
197 | int transaction, u8 *extra, size_t extra_len, | ||
198 | int encrypt) | ||
199 | { | ||
200 | struct ieee80211_local *local = sdata->local; | ||
201 | struct sk_buff *skb; | ||
202 | struct ieee80211_mgmt *mgmt; | ||
203 | |||
204 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
205 | sizeof(*mgmt) + 6 + extra_len); | ||
206 | if (!skb) { | ||
207 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
208 | "frame\n", sdata->dev->name); | ||
209 | return; | ||
210 | } | ||
211 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
212 | |||
213 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
214 | memset(mgmt, 0, 24 + 6); | ||
215 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
216 | IEEE80211_STYPE_AUTH); | ||
217 | if (encrypt) | ||
218 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
219 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
220 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
221 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
222 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | ||
223 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
224 | ifsta->auth_transaction = transaction + 1; | ||
225 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
226 | if (extra) | ||
227 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
228 | |||
229 | ieee80211_tx_skb(sdata, skb, encrypt); | ||
230 | } | ||
231 | |||
232 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
233 | struct ieee80211_if_sta *ifsta) | ||
234 | { | 86 | { |
87 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
235 | struct ieee80211_local *local = sdata->local; | 88 | struct ieee80211_local *local = sdata->local; |
236 | struct sk_buff *skb; | 89 | struct sk_buff *skb; |
237 | struct ieee80211_mgmt *mgmt; | 90 | struct ieee80211_mgmt *mgmt; |
@@ -241,11 +94,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
241 | struct ieee80211_bss *bss; | 94 | struct ieee80211_bss *bss; |
242 | int wmm = 0; | 95 | int wmm = 0; |
243 | struct ieee80211_supported_band *sband; | 96 | struct ieee80211_supported_band *sband; |
244 | u64 rates = 0; | 97 | u32 rates = 0; |
245 | 98 | ||
246 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 99 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
247 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | 100 | sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + |
248 | ifsta->ssid_len); | 101 | ifmgd->ssid_len); |
249 | if (!skb) { | 102 | if (!skb) { |
250 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 103 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
251 | "frame\n", sdata->dev->name); | 104 | "frame\n", sdata->dev->name); |
@@ -255,7 +108,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
255 | 108 | ||
256 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 109 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
257 | 110 | ||
258 | capab = ifsta->capab; | 111 | capab = ifmgd->capab; |
259 | 112 | ||
260 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | 113 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { |
261 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | 114 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) |
@@ -264,11 +117,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
264 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | 117 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; |
265 | } | 118 | } |
266 | 119 | ||
267 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 120 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
268 | local->hw.conf.channel->center_freq, | 121 | local->hw.conf.channel->center_freq, |
269 | ifsta->ssid, ifsta->ssid_len); | 122 | ifmgd->ssid, ifmgd->ssid_len); |
270 | if (bss) { | 123 | if (bss) { |
271 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | 124 | if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) |
272 | capab |= WLAN_CAPABILITY_PRIVACY; | 125 | capab |= WLAN_CAPABILITY_PRIVACY; |
273 | if (bss->wmm_used) | 126 | if (bss->wmm_used) |
274 | wmm = 1; | 127 | wmm = 1; |
@@ -279,7 +132,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
279 | * b-only mode) */ | 132 | * b-only mode) */ |
280 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); | 133 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); |
281 | 134 | ||
282 | if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | 135 | if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && |
283 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | 136 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) |
284 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | 137 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; |
285 | 138 | ||
@@ -291,18 +144,18 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
291 | 144 | ||
292 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 145 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
293 | memset(mgmt, 0, 24); | 146 | memset(mgmt, 0, 24); |
294 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 147 | memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); |
295 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 148 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
296 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 149 | memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); |
297 | 150 | ||
298 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | 151 | if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) { |
299 | skb_put(skb, 10); | 152 | skb_put(skb, 10); |
300 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 153 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
301 | IEEE80211_STYPE_REASSOC_REQ); | 154 | IEEE80211_STYPE_REASSOC_REQ); |
302 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | 155 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); |
303 | mgmt->u.reassoc_req.listen_interval = | 156 | mgmt->u.reassoc_req.listen_interval = |
304 | cpu_to_le16(local->hw.conf.listen_interval); | 157 | cpu_to_le16(local->hw.conf.listen_interval); |
305 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, | 158 | memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid, |
306 | ETH_ALEN); | 159 | ETH_ALEN); |
307 | } else { | 160 | } else { |
308 | skb_put(skb, 4); | 161 | skb_put(skb, 4); |
@@ -314,10 +167,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
314 | } | 167 | } |
315 | 168 | ||
316 | /* SSID */ | 169 | /* SSID */ |
317 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); | 170 | ies = pos = skb_put(skb, 2 + ifmgd->ssid_len); |
318 | *pos++ = WLAN_EID_SSID; | 171 | *pos++ = WLAN_EID_SSID; |
319 | *pos++ = ifsta->ssid_len; | 172 | *pos++ = ifmgd->ssid_len; |
320 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | 173 | memcpy(pos, ifmgd->ssid, ifmgd->ssid_len); |
321 | 174 | ||
322 | /* add all rates which were marked to be used above */ | 175 | /* add all rates which were marked to be used above */ |
323 | supp_rates_len = rates_len; | 176 | supp_rates_len = rates_len; |
@@ -372,12 +225,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
372 | } | 225 | } |
373 | } | 226 | } |
374 | 227 | ||
375 | if (ifsta->extra_ie) { | 228 | if (ifmgd->extra_ie) { |
376 | pos = skb_put(skb, ifsta->extra_ie_len); | 229 | pos = skb_put(skb, ifmgd->extra_ie_len); |
377 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); | 230 | memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len); |
378 | } | 231 | } |
379 | 232 | ||
380 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | 233 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { |
381 | pos = skb_put(skb, 9); | 234 | pos = skb_put(skb, 9); |
382 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 235 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
383 | *pos++ = 7; /* len */ | 236 | *pos++ = 7; /* len */ |
@@ -391,10 +244,17 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
391 | } | 244 | } |
392 | 245 | ||
393 | /* wmm support is a must to HT */ | 246 | /* wmm support is a must to HT */ |
394 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | 247 | /* |
248 | * IEEE802.11n does not allow TKIP/WEP as pairwise | ||
249 | * ciphers in HT mode. We still associate in non-ht | ||
250 | * mode (11a/b/g) if any one of these ciphers is | ||
251 | * configured as pairwise. | ||
252 | */ | ||
253 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | ||
395 | sband->ht_cap.ht_supported && | 254 | sband->ht_cap.ht_supported && |
396 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && | 255 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && |
397 | ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { | 256 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && |
257 | (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) { | ||
398 | struct ieee80211_ht_info *ht_info = | 258 | struct ieee80211_ht_info *ht_info = |
399 | (struct ieee80211_ht_info *)(ht_ie + 2); | 259 | (struct ieee80211_ht_info *)(ht_ie + 2); |
400 | u16 cap = sband->ht_cap.cap; | 260 | u16 cap = sband->ht_cap.cap; |
@@ -429,11 +289,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
429 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 289 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
430 | } | 290 | } |
431 | 291 | ||
432 | kfree(ifsta->assocreq_ies); | 292 | kfree(ifmgd->assocreq_ies); |
433 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | 293 | ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; |
434 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | 294 | ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); |
435 | if (ifsta->assocreq_ies) | 295 | if (ifmgd->assocreq_ies) |
436 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); | 296 | memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len); |
437 | 297 | ||
438 | ieee80211_tx_skb(sdata, skb, 0); | 298 | ieee80211_tx_skb(sdata, skb, 0); |
439 | } | 299 | } |
@@ -443,7 +303,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
443 | u16 stype, u16 reason) | 303 | u16 stype, u16 reason) |
444 | { | 304 | { |
445 | struct ieee80211_local *local = sdata->local; | 305 | struct ieee80211_local *local = sdata->local; |
446 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 306 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
447 | struct sk_buff *skb; | 307 | struct sk_buff *skb; |
448 | struct ieee80211_mgmt *mgmt; | 308 | struct ieee80211_mgmt *mgmt; |
449 | 309 | ||
@@ -457,40 +317,51 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
457 | 317 | ||
458 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 318 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
459 | memset(mgmt, 0, 24); | 319 | memset(mgmt, 0, 24); |
460 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 320 | memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); |
461 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 321 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
462 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 322 | memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); |
463 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | 323 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); |
464 | skb_put(skb, 2); | 324 | skb_put(skb, 2); |
465 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 325 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
466 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | 326 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); |
467 | 327 | ||
468 | ieee80211_tx_skb(sdata, skb, 0); | 328 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); |
469 | } | 329 | } |
470 | 330 | ||
471 | /* MLME */ | 331 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
472 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 332 | struct ieee80211_sub_if_data *sdata) |
473 | struct ieee80211_bss *bss) | ||
474 | { | 333 | { |
475 | struct ieee80211_local *local = sdata->local; | 334 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
476 | int i, have_higher_than_11mbit = 0; | 335 | struct ieee80211_pspoll *pspoll; |
336 | struct sk_buff *skb; | ||
337 | u16 fc; | ||
477 | 338 | ||
478 | /* cf. IEEE 802.11 9.2.12 */ | 339 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); |
479 | for (i = 0; i < bss->supp_rates_len; i++) | 340 | if (!skb) { |
480 | if ((bss->supp_rates[i] & 0x7f) * 5 > 110) | 341 | printk(KERN_DEBUG "%s: failed to allocate buffer for " |
481 | have_higher_than_11mbit = 1; | 342 | "pspoll frame\n", sdata->dev->name); |
343 | return; | ||
344 | } | ||
345 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
482 | 346 | ||
483 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | 347 | pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); |
484 | have_higher_than_11mbit) | 348 | memset(pspoll, 0, sizeof(*pspoll)); |
485 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 349 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; |
486 | else | 350 | pspoll->frame_control = cpu_to_le16(fc); |
487 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 351 | pspoll->aid = cpu_to_le16(ifmgd->aid); |
352 | |||
353 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
354 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | ||
488 | 355 | ||
489 | ieee80211_set_wmm_default(sdata); | 356 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); |
357 | memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); | ||
358 | |||
359 | ieee80211_tx_skb(sdata, skb, 0); | ||
490 | } | 360 | } |
491 | 361 | ||
362 | /* MLME */ | ||
492 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | 363 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, |
493 | struct ieee80211_if_sta *ifsta, | 364 | struct ieee80211_if_managed *ifmgd, |
494 | u8 *wmm_param, size_t wmm_param_len) | 365 | u8 *wmm_param, size_t wmm_param_len) |
495 | { | 366 | { |
496 | struct ieee80211_tx_queue_params params; | 367 | struct ieee80211_tx_queue_params params; |
@@ -498,7 +369,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
498 | int count; | 369 | int count; |
499 | u8 *pos; | 370 | u8 *pos; |
500 | 371 | ||
501 | if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED)) | 372 | if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) |
502 | return; | 373 | return; |
503 | 374 | ||
504 | if (!wmm_param) | 375 | if (!wmm_param) |
@@ -507,18 +378,15 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
507 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) | 378 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) |
508 | return; | 379 | return; |
509 | count = wmm_param[6] & 0x0f; | 380 | count = wmm_param[6] & 0x0f; |
510 | if (count == ifsta->wmm_last_param_set) | 381 | if (count == ifmgd->wmm_last_param_set) |
511 | return; | 382 | return; |
512 | ifsta->wmm_last_param_set = count; | 383 | ifmgd->wmm_last_param_set = count; |
513 | 384 | ||
514 | pos = wmm_param + 8; | 385 | pos = wmm_param + 8; |
515 | left = wmm_param_len - 8; | 386 | left = wmm_param_len - 8; |
516 | 387 | ||
517 | memset(¶ms, 0, sizeof(params)); | 388 | memset(¶ms, 0, sizeof(params)); |
518 | 389 | ||
519 | if (!local->ops->conf_tx) | ||
520 | return; | ||
521 | |||
522 | local->wmm_acm = 0; | 390 | local->wmm_acm = 0; |
523 | for (; left >= 4; left -= 4, pos += 4) { | 391 | for (; left >= 4; left -= 4, pos += 4) { |
524 | int aci = (pos[0] >> 5) & 0x03; | 392 | int aci = (pos[0] >> 5) & 0x03; |
@@ -526,26 +394,26 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
526 | int queue; | 394 | int queue; |
527 | 395 | ||
528 | switch (aci) { | 396 | switch (aci) { |
529 | case 1: | 397 | case 1: /* AC_BK */ |
530 | queue = 3; | 398 | queue = 3; |
531 | if (acm) | 399 | if (acm) |
532 | local->wmm_acm |= BIT(0) | BIT(3); | 400 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ |
533 | break; | 401 | break; |
534 | case 2: | 402 | case 2: /* AC_VI */ |
535 | queue = 1; | 403 | queue = 1; |
536 | if (acm) | 404 | if (acm) |
537 | local->wmm_acm |= BIT(4) | BIT(5); | 405 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ |
538 | break; | 406 | break; |
539 | case 3: | 407 | case 3: /* AC_VO */ |
540 | queue = 0; | 408 | queue = 0; |
541 | if (acm) | 409 | if (acm) |
542 | local->wmm_acm |= BIT(6) | BIT(7); | 410 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ |
543 | break; | 411 | break; |
544 | case 0: | 412 | case 0: /* AC_BE */ |
545 | default: | 413 | default: |
546 | queue = 2; | 414 | queue = 2; |
547 | if (acm) | 415 | if (acm) |
548 | local->wmm_acm |= BIT(1) | BIT(2); | 416 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ |
549 | break; | 417 | break; |
550 | } | 418 | } |
551 | 419 | ||
@@ -559,21 +427,41 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
559 | local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, | 427 | local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, |
560 | params.cw_max, params.txop); | 428 | params.cw_max, params.txop); |
561 | #endif | 429 | #endif |
562 | /* TODO: handle ACM (block TX, fallback to next lowest allowed | 430 | if (local->ops->conf_tx && |
563 | * AC for now) */ | 431 | local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { |
564 | if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { | ||
565 | printk(KERN_DEBUG "%s: failed to set TX queue " | 432 | printk(KERN_DEBUG "%s: failed to set TX queue " |
566 | "parameters for queue %d\n", local->mdev->name, queue); | 433 | "parameters for queue %d\n", local->mdev->name, queue); |
567 | } | 434 | } |
568 | } | 435 | } |
569 | } | 436 | } |
570 | 437 | ||
438 | static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid) | ||
439 | { | ||
440 | u8 mask; | ||
441 | u8 index, indexn1, indexn2; | ||
442 | struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim; | ||
443 | |||
444 | aid &= 0x3fff; | ||
445 | index = aid / 8; | ||
446 | mask = 1 << (aid & 7); | ||
447 | |||
448 | indexn1 = tim->bitmap_ctrl & 0xfe; | ||
449 | indexn2 = elems->tim_len + indexn1 - 4; | ||
450 | |||
451 | if (index < indexn1 || index > indexn2) | ||
452 | return false; | ||
453 | |||
454 | index -= indexn1; | ||
455 | |||
456 | return !!(tim->virtual_map[index] & mask); | ||
457 | } | ||
458 | |||
571 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | 459 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, |
572 | u16 capab, bool erp_valid, u8 erp) | 460 | u16 capab, bool erp_valid, u8 erp) |
573 | { | 461 | { |
574 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 462 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
575 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 463 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
576 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 464 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
577 | #endif | 465 | #endif |
578 | u32 changed = 0; | 466 | u32 changed = 0; |
579 | bool use_protection; | 467 | bool use_protection; |
@@ -596,7 +484,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
596 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", | 484 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", |
597 | sdata->dev->name, | 485 | sdata->dev->name, |
598 | use_protection ? "enabled" : "disabled", | 486 | use_protection ? "enabled" : "disabled", |
599 | ifsta->bssid); | 487 | ifmgd->bssid); |
600 | } | 488 | } |
601 | #endif | 489 | #endif |
602 | bss_conf->use_cts_prot = use_protection; | 490 | bss_conf->use_cts_prot = use_protection; |
@@ -610,7 +498,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
610 | " (BSSID=%pM)\n", | 498 | " (BSSID=%pM)\n", |
611 | sdata->dev->name, | 499 | sdata->dev->name, |
612 | use_short_preamble ? "short" : "long", | 500 | use_short_preamble ? "short" : "long", |
613 | ifsta->bssid); | 501 | ifmgd->bssid); |
614 | } | 502 | } |
615 | #endif | 503 | #endif |
616 | bss_conf->use_short_preamble = use_short_preamble; | 504 | bss_conf->use_short_preamble = use_short_preamble; |
@@ -624,7 +512,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
624 | " (BSSID=%pM)\n", | 512 | " (BSSID=%pM)\n", |
625 | sdata->dev->name, | 513 | sdata->dev->name, |
626 | use_short_slot ? "short" : "long", | 514 | use_short_slot ? "short" : "long", |
627 | ifsta->bssid); | 515 | ifmgd->bssid); |
628 | } | 516 | } |
629 | #endif | 517 | #endif |
630 | bss_conf->use_short_slot = use_short_slot; | 518 | bss_conf->use_short_slot = use_short_slot; |
@@ -634,57 +522,57 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
634 | return changed; | 522 | return changed; |
635 | } | 523 | } |
636 | 524 | ||
637 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata, | 525 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata) |
638 | struct ieee80211_if_sta *ifsta) | ||
639 | { | 526 | { |
640 | union iwreq_data wrqu; | 527 | union iwreq_data wrqu; |
528 | |||
641 | memset(&wrqu, 0, sizeof(wrqu)); | 529 | memset(&wrqu, 0, sizeof(wrqu)); |
642 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 530 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) |
643 | memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); | 531 | memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN); |
644 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 532 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
645 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | 533 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); |
646 | } | 534 | } |
647 | 535 | ||
648 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | 536 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata) |
649 | struct ieee80211_if_sta *ifsta) | ||
650 | { | 537 | { |
538 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
651 | char *buf; | 539 | char *buf; |
652 | size_t len; | 540 | size_t len; |
653 | int i; | 541 | int i; |
654 | union iwreq_data wrqu; | 542 | union iwreq_data wrqu; |
655 | 543 | ||
656 | if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) | 544 | if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies) |
657 | return; | 545 | return; |
658 | 546 | ||
659 | buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + | 547 | buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len + |
660 | ifsta->assocresp_ies_len), GFP_KERNEL); | 548 | ifmgd->assocresp_ies_len), GFP_KERNEL); |
661 | if (!buf) | 549 | if (!buf) |
662 | return; | 550 | return; |
663 | 551 | ||
664 | len = sprintf(buf, "ASSOCINFO("); | 552 | len = sprintf(buf, "ASSOCINFO("); |
665 | if (ifsta->assocreq_ies) { | 553 | if (ifmgd->assocreq_ies) { |
666 | len += sprintf(buf + len, "ReqIEs="); | 554 | len += sprintf(buf + len, "ReqIEs="); |
667 | for (i = 0; i < ifsta->assocreq_ies_len; i++) { | 555 | for (i = 0; i < ifmgd->assocreq_ies_len; i++) { |
668 | len += sprintf(buf + len, "%02x", | 556 | len += sprintf(buf + len, "%02x", |
669 | ifsta->assocreq_ies[i]); | 557 | ifmgd->assocreq_ies[i]); |
670 | } | 558 | } |
671 | } | 559 | } |
672 | if (ifsta->assocresp_ies) { | 560 | if (ifmgd->assocresp_ies) { |
673 | if (ifsta->assocreq_ies) | 561 | if (ifmgd->assocreq_ies) |
674 | len += sprintf(buf + len, " "); | 562 | len += sprintf(buf + len, " "); |
675 | len += sprintf(buf + len, "RespIEs="); | 563 | len += sprintf(buf + len, "RespIEs="); |
676 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { | 564 | for (i = 0; i < ifmgd->assocresp_ies_len; i++) { |
677 | len += sprintf(buf + len, "%02x", | 565 | len += sprintf(buf + len, "%02x", |
678 | ifsta->assocresp_ies[i]); | 566 | ifmgd->assocresp_ies[i]); |
679 | } | 567 | } |
680 | } | 568 | } |
681 | len += sprintf(buf + len, ")"); | 569 | len += sprintf(buf + len, ")"); |
682 | 570 | ||
683 | if (len > IW_CUSTOM_MAX) { | 571 | if (len > IW_CUSTOM_MAX) { |
684 | len = sprintf(buf, "ASSOCRESPIE="); | 572 | len = sprintf(buf, "ASSOCRESPIE="); |
685 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { | 573 | for (i = 0; i < ifmgd->assocresp_ies_len; i++) { |
686 | len += sprintf(buf + len, "%02x", | 574 | len += sprintf(buf + len, "%02x", |
687 | ifsta->assocresp_ies[i]); | 575 | ifmgd->assocresp_ies[i]); |
688 | } | 576 | } |
689 | } | 577 | } |
690 | 578 | ||
@@ -699,40 +587,39 @@ static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | |||
699 | 587 | ||
700 | 588 | ||
701 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 589 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
702 | struct ieee80211_if_sta *ifsta, | ||
703 | u32 bss_info_changed) | 590 | u32 bss_info_changed) |
704 | { | 591 | { |
592 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
705 | struct ieee80211_local *local = sdata->local; | 593 | struct ieee80211_local *local = sdata->local; |
706 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | 594 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; |
707 | 595 | ||
708 | struct ieee80211_bss *bss; | 596 | struct ieee80211_bss *bss; |
709 | 597 | ||
710 | bss_info_changed |= BSS_CHANGED_ASSOC; | 598 | bss_info_changed |= BSS_CHANGED_ASSOC; |
711 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; | 599 | ifmgd->flags |= IEEE80211_STA_ASSOCIATED; |
712 | |||
713 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
714 | return; | ||
715 | 600 | ||
716 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 601 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
717 | conf->channel->center_freq, | 602 | conf->channel->center_freq, |
718 | ifsta->ssid, ifsta->ssid_len); | 603 | ifmgd->ssid, ifmgd->ssid_len); |
719 | if (bss) { | 604 | if (bss) { |
720 | /* set timing information */ | 605 | /* set timing information */ |
721 | sdata->vif.bss_conf.beacon_int = bss->beacon_int; | 606 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; |
722 | sdata->vif.bss_conf.timestamp = bss->timestamp; | 607 | sdata->vif.bss_conf.timestamp = bss->cbss.tsf; |
723 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | 608 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; |
724 | 609 | ||
725 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 610 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
726 | bss->capability, bss->has_erp_value, bss->erp_value); | 611 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
612 | |||
613 | cfg80211_hold_bss(&bss->cbss); | ||
727 | 614 | ||
728 | ieee80211_rx_bss_put(local, bss); | 615 | ieee80211_rx_bss_put(local, bss); |
729 | } | 616 | } |
730 | 617 | ||
731 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | 618 | ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET; |
732 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); | 619 | memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN); |
733 | ieee80211_sta_send_associnfo(sdata, ifsta); | 620 | ieee80211_sta_send_associnfo(sdata); |
734 | 621 | ||
735 | ifsta->last_probe = jiffies; | 622 | ifmgd->last_probe = jiffies; |
736 | ieee80211_led_assoc(local, 1); | 623 | ieee80211_led_assoc(local, 1); |
737 | 624 | ||
738 | sdata->vif.bss_conf.assoc = 1; | 625 | sdata->vif.bss_conf.assoc = 1; |
@@ -745,72 +632,115 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
745 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 632 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
746 | 633 | ||
747 | if (local->powersave) { | 634 | if (local->powersave) { |
748 | if (local->dynamic_ps_timeout > 0) | 635 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) && |
636 | local->hw.conf.dynamic_ps_timeout > 0) { | ||
749 | mod_timer(&local->dynamic_ps_timer, jiffies + | 637 | mod_timer(&local->dynamic_ps_timer, jiffies + |
750 | msecs_to_jiffies(local->dynamic_ps_timeout)); | 638 | msecs_to_jiffies( |
751 | else { | 639 | local->hw.conf.dynamic_ps_timeout)); |
640 | } else { | ||
641 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
642 | ieee80211_send_nullfunc(local, sdata, 1); | ||
752 | conf->flags |= IEEE80211_CONF_PS; | 643 | conf->flags |= IEEE80211_CONF_PS; |
753 | ieee80211_hw_config(local, | 644 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
754 | IEEE80211_CONF_CHANGE_PS); | ||
755 | } | 645 | } |
756 | } | 646 | } |
757 | 647 | ||
758 | netif_tx_start_all_queues(sdata->dev); | 648 | netif_tx_start_all_queues(sdata->dev); |
759 | netif_carrier_on(sdata->dev); | 649 | netif_carrier_on(sdata->dev); |
760 | 650 | ||
761 | ieee80211_sta_send_apinfo(sdata, ifsta); | 651 | ieee80211_sta_send_apinfo(sdata); |
762 | } | 652 | } |
763 | 653 | ||
764 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | 654 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) |
765 | struct ieee80211_if_sta *ifsta) | ||
766 | { | 655 | { |
767 | ifsta->direct_probe_tries++; | 656 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
768 | if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | 657 | struct ieee80211_local *local = sdata->local; |
658 | |||
659 | ifmgd->direct_probe_tries++; | ||
660 | if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | ||
769 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | 661 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", |
770 | sdata->dev->name, ifsta->bssid); | 662 | sdata->dev->name, ifmgd->bssid); |
771 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 663 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
772 | ieee80211_sta_send_apinfo(sdata, ifsta); | 664 | ieee80211_sta_send_apinfo(sdata); |
665 | |||
666 | /* | ||
667 | * Most likely AP is not in the range so remove the | ||
668 | * bss information associated to the AP | ||
669 | */ | ||
670 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | ||
671 | sdata->local->hw.conf.channel->center_freq, | ||
672 | ifmgd->ssid, ifmgd->ssid_len); | ||
673 | |||
674 | /* | ||
675 | * We might have a pending scan which had no chance to run yet | ||
676 | * due to state == IEEE80211_STA_MLME_DIRECT_PROBE. | ||
677 | * Hence, queue the STAs work again | ||
678 | */ | ||
679 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
773 | return; | 680 | return; |
774 | } | 681 | } |
775 | 682 | ||
776 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", | 683 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", |
777 | sdata->dev->name, ifsta->bssid, | 684 | sdata->dev->name, ifmgd->bssid, |
778 | ifsta->direct_probe_tries); | 685 | ifmgd->direct_probe_tries); |
779 | 686 | ||
780 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 687 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
781 | 688 | ||
782 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request); | 689 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request); |
783 | 690 | ||
784 | /* Direct probe is sent to broadcast address as some APs | 691 | /* Direct probe is sent to broadcast address as some APs |
785 | * will not answer to direct packet in unassociated state. | 692 | * will not answer to direct packet in unassociated state. |
786 | */ | 693 | */ |
787 | ieee80211_send_probe_req(sdata, NULL, | 694 | ieee80211_send_probe_req(sdata, NULL, |
788 | ifsta->ssid, ifsta->ssid_len); | 695 | ifmgd->ssid, ifmgd->ssid_len, NULL, 0); |
789 | 696 | ||
790 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 697 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
791 | } | 698 | } |
792 | 699 | ||
793 | 700 | ||
794 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | 701 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) |
795 | struct ieee80211_if_sta *ifsta) | ||
796 | { | 702 | { |
797 | ifsta->auth_tries++; | 703 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
798 | if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | 704 | struct ieee80211_local *local = sdata->local; |
705 | u8 *ies; | ||
706 | size_t ies_len; | ||
707 | |||
708 | ifmgd->auth_tries++; | ||
709 | if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | ||
799 | printk(KERN_DEBUG "%s: authentication with AP %pM" | 710 | printk(KERN_DEBUG "%s: authentication with AP %pM" |
800 | " timed out\n", | 711 | " timed out\n", |
801 | sdata->dev->name, ifsta->bssid); | 712 | sdata->dev->name, ifmgd->bssid); |
802 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 713 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
803 | ieee80211_sta_send_apinfo(sdata, ifsta); | 714 | ieee80211_sta_send_apinfo(sdata); |
715 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | ||
716 | sdata->local->hw.conf.channel->center_freq, | ||
717 | ifmgd->ssid, ifmgd->ssid_len); | ||
718 | |||
719 | /* | ||
720 | * We might have a pending scan which had no chance to run yet | ||
721 | * due to state == IEEE80211_STA_MLME_AUTHENTICATE. | ||
722 | * Hence, queue the STAs work again | ||
723 | */ | ||
724 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
804 | return; | 725 | return; |
805 | } | 726 | } |
806 | 727 | ||
807 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 728 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
808 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", | 729 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", |
809 | sdata->dev->name, ifsta->bssid); | 730 | sdata->dev->name, ifmgd->bssid); |
810 | 731 | ||
811 | ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0); | 732 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { |
733 | ies = ifmgd->sme_auth_ie; | ||
734 | ies_len = ifmgd->sme_auth_ie_len; | ||
735 | } else { | ||
736 | ies = NULL; | ||
737 | ies_len = 0; | ||
738 | } | ||
739 | ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ies, ies_len, | ||
740 | ifmgd->bssid, 0); | ||
741 | ifmgd->auth_transaction = 2; | ||
812 | 742 | ||
813 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 743 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
814 | } | 744 | } |
815 | 745 | ||
816 | /* | 746 | /* |
@@ -818,32 +748,44 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
818 | * if self disconnected or a reason code from the AP. | 748 | * if self disconnected or a reason code from the AP. |
819 | */ | 749 | */ |
820 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 750 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
821 | struct ieee80211_if_sta *ifsta, bool deauth, | 751 | bool deauth, bool self_disconnected, |
822 | bool self_disconnected, u16 reason) | 752 | u16 reason) |
823 | { | 753 | { |
754 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
824 | struct ieee80211_local *local = sdata->local; | 755 | struct ieee80211_local *local = sdata->local; |
756 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | ||
757 | struct ieee80211_bss *bss; | ||
825 | struct sta_info *sta; | 758 | struct sta_info *sta; |
826 | u32 changed = 0, config_changed = 0; | 759 | u32 changed = 0, config_changed = 0; |
827 | 760 | ||
828 | rcu_read_lock(); | 761 | rcu_read_lock(); |
829 | 762 | ||
830 | sta = sta_info_get(local, ifsta->bssid); | 763 | sta = sta_info_get(local, ifmgd->bssid); |
831 | if (!sta) { | 764 | if (!sta) { |
832 | rcu_read_unlock(); | 765 | rcu_read_unlock(); |
833 | return; | 766 | return; |
834 | } | 767 | } |
835 | 768 | ||
836 | if (deauth) { | 769 | if (deauth) { |
837 | ifsta->direct_probe_tries = 0; | 770 | ifmgd->direct_probe_tries = 0; |
838 | ifsta->auth_tries = 0; | 771 | ifmgd->auth_tries = 0; |
839 | } | 772 | } |
840 | ifsta->assoc_scan_tries = 0; | 773 | ifmgd->assoc_scan_tries = 0; |
841 | ifsta->assoc_tries = 0; | 774 | ifmgd->assoc_tries = 0; |
842 | 775 | ||
843 | netif_tx_stop_all_queues(sdata->dev); | 776 | netif_tx_stop_all_queues(sdata->dev); |
844 | netif_carrier_off(sdata->dev); | 777 | netif_carrier_off(sdata->dev); |
845 | 778 | ||
846 | ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr); | 779 | ieee80211_sta_tear_down_BA_sessions(sta); |
780 | |||
781 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | ||
782 | conf->channel->center_freq, | ||
783 | ifmgd->ssid, ifmgd->ssid_len); | ||
784 | |||
785 | if (bss) { | ||
786 | cfg80211_unhold_bss(&bss->cbss); | ||
787 | ieee80211_rx_bss_put(local, bss); | ||
788 | } | ||
847 | 789 | ||
848 | if (self_disconnected) { | 790 | if (self_disconnected) { |
849 | if (deauth) | 791 | if (deauth) |
@@ -854,23 +796,28 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
854 | IEEE80211_STYPE_DISASSOC, reason); | 796 | IEEE80211_STYPE_DISASSOC, reason); |
855 | } | 797 | } |
856 | 798 | ||
857 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 799 | ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; |
858 | changed |= ieee80211_reset_erp_info(sdata); | 800 | changed |= ieee80211_reset_erp_info(sdata); |
859 | 801 | ||
860 | ieee80211_led_assoc(local, 0); | 802 | ieee80211_led_assoc(local, 0); |
861 | changed |= BSS_CHANGED_ASSOC; | 803 | changed |= BSS_CHANGED_ASSOC; |
862 | sdata->vif.bss_conf.assoc = false; | 804 | sdata->vif.bss_conf.assoc = false; |
863 | 805 | ||
864 | ieee80211_sta_send_apinfo(sdata, ifsta); | 806 | ieee80211_sta_send_apinfo(sdata); |
865 | 807 | ||
866 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) | 808 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { |
867 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 809 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
810 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | ||
811 | sdata->local->hw.conf.channel->center_freq, | ||
812 | ifmgd->ssid, ifmgd->ssid_len); | ||
813 | } | ||
868 | 814 | ||
869 | rcu_read_unlock(); | 815 | rcu_read_unlock(); |
870 | 816 | ||
871 | local->hw.conf.ht.enabled = false; | 817 | /* channel(_type) changes are handled by ieee80211_hw_config */ |
872 | local->oper_channel_type = NL80211_CHAN_NO_HT; | 818 | local->oper_channel_type = NL80211_CHAN_NO_HT; |
873 | config_changed |= IEEE80211_CONF_CHANGE_HT; | 819 | |
820 | local->power_constr_level = 0; | ||
874 | 821 | ||
875 | del_timer_sync(&local->dynamic_ps_timer); | 822 | del_timer_sync(&local->dynamic_ps_timer); |
876 | cancel_work_sync(&local->dynamic_ps_enable_work); | 823 | cancel_work_sync(&local->dynamic_ps_enable_work); |
@@ -885,7 +832,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
885 | 832 | ||
886 | rcu_read_lock(); | 833 | rcu_read_lock(); |
887 | 834 | ||
888 | sta = sta_info_get(local, ifsta->bssid); | 835 | sta = sta_info_get(local, ifmgd->bssid); |
889 | if (!sta) { | 836 | if (!sta) { |
890 | rcu_read_unlock(); | 837 | rcu_read_unlock(); |
891 | return; | 838 | return; |
@@ -906,27 +853,27 @@ static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | |||
906 | return 1; | 853 | return 1; |
907 | } | 854 | } |
908 | 855 | ||
909 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | 856 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) |
910 | struct ieee80211_if_sta *ifsta) | ||
911 | { | 857 | { |
858 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
912 | struct ieee80211_local *local = sdata->local; | 859 | struct ieee80211_local *local = sdata->local; |
913 | struct ieee80211_bss *bss; | 860 | struct ieee80211_bss *bss; |
914 | int bss_privacy; | 861 | int bss_privacy; |
915 | int wep_privacy; | 862 | int wep_privacy; |
916 | int privacy_invoked; | 863 | int privacy_invoked; |
917 | 864 | ||
918 | if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) | 865 | if (!ifmgd || (ifmgd->flags & IEEE80211_STA_EXT_SME)) |
919 | return 0; | 866 | return 0; |
920 | 867 | ||
921 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 868 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
922 | local->hw.conf.channel->center_freq, | 869 | local->hw.conf.channel->center_freq, |
923 | ifsta->ssid, ifsta->ssid_len); | 870 | ifmgd->ssid, ifmgd->ssid_len); |
924 | if (!bss) | 871 | if (!bss) |
925 | return 0; | 872 | return 0; |
926 | 873 | ||
927 | bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY); | 874 | bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY); |
928 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); | 875 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); |
929 | privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); | 876 | privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED); |
930 | 877 | ||
931 | ieee80211_rx_bss_put(local, bss); | 878 | ieee80211_rx_bss_put(local, bss); |
932 | 879 | ||
@@ -936,105 +883,173 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | |||
936 | return 1; | 883 | return 1; |
937 | } | 884 | } |
938 | 885 | ||
939 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, | 886 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) |
940 | struct ieee80211_if_sta *ifsta) | ||
941 | { | 887 | { |
942 | ifsta->assoc_tries++; | 888 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
943 | if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | 889 | struct ieee80211_local *local = sdata->local; |
890 | |||
891 | ifmgd->assoc_tries++; | ||
892 | if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
944 | printk(KERN_DEBUG "%s: association with AP %pM" | 893 | printk(KERN_DEBUG "%s: association with AP %pM" |
945 | " timed out\n", | 894 | " timed out\n", |
946 | sdata->dev->name, ifsta->bssid); | 895 | sdata->dev->name, ifmgd->bssid); |
947 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 896 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
948 | ieee80211_sta_send_apinfo(sdata, ifsta); | 897 | ieee80211_sta_send_apinfo(sdata); |
898 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | ||
899 | sdata->local->hw.conf.channel->center_freq, | ||
900 | ifmgd->ssid, ifmgd->ssid_len); | ||
901 | /* | ||
902 | * We might have a pending scan which had no chance to run yet | ||
903 | * due to state == IEEE80211_STA_MLME_ASSOCIATE. | ||
904 | * Hence, queue the STAs work again | ||
905 | */ | ||
906 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
949 | return; | 907 | return; |
950 | } | 908 | } |
951 | 909 | ||
952 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 910 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; |
953 | printk(KERN_DEBUG "%s: associate with AP %pM\n", | 911 | printk(KERN_DEBUG "%s: associate with AP %pM\n", |
954 | sdata->dev->name, ifsta->bssid); | 912 | sdata->dev->name, ifmgd->bssid); |
955 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | 913 | if (ieee80211_privacy_mismatch(sdata)) { |
956 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " | 914 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " |
957 | "mixed-cell disabled - abort association\n", sdata->dev->name); | 915 | "mixed-cell disabled - abort association\n", sdata->dev->name); |
958 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 916 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
959 | return; | 917 | return; |
960 | } | 918 | } |
961 | 919 | ||
962 | ieee80211_send_assoc(sdata, ifsta); | 920 | ieee80211_send_assoc(sdata); |
963 | 921 | ||
964 | mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); | 922 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); |
965 | } | 923 | } |
966 | 924 | ||
925 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | ||
926 | struct ieee80211_hdr *hdr) | ||
927 | { | ||
928 | /* | ||
929 | * We can postpone the mgd.timer whenever receiving unicast frames | ||
930 | * from AP because we know that the connection is working both ways | ||
931 | * at that time. But multicast frames (and hence also beacons) must | ||
932 | * be ignored here, because we need to trigger the timer during | ||
933 | * data idle periods for sending the periodical probe request to | ||
934 | * the AP. | ||
935 | */ | ||
936 | if (!is_multicast_ether_addr(hdr->addr1)) | ||
937 | mod_timer(&sdata->u.mgd.timer, | ||
938 | jiffies + IEEE80211_MONITORING_INTERVAL); | ||
939 | } | ||
967 | 940 | ||
968 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | 941 | void ieee80211_beacon_loss_work(struct work_struct *work) |
969 | struct ieee80211_if_sta *ifsta) | ||
970 | { | 942 | { |
943 | struct ieee80211_sub_if_data *sdata = | ||
944 | container_of(work, struct ieee80211_sub_if_data, | ||
945 | u.mgd.beacon_loss_work); | ||
946 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
947 | |||
948 | printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " | ||
949 | "- sending probe request\n", sdata->dev->name, | ||
950 | sdata->u.mgd.bssid); | ||
951 | |||
952 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
953 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
954 | ifmgd->ssid_len, NULL, 0); | ||
955 | |||
956 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); | ||
957 | } | ||
958 | |||
959 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | ||
960 | { | ||
961 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
962 | |||
963 | queue_work(sdata->local->hw.workqueue, | ||
964 | &sdata->u.mgd.beacon_loss_work); | ||
965 | } | ||
966 | EXPORT_SYMBOL(ieee80211_beacon_loss); | ||
967 | |||
968 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | ||
969 | { | ||
970 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
971 | struct ieee80211_local *local = sdata->local; | 971 | struct ieee80211_local *local = sdata->local; |
972 | struct sta_info *sta; | 972 | struct sta_info *sta; |
973 | int disassoc; | 973 | bool disassoc = false; |
974 | 974 | ||
975 | /* TODO: start monitoring current AP signal quality and number of | 975 | /* TODO: start monitoring current AP signal quality and number of |
976 | * missed beacons. Scan other channels every now and then and search | 976 | * missed beacons. Scan other channels every now and then and search |
977 | * for better APs. */ | 977 | * for better APs. */ |
978 | /* TODO: remove expired BSSes */ | 978 | /* TODO: remove expired BSSes */ |
979 | 979 | ||
980 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATED; | 980 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED; |
981 | 981 | ||
982 | rcu_read_lock(); | 982 | rcu_read_lock(); |
983 | 983 | ||
984 | sta = sta_info_get(local, ifsta->bssid); | 984 | sta = sta_info_get(local, ifmgd->bssid); |
985 | if (!sta) { | 985 | if (!sta) { |
986 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", | 986 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", |
987 | sdata->dev->name, ifsta->bssid); | 987 | sdata->dev->name, ifmgd->bssid); |
988 | disassoc = 1; | 988 | disassoc = true; |
989 | } else { | 989 | goto unlock; |
990 | disassoc = 0; | ||
991 | if (time_after(jiffies, | ||
992 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | ||
993 | if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { | ||
994 | printk(KERN_DEBUG "%s: No ProbeResp from " | ||
995 | "current AP %pM - assume out of " | ||
996 | "range\n", | ||
997 | sdata->dev->name, ifsta->bssid); | ||
998 | disassoc = 1; | ||
999 | } else | ||
1000 | ieee80211_send_probe_req(sdata, ifsta->bssid, | ||
1001 | ifsta->ssid, | ||
1002 | ifsta->ssid_len); | ||
1003 | ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; | ||
1004 | } else { | ||
1005 | ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
1006 | if (time_after(jiffies, ifsta->last_probe + | ||
1007 | IEEE80211_PROBE_INTERVAL)) { | ||
1008 | ifsta->last_probe = jiffies; | ||
1009 | ieee80211_send_probe_req(sdata, ifsta->bssid, | ||
1010 | ifsta->ssid, | ||
1011 | ifsta->ssid_len); | ||
1012 | } | ||
1013 | } | ||
1014 | } | 990 | } |
1015 | 991 | ||
992 | if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && | ||
993 | time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | ||
994 | printk(KERN_DEBUG "%s: no probe response from AP %pM " | ||
995 | "- disassociating\n", | ||
996 | sdata->dev->name, ifmgd->bssid); | ||
997 | disassoc = true; | ||
998 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
999 | goto unlock; | ||
1000 | } | ||
1001 | |||
1002 | /* | ||
1003 | * Beacon filtering is only enabled with power save and then the | ||
1004 | * stack should not check for beacon loss. | ||
1005 | */ | ||
1006 | if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) && | ||
1007 | (local->hw.conf.flags & IEEE80211_CONF_PS)) && | ||
1008 | time_after(jiffies, | ||
1009 | ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { | ||
1010 | printk(KERN_DEBUG "%s: beacon loss from AP %pM " | ||
1011 | "- sending probe request\n", | ||
1012 | sdata->dev->name, ifmgd->bssid); | ||
1013 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
1014 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
1015 | ifmgd->ssid_len, NULL, 0); | ||
1016 | goto unlock; | ||
1017 | |||
1018 | } | ||
1019 | |||
1020 | if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { | ||
1021 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
1022 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
1023 | ifmgd->ssid_len, NULL, 0); | ||
1024 | } | ||
1025 | |||
1026 | unlock: | ||
1016 | rcu_read_unlock(); | 1027 | rcu_read_unlock(); |
1017 | 1028 | ||
1018 | if (disassoc) | 1029 | if (disassoc) |
1019 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 1030 | ieee80211_set_disassoc(sdata, true, true, |
1020 | WLAN_REASON_PREV_AUTH_NOT_VALID); | 1031 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
1021 | else | 1032 | else |
1022 | mod_timer(&ifsta->timer, jiffies + | 1033 | mod_timer(&ifmgd->timer, jiffies + |
1023 | IEEE80211_MONITORING_INTERVAL); | 1034 | IEEE80211_MONITORING_INTERVAL); |
1024 | } | 1035 | } |
1025 | 1036 | ||
1026 | 1037 | ||
1027 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | 1038 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) |
1028 | struct ieee80211_if_sta *ifsta) | ||
1029 | { | 1039 | { |
1040 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1041 | |||
1030 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); | 1042 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); |
1031 | ifsta->flags |= IEEE80211_STA_AUTHENTICATED; | 1043 | ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; |
1032 | ieee80211_associate(sdata, ifsta); | 1044 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { |
1045 | /* Wait for SME to request association */ | ||
1046 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
1047 | } else | ||
1048 | ieee80211_associate(sdata); | ||
1033 | } | 1049 | } |
1034 | 1050 | ||
1035 | 1051 | ||
1036 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | 1052 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, |
1037 | struct ieee80211_if_sta *ifsta, | ||
1038 | struct ieee80211_mgmt *mgmt, | 1053 | struct ieee80211_mgmt *mgmt, |
1039 | size_t len) | 1054 | size_t len) |
1040 | { | 1055 | { |
@@ -1045,50 +1060,37 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1045 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 1060 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); |
1046 | if (!elems.challenge) | 1061 | if (!elems.challenge) |
1047 | return; | 1062 | return; |
1048 | ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2, | 1063 | ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg, |
1049 | elems.challenge_len + 2, 1); | 1064 | elems.challenge - 2, elems.challenge_len + 2, |
1065 | sdata->u.mgd.bssid, 1); | ||
1066 | sdata->u.mgd.auth_transaction = 4; | ||
1050 | } | 1067 | } |
1051 | 1068 | ||
1052 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 1069 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
1053 | struct ieee80211_if_sta *ifsta, | ||
1054 | struct ieee80211_mgmt *mgmt, | 1070 | struct ieee80211_mgmt *mgmt, |
1055 | size_t len) | 1071 | size_t len) |
1056 | { | 1072 | { |
1073 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1057 | u16 auth_alg, auth_transaction, status_code; | 1074 | u16 auth_alg, auth_transaction, status_code; |
1058 | 1075 | ||
1059 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 1076 | if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE) |
1060 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
1061 | return; | 1077 | return; |
1062 | 1078 | ||
1063 | if (len < 24 + 6) | 1079 | if (len < 24 + 6) |
1064 | return; | 1080 | return; |
1065 | 1081 | ||
1066 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1082 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) |
1067 | memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | ||
1068 | return; | 1083 | return; |
1069 | 1084 | ||
1070 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1085 | if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1071 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1072 | return; | 1086 | return; |
1073 | 1087 | ||
1074 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 1088 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
1075 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 1089 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
1076 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | 1090 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
1077 | 1091 | ||
1078 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1092 | if (auth_alg != ifmgd->auth_alg || |
1079 | /* | 1093 | auth_transaction != ifmgd->auth_transaction) |
1080 | * IEEE 802.11 standard does not require authentication in IBSS | ||
1081 | * networks and most implementations do not seem to use it. | ||
1082 | * However, try to reply to authentication attempts if someone | ||
1083 | * has actually implemented this. | ||
1084 | */ | ||
1085 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | ||
1086 | return; | ||
1087 | ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0); | ||
1088 | } | ||
1089 | |||
1090 | if (auth_alg != ifsta->auth_alg || | ||
1091 | auth_transaction != ifsta->auth_transaction) | ||
1092 | return; | 1094 | return; |
1093 | 1095 | ||
1094 | if (status_code != WLAN_STATUS_SUCCESS) { | 1096 | if (status_code != WLAN_STATUS_SUCCESS) { |
@@ -1097,15 +1099,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1097 | const int num_algs = ARRAY_SIZE(algs); | 1099 | const int num_algs = ARRAY_SIZE(algs); |
1098 | int i, pos; | 1100 | int i, pos; |
1099 | algs[0] = algs[1] = algs[2] = 0xff; | 1101 | algs[0] = algs[1] = algs[2] = 0xff; |
1100 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) | 1102 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) |
1101 | algs[0] = WLAN_AUTH_OPEN; | 1103 | algs[0] = WLAN_AUTH_OPEN; |
1102 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) | 1104 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) |
1103 | algs[1] = WLAN_AUTH_SHARED_KEY; | 1105 | algs[1] = WLAN_AUTH_SHARED_KEY; |
1104 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1106 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
1105 | algs[2] = WLAN_AUTH_LEAP; | 1107 | algs[2] = WLAN_AUTH_LEAP; |
1106 | if (ifsta->auth_alg == WLAN_AUTH_OPEN) | 1108 | if (ifmgd->auth_alg == WLAN_AUTH_OPEN) |
1107 | pos = 0; | 1109 | pos = 0; |
1108 | else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY) | 1110 | else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY) |
1109 | pos = 1; | 1111 | pos = 1; |
1110 | else | 1112 | else |
1111 | pos = 2; | 1113 | pos = 2; |
@@ -1113,105 +1115,112 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1113 | pos++; | 1115 | pos++; |
1114 | if (pos >= num_algs) | 1116 | if (pos >= num_algs) |
1115 | pos = 0; | 1117 | pos = 0; |
1116 | if (algs[pos] == ifsta->auth_alg || | 1118 | if (algs[pos] == ifmgd->auth_alg || |
1117 | algs[pos] == 0xff) | 1119 | algs[pos] == 0xff) |
1118 | continue; | 1120 | continue; |
1119 | if (algs[pos] == WLAN_AUTH_SHARED_KEY && | 1121 | if (algs[pos] == WLAN_AUTH_SHARED_KEY && |
1120 | !ieee80211_sta_wep_configured(sdata)) | 1122 | !ieee80211_sta_wep_configured(sdata)) |
1121 | continue; | 1123 | continue; |
1122 | ifsta->auth_alg = algs[pos]; | 1124 | ifmgd->auth_alg = algs[pos]; |
1123 | break; | 1125 | break; |
1124 | } | 1126 | } |
1125 | } | 1127 | } |
1126 | return; | 1128 | return; |
1127 | } | 1129 | } |
1128 | 1130 | ||
1129 | switch (ifsta->auth_alg) { | 1131 | switch (ifmgd->auth_alg) { |
1130 | case WLAN_AUTH_OPEN: | 1132 | case WLAN_AUTH_OPEN: |
1131 | case WLAN_AUTH_LEAP: | 1133 | case WLAN_AUTH_LEAP: |
1132 | ieee80211_auth_completed(sdata, ifsta); | 1134 | case WLAN_AUTH_FT: |
1135 | ieee80211_auth_completed(sdata); | ||
1136 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); | ||
1133 | break; | 1137 | break; |
1134 | case WLAN_AUTH_SHARED_KEY: | 1138 | case WLAN_AUTH_SHARED_KEY: |
1135 | if (ifsta->auth_transaction == 4) | 1139 | if (ifmgd->auth_transaction == 4) { |
1136 | ieee80211_auth_completed(sdata, ifsta); | 1140 | ieee80211_auth_completed(sdata); |
1137 | else | 1141 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); |
1138 | ieee80211_auth_challenge(sdata, ifsta, mgmt, len); | 1142 | } else |
1143 | ieee80211_auth_challenge(sdata, mgmt, len); | ||
1139 | break; | 1144 | break; |
1140 | } | 1145 | } |
1141 | } | 1146 | } |
1142 | 1147 | ||
1143 | 1148 | ||
1144 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1149 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1145 | struct ieee80211_if_sta *ifsta, | ||
1146 | struct ieee80211_mgmt *mgmt, | 1150 | struct ieee80211_mgmt *mgmt, |
1147 | size_t len) | 1151 | size_t len) |
1148 | { | 1152 | { |
1153 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1149 | u16 reason_code; | 1154 | u16 reason_code; |
1150 | 1155 | ||
1151 | if (len < 24 + 2) | 1156 | if (len < 24 + 2) |
1152 | return; | 1157 | return; |
1153 | 1158 | ||
1154 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) | 1159 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) |
1155 | return; | 1160 | return; |
1156 | 1161 | ||
1157 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 1162 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
1158 | 1163 | ||
1159 | if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) | 1164 | if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED) |
1160 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", | 1165 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", |
1161 | sdata->dev->name, reason_code); | 1166 | sdata->dev->name, reason_code); |
1162 | 1167 | ||
1163 | if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || | 1168 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
1164 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || | 1169 | (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || |
1165 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1170 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || |
1166 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1171 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) { |
1167 | mod_timer(&ifsta->timer, jiffies + | 1172 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
1173 | mod_timer(&ifmgd->timer, jiffies + | ||
1168 | IEEE80211_RETRY_AUTH_INTERVAL); | 1174 | IEEE80211_RETRY_AUTH_INTERVAL); |
1169 | } | 1175 | } |
1170 | 1176 | ||
1171 | ieee80211_set_disassoc(sdata, ifsta, true, false, 0); | 1177 | ieee80211_set_disassoc(sdata, true, false, 0); |
1172 | ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1178 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1179 | cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len); | ||
1173 | } | 1180 | } |
1174 | 1181 | ||
1175 | 1182 | ||
1176 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | 1183 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, |
1177 | struct ieee80211_if_sta *ifsta, | ||
1178 | struct ieee80211_mgmt *mgmt, | 1184 | struct ieee80211_mgmt *mgmt, |
1179 | size_t len) | 1185 | size_t len) |
1180 | { | 1186 | { |
1187 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1181 | u16 reason_code; | 1188 | u16 reason_code; |
1182 | 1189 | ||
1183 | if (len < 24 + 2) | 1190 | if (len < 24 + 2) |
1184 | return; | 1191 | return; |
1185 | 1192 | ||
1186 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) | 1193 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) |
1187 | return; | 1194 | return; |
1188 | 1195 | ||
1189 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 1196 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
1190 | 1197 | ||
1191 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 1198 | if (ifmgd->flags & IEEE80211_STA_ASSOCIATED) |
1192 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1199 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1193 | sdata->dev->name, reason_code); | 1200 | sdata->dev->name, reason_code); |
1194 | 1201 | ||
1195 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1202 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
1196 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 1203 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { |
1197 | mod_timer(&ifsta->timer, jiffies + | 1204 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; |
1205 | mod_timer(&ifmgd->timer, jiffies + | ||
1198 | IEEE80211_RETRY_AUTH_INTERVAL); | 1206 | IEEE80211_RETRY_AUTH_INTERVAL); |
1199 | } | 1207 | } |
1200 | 1208 | ||
1201 | ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code); | 1209 | ieee80211_set_disassoc(sdata, false, false, reason_code); |
1210 | cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len); | ||
1202 | } | 1211 | } |
1203 | 1212 | ||
1204 | 1213 | ||
1205 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 1214 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, |
1206 | struct ieee80211_if_sta *ifsta, | ||
1207 | struct ieee80211_mgmt *mgmt, | 1215 | struct ieee80211_mgmt *mgmt, |
1208 | size_t len, | 1216 | size_t len, |
1209 | int reassoc) | 1217 | int reassoc) |
1210 | { | 1218 | { |
1219 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1211 | struct ieee80211_local *local = sdata->local; | 1220 | struct ieee80211_local *local = sdata->local; |
1212 | struct ieee80211_supported_band *sband; | 1221 | struct ieee80211_supported_band *sband; |
1213 | struct sta_info *sta; | 1222 | struct sta_info *sta; |
1214 | u64 rates, basic_rates; | 1223 | u32 rates, basic_rates; |
1215 | u16 capab_info, status_code, aid; | 1224 | u16 capab_info, status_code, aid; |
1216 | struct ieee802_11_elems elems; | 1225 | struct ieee802_11_elems elems; |
1217 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 1226 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
@@ -1224,13 +1233,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1224 | /* AssocResp and ReassocResp have identical structure, so process both | 1233 | /* AssocResp and ReassocResp have identical structure, so process both |
1225 | * of them in this function. */ | 1234 | * of them in this function. */ |
1226 | 1235 | ||
1227 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATE) | 1236 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) |
1228 | return; | 1237 | return; |
1229 | 1238 | ||
1230 | if (len < 24 + 6) | 1239 | if (len < 24 + 6) |
1231 | return; | 1240 | return; |
1232 | 1241 | ||
1233 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | 1242 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) |
1234 | return; | 1243 | return; |
1235 | 1244 | ||
1236 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | 1245 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
@@ -1242,13 +1251,31 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1242 | sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, | 1251 | sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, |
1243 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | 1252 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); |
1244 | 1253 | ||
1254 | pos = mgmt->u.assoc_resp.variable; | ||
1255 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1256 | |||
1257 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
1258 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
1259 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
1260 | u32 tu, ms; | ||
1261 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
1262 | ms = tu * 1024 / 1000; | ||
1263 | printk(KERN_DEBUG "%s: AP rejected association temporarily; " | ||
1264 | "comeback duration %u TU (%u ms)\n", | ||
1265 | sdata->dev->name, tu, ms); | ||
1266 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
1267 | mod_timer(&ifmgd->timer, | ||
1268 | jiffies + msecs_to_jiffies(ms)); | ||
1269 | return; | ||
1270 | } | ||
1271 | |||
1245 | if (status_code != WLAN_STATUS_SUCCESS) { | 1272 | if (status_code != WLAN_STATUS_SUCCESS) { |
1246 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", | 1273 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", |
1247 | sdata->dev->name, status_code); | 1274 | sdata->dev->name, status_code); |
1248 | /* if this was a reassociation, ensure we try a "full" | 1275 | /* if this was a reassociation, ensure we try a "full" |
1249 | * association next time. This works around some broken APs | 1276 | * association next time. This works around some broken APs |
1250 | * which do not correctly reject reassociation requests. */ | 1277 | * which do not correctly reject reassociation requests. */ |
1251 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 1278 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
1252 | return; | 1279 | return; |
1253 | } | 1280 | } |
1254 | 1281 | ||
@@ -1257,9 +1284,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1257 | "set\n", sdata->dev->name, aid); | 1284 | "set\n", sdata->dev->name, aid); |
1258 | aid &= ~(BIT(15) | BIT(14)); | 1285 | aid &= ~(BIT(15) | BIT(14)); |
1259 | 1286 | ||
1260 | pos = mgmt->u.assoc_resp.variable; | ||
1261 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1262 | |||
1263 | if (!elems.supp_rates) { | 1287 | if (!elems.supp_rates) { |
1264 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", | 1288 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", |
1265 | sdata->dev->name); | 1289 | sdata->dev->name); |
@@ -1267,40 +1291,29 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1267 | } | 1291 | } |
1268 | 1292 | ||
1269 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); | 1293 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); |
1270 | ifsta->aid = aid; | 1294 | ifmgd->aid = aid; |
1271 | ifsta->ap_capab = capab_info; | 1295 | ifmgd->ap_capab = capab_info; |
1272 | 1296 | ||
1273 | kfree(ifsta->assocresp_ies); | 1297 | kfree(ifmgd->assocresp_ies); |
1274 | ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); | 1298 | ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt); |
1275 | ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); | 1299 | ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL); |
1276 | if (ifsta->assocresp_ies) | 1300 | if (ifmgd->assocresp_ies) |
1277 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); | 1301 | memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len); |
1278 | 1302 | ||
1279 | rcu_read_lock(); | 1303 | rcu_read_lock(); |
1280 | 1304 | ||
1281 | /* Add STA entry for the AP */ | 1305 | /* Add STA entry for the AP */ |
1282 | sta = sta_info_get(local, ifsta->bssid); | 1306 | sta = sta_info_get(local, ifmgd->bssid); |
1283 | if (!sta) { | 1307 | if (!sta) { |
1284 | struct ieee80211_bss *bss; | ||
1285 | |||
1286 | newsta = true; | 1308 | newsta = true; |
1287 | 1309 | ||
1288 | sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); | 1310 | sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC); |
1289 | if (!sta) { | 1311 | if (!sta) { |
1290 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | 1312 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" |
1291 | " the AP\n", sdata->dev->name); | 1313 | " the AP\n", sdata->dev->name); |
1292 | rcu_read_unlock(); | 1314 | rcu_read_unlock(); |
1293 | return; | 1315 | return; |
1294 | } | 1316 | } |
1295 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | ||
1296 | local->hw.conf.channel->center_freq, | ||
1297 | ifsta->ssid, ifsta->ssid_len); | ||
1298 | if (bss) { | ||
1299 | sta->last_signal = bss->signal; | ||
1300 | sta->last_qual = bss->qual; | ||
1301 | sta->last_noise = bss->noise; | ||
1302 | ieee80211_rx_bss_put(local, bss); | ||
1303 | } | ||
1304 | 1317 | ||
1305 | /* update new sta with its last rx activity */ | 1318 | /* update new sta with its last rx activity */ |
1306 | sta->last_rx = jiffies; | 1319 | sta->last_rx = jiffies; |
@@ -1367,7 +1380,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1367 | else | 1380 | else |
1368 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 1381 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
1369 | 1382 | ||
1370 | if (elems.ht_cap_elem) | 1383 | /* If TKIP/WEP is used, no need to parse AP's HT capabilities */ |
1384 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) | ||
1371 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1385 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, |
1372 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1386 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1373 | 1387 | ||
@@ -1375,6 +1389,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1375 | 1389 | ||
1376 | rate_control_rate_init(sta); | 1390 | rate_control_rate_init(sta); |
1377 | 1391 | ||
1392 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) | ||
1393 | set_sta_flags(sta, WLAN_STA_MFP); | ||
1394 | |||
1378 | if (elems.wmm_param) | 1395 | if (elems.wmm_param) |
1379 | set_sta_flags(sta, WLAN_STA_WME); | 1396 | set_sta_flags(sta, WLAN_STA_WME); |
1380 | 1397 | ||
@@ -1391,11 +1408,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1391 | rcu_read_unlock(); | 1408 | rcu_read_unlock(); |
1392 | 1409 | ||
1393 | if (elems.wmm_param) | 1410 | if (elems.wmm_param) |
1394 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1411 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
1395 | elems.wmm_param_len); | 1412 | elems.wmm_param_len); |
1396 | 1413 | ||
1397 | if (elems.ht_info_elem && elems.wmm_param && | 1414 | if (elems.ht_info_elem && elems.wmm_param && |
1398 | (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) | 1415 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && |
1416 | !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) | ||
1399 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1417 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1400 | ap_ht_cap_flags); | 1418 | ap_ht_cap_flags); |
1401 | 1419 | ||
@@ -1403,136 +1421,19 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1403 | * ieee80211_set_associated() will tell the driver */ | 1421 | * ieee80211_set_associated() will tell the driver */ |
1404 | bss_conf->aid = aid; | 1422 | bss_conf->aid = aid; |
1405 | bss_conf->assoc_capability = capab_info; | 1423 | bss_conf->assoc_capability = capab_info; |
1406 | ieee80211_set_associated(sdata, ifsta, changed); | 1424 | ieee80211_set_associated(sdata, changed); |
1407 | |||
1408 | ieee80211_associated(sdata, ifsta); | ||
1409 | } | ||
1410 | |||
1411 | |||
1412 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||
1413 | struct ieee80211_if_sta *ifsta, | ||
1414 | struct ieee80211_bss *bss) | ||
1415 | { | ||
1416 | struct ieee80211_local *local = sdata->local; | ||
1417 | int res, rates, i, j; | ||
1418 | struct sk_buff *skb; | ||
1419 | struct ieee80211_mgmt *mgmt; | ||
1420 | u8 *pos; | ||
1421 | struct ieee80211_supported_band *sband; | ||
1422 | union iwreq_data wrqu; | ||
1423 | |||
1424 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | ||
1425 | if (!skb) { | ||
1426 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
1427 | "response\n", sdata->dev->name); | ||
1428 | return -ENOMEM; | ||
1429 | } | ||
1430 | |||
1431 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1432 | |||
1433 | /* Remove possible STA entries from other IBSS networks. */ | ||
1434 | sta_info_flush_delayed(sdata); | ||
1435 | |||
1436 | if (local->ops->reset_tsf) { | ||
1437 | /* Reset own TSF to allow time synchronization work. */ | ||
1438 | local->ops->reset_tsf(local_to_hw(local)); | ||
1439 | } | ||
1440 | memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); | ||
1441 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
1442 | if (res) | ||
1443 | return res; | ||
1444 | |||
1445 | local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; | ||
1446 | |||
1447 | sdata->drop_unencrypted = bss->capability & | ||
1448 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
1449 | |||
1450 | res = ieee80211_set_freq(sdata, bss->freq); | ||
1451 | |||
1452 | if (res) | ||
1453 | return res; | ||
1454 | |||
1455 | /* Build IBSS probe response */ | ||
1456 | 1425 | ||
1457 | skb_reserve(skb, local->hw.extra_tx_headroom); | 1426 | /* |
1458 | 1427 | * initialise the time of last beacon to be the association time, | |
1459 | mgmt = (struct ieee80211_mgmt *) | 1428 | * otherwise beacon loss check will trigger immediately |
1460 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | 1429 | */ |
1461 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | 1430 | ifmgd->last_beacon = jiffies; |
1462 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1463 | IEEE80211_STYPE_PROBE_RESP); | ||
1464 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1465 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1466 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
1467 | mgmt->u.beacon.beacon_int = | ||
1468 | cpu_to_le16(local->hw.conf.beacon_int); | ||
1469 | mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp); | ||
1470 | mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); | ||
1471 | |||
1472 | pos = skb_put(skb, 2 + ifsta->ssid_len); | ||
1473 | *pos++ = WLAN_EID_SSID; | ||
1474 | *pos++ = ifsta->ssid_len; | ||
1475 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | ||
1476 | |||
1477 | rates = bss->supp_rates_len; | ||
1478 | if (rates > 8) | ||
1479 | rates = 8; | ||
1480 | pos = skb_put(skb, 2 + rates); | ||
1481 | *pos++ = WLAN_EID_SUPP_RATES; | ||
1482 | *pos++ = rates; | ||
1483 | memcpy(pos, bss->supp_rates, rates); | ||
1484 | |||
1485 | if (bss->band == IEEE80211_BAND_2GHZ) { | ||
1486 | pos = skb_put(skb, 2 + 1); | ||
1487 | *pos++ = WLAN_EID_DS_PARAMS; | ||
1488 | *pos++ = 1; | ||
1489 | *pos++ = ieee80211_frequency_to_channel(bss->freq); | ||
1490 | } | ||
1491 | |||
1492 | pos = skb_put(skb, 2 + 2); | ||
1493 | *pos++ = WLAN_EID_IBSS_PARAMS; | ||
1494 | *pos++ = 2; | ||
1495 | /* FIX: set ATIM window based on scan results */ | ||
1496 | *pos++ = 0; | ||
1497 | *pos++ = 0; | ||
1498 | |||
1499 | if (bss->supp_rates_len > 8) { | ||
1500 | rates = bss->supp_rates_len - 8; | ||
1501 | pos = skb_put(skb, 2 + rates); | ||
1502 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
1503 | *pos++ = rates; | ||
1504 | memcpy(pos, &bss->supp_rates[8], rates); | ||
1505 | } | ||
1506 | |||
1507 | ifsta->probe_resp = skb; | ||
1508 | |||
1509 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | ||
1510 | |||
1511 | |||
1512 | rates = 0; | ||
1513 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1514 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
1515 | int bitrate = (bss->supp_rates[i] & 0x7f) * 5; | ||
1516 | for (j = 0; j < sband->n_bitrates; j++) | ||
1517 | if (sband->bitrates[j].bitrate == bitrate) | ||
1518 | rates |= BIT(j); | ||
1519 | } | ||
1520 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; | ||
1521 | |||
1522 | ieee80211_sta_def_wmm_params(sdata, bss); | ||
1523 | |||
1524 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; | ||
1525 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
1526 | |||
1527 | ieee80211_led_assoc(local, true); | ||
1528 | |||
1529 | memset(&wrqu, 0, sizeof(wrqu)); | ||
1530 | memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN); | ||
1531 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | ||
1532 | 1431 | ||
1533 | return res; | 1432 | ieee80211_associated(sdata); |
1433 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); | ||
1534 | } | 1434 | } |
1535 | 1435 | ||
1436 | |||
1536 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 1437 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
1537 | struct ieee80211_mgmt *mgmt, | 1438 | struct ieee80211_mgmt *mgmt, |
1538 | size_t len, | 1439 | size_t len, |
@@ -1543,11 +1444,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1543 | struct ieee80211_local *local = sdata->local; | 1444 | struct ieee80211_local *local = sdata->local; |
1544 | int freq; | 1445 | int freq; |
1545 | struct ieee80211_bss *bss; | 1446 | struct ieee80211_bss *bss; |
1546 | struct sta_info *sta; | ||
1547 | struct ieee80211_channel *channel; | 1447 | struct ieee80211_channel *channel; |
1548 | u64 beacon_timestamp, rx_timestamp; | ||
1549 | u64 supp_rates = 0; | ||
1550 | enum ieee80211_band band = rx_status->band; | ||
1551 | 1448 | ||
1552 | if (elems->ds_params && elems->ds_params_len == 1) | 1449 | if (elems->ds_params && elems->ds_params_len == 1) |
1553 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | 1450 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); |
@@ -1559,112 +1456,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1559 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 1456 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
1560 | return; | 1457 | return; |
1561 | 1458 | ||
1562 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && | ||
1563 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { | ||
1564 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
1565 | |||
1566 | rcu_read_lock(); | ||
1567 | |||
1568 | sta = sta_info_get(local, mgmt->sa); | ||
1569 | if (sta) { | ||
1570 | u64 prev_rates; | ||
1571 | |||
1572 | prev_rates = sta->sta.supp_rates[band]; | ||
1573 | /* make sure mandatory rates are always added */ | ||
1574 | sta->sta.supp_rates[band] = supp_rates | | ||
1575 | ieee80211_mandatory_rates(local, band); | ||
1576 | |||
1577 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1578 | if (sta->sta.supp_rates[band] != prev_rates) | ||
1579 | printk(KERN_DEBUG "%s: updated supp_rates set " | ||
1580 | "for %pM based on beacon info (0x%llx | " | ||
1581 | "0x%llx -> 0x%llx)\n", | ||
1582 | sdata->dev->name, | ||
1583 | sta->sta.addr, | ||
1584 | (unsigned long long) prev_rates, | ||
1585 | (unsigned long long) supp_rates, | ||
1586 | (unsigned long long) sta->sta.supp_rates[band]); | ||
1587 | #endif | ||
1588 | } else { | ||
1589 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
1590 | } | ||
1591 | |||
1592 | rcu_read_unlock(); | ||
1593 | } | ||
1594 | |||
1595 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 1459 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
1596 | freq, beacon); | 1460 | channel, beacon); |
1597 | if (!bss) | 1461 | if (!bss) |
1598 | return; | 1462 | return; |
1599 | 1463 | ||
1600 | /* was just updated in ieee80211_bss_info_update */ | 1464 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && |
1601 | beacon_timestamp = bss->timestamp; | 1465 | (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { |
1602 | 1466 | struct ieee80211_channel_sw_ie *sw_elem = | |
1603 | /* | 1467 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
1604 | * In STA mode, the remaining parameters should not be overridden | 1468 | ieee80211_process_chanswitch(sdata, sw_elem, bss); |
1605 | * by beacons because they're not necessarily accurate there. | ||
1606 | */ | ||
1607 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | ||
1608 | bss->last_probe_resp && beacon) { | ||
1609 | ieee80211_rx_bss_put(local, bss); | ||
1610 | return; | ||
1611 | } | ||
1612 | |||
1613 | /* check if we need to merge IBSS */ | ||
1614 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon && | ||
1615 | bss->capability & WLAN_CAPABILITY_IBSS && | ||
1616 | bss->freq == local->oper_channel->center_freq && | ||
1617 | elems->ssid_len == sdata->u.sta.ssid_len && | ||
1618 | memcmp(elems->ssid, sdata->u.sta.ssid, | ||
1619 | sdata->u.sta.ssid_len) == 0) { | ||
1620 | if (rx_status->flag & RX_FLAG_TSFT) { | ||
1621 | /* in order for correct IBSS merging we need mactime | ||
1622 | * | ||
1623 | * since mactime is defined as the time the first data | ||
1624 | * symbol of the frame hits the PHY, and the timestamp | ||
1625 | * of the beacon is defined as "the time that the data | ||
1626 | * symbol containing the first bit of the timestamp is | ||
1627 | * transmitted to the PHY plus the transmitting STA’s | ||
1628 | * delays through its local PHY from the MAC-PHY | ||
1629 | * interface to its interface with the WM" | ||
1630 | * (802.11 11.1.2) - equals the time this bit arrives at | ||
1631 | * the receiver - we have to take into account the | ||
1632 | * offset between the two. | ||
1633 | * e.g: at 1 MBit that means mactime is 192 usec earlier | ||
1634 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | ||
1635 | */ | ||
1636 | int rate; | ||
1637 | if (rx_status->flag & RX_FLAG_HT) { | ||
1638 | rate = 65; /* TODO: HT rates */ | ||
1639 | } else { | ||
1640 | rate = local->hw.wiphy->bands[band]-> | ||
1641 | bitrates[rx_status->rate_idx].bitrate; | ||
1642 | } | ||
1643 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
1644 | } else if (local && local->ops && local->ops->get_tsf) | ||
1645 | /* second best option: get current TSF */ | ||
1646 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | ||
1647 | else | ||
1648 | /* can't merge without knowing the TSF */ | ||
1649 | rx_timestamp = -1LLU; | ||
1650 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1651 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | ||
1652 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | ||
1653 | mgmt->sa, mgmt->bssid, | ||
1654 | (unsigned long long)rx_timestamp, | ||
1655 | (unsigned long long)beacon_timestamp, | ||
1656 | (unsigned long long)(rx_timestamp - beacon_timestamp), | ||
1657 | jiffies); | ||
1658 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
1659 | if (beacon_timestamp > rx_timestamp) { | ||
1660 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1661 | printk(KERN_DEBUG "%s: beacon TSF higher than " | ||
1662 | "local TSF - IBSS merge with BSSID %pM\n", | ||
1663 | sdata->dev->name, mgmt->bssid); | ||
1664 | #endif | ||
1665 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); | ||
1666 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
1667 | } | ||
1668 | } | 1469 | } |
1669 | 1470 | ||
1670 | ieee80211_rx_bss_put(local, bss); | 1471 | ieee80211_rx_bss_put(local, bss); |
@@ -1676,9 +1477,11 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1676 | size_t len, | 1477 | size_t len, |
1677 | struct ieee80211_rx_status *rx_status) | 1478 | struct ieee80211_rx_status *rx_status) |
1678 | { | 1479 | { |
1480 | struct ieee80211_if_managed *ifmgd; | ||
1679 | size_t baselen; | 1481 | size_t baselen; |
1680 | struct ieee802_11_elems elems; | 1482 | struct ieee802_11_elems elems; |
1681 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1483 | |
1484 | ifmgd = &sdata->u.mgd; | ||
1682 | 1485 | ||
1683 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 1486 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) |
1684 | return; /* ignore ProbeResp to foreign address */ | 1487 | return; /* ignore ProbeResp to foreign address */ |
@@ -1694,25 +1497,27 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1694 | 1497 | ||
1695 | /* direct probe may be part of the association flow */ | 1498 | /* direct probe may be part of the association flow */ |
1696 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 1499 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, |
1697 | &ifsta->request)) { | 1500 | &ifmgd->request)) { |
1698 | printk(KERN_DEBUG "%s direct probe responded\n", | 1501 | printk(KERN_DEBUG "%s direct probe responded\n", |
1699 | sdata->dev->name); | 1502 | sdata->dev->name); |
1700 | ieee80211_authenticate(sdata, ifsta); | 1503 | ieee80211_authenticate(sdata); |
1701 | } | 1504 | } |
1702 | } | ||
1703 | 1505 | ||
1506 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) | ||
1507 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
1508 | } | ||
1704 | 1509 | ||
1705 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 1510 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
1706 | struct ieee80211_mgmt *mgmt, | 1511 | struct ieee80211_mgmt *mgmt, |
1707 | size_t len, | 1512 | size_t len, |
1708 | struct ieee80211_rx_status *rx_status) | 1513 | struct ieee80211_rx_status *rx_status) |
1709 | { | 1514 | { |
1710 | struct ieee80211_if_sta *ifsta; | 1515 | struct ieee80211_if_managed *ifmgd; |
1711 | size_t baselen; | 1516 | size_t baselen; |
1712 | struct ieee802_11_elems elems; | 1517 | struct ieee802_11_elems elems; |
1713 | struct ieee80211_local *local = sdata->local; | 1518 | struct ieee80211_local *local = sdata->local; |
1714 | u32 changed = 0; | 1519 | u32 changed = 0; |
1715 | bool erp_valid; | 1520 | bool erp_valid, directed_tim; |
1716 | u8 erp_value = 0; | 1521 | u8 erp_value = 0; |
1717 | 1522 | ||
1718 | /* Process beacon from the current BSS */ | 1523 | /* Process beacon from the current BSS */ |
@@ -1726,15 +1531,43 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1726 | 1531 | ||
1727 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1532 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
1728 | return; | 1533 | return; |
1729 | ifsta = &sdata->u.sta; | ||
1730 | 1534 | ||
1731 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || | 1535 | ifmgd = &sdata->u.mgd; |
1732 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1536 | |
1537 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || | ||
1538 | memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1539 | return; | ||
1540 | |||
1541 | if (rx_status->freq != local->hw.conf.channel->center_freq) | ||
1733 | return; | 1542 | return; |
1734 | 1543 | ||
1735 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1544 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
1736 | elems.wmm_param_len); | 1545 | elems.wmm_param_len); |
1737 | 1546 | ||
1547 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { | ||
1548 | directed_tim = ieee80211_check_tim(&elems, ifmgd->aid); | ||
1549 | |||
1550 | if (directed_tim) { | ||
1551 | if (local->hw.conf.dynamic_ps_timeout > 0) { | ||
1552 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
1553 | ieee80211_hw_config(local, | ||
1554 | IEEE80211_CONF_CHANGE_PS); | ||
1555 | ieee80211_send_nullfunc(local, sdata, 0); | ||
1556 | } else { | ||
1557 | local->pspolling = true; | ||
1558 | |||
1559 | /* | ||
1560 | * Here is assumed that the driver will be | ||
1561 | * able to send ps-poll frame and receive a | ||
1562 | * response even though power save mode is | ||
1563 | * enabled, but some drivers might require | ||
1564 | * to disable power save here. This needs | ||
1565 | * to be investigated. | ||
1566 | */ | ||
1567 | ieee80211_send_pspoll(local, sdata); | ||
1568 | } | ||
1569 | } | ||
1570 | } | ||
1738 | 1571 | ||
1739 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1572 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1740 | erp_valid = true; | 1573 | erp_valid = true; |
@@ -1747,14 +1580,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1747 | erp_valid, erp_value); | 1580 | erp_valid, erp_value); |
1748 | 1581 | ||
1749 | 1582 | ||
1750 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { | 1583 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && |
1584 | !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) { | ||
1751 | struct sta_info *sta; | 1585 | struct sta_info *sta; |
1752 | struct ieee80211_supported_band *sband; | 1586 | struct ieee80211_supported_band *sband; |
1753 | u16 ap_ht_cap_flags; | 1587 | u16 ap_ht_cap_flags; |
1754 | 1588 | ||
1755 | rcu_read_lock(); | 1589 | rcu_read_lock(); |
1756 | 1590 | ||
1757 | sta = sta_info_get(local, ifsta->bssid); | 1591 | sta = sta_info_get(local, ifmgd->bssid); |
1758 | if (!sta) { | 1592 | if (!sta) { |
1759 | rcu_read_unlock(); | 1593 | rcu_read_unlock(); |
1760 | return; | 1594 | return; |
@@ -1778,92 +1612,28 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1778 | * for the BSSID we are associated to */ | 1612 | * for the BSSID we are associated to */ |
1779 | regulatory_hint_11d(local->hw.wiphy, | 1613 | regulatory_hint_11d(local->hw.wiphy, |
1780 | elems.country_elem, elems.country_elem_len); | 1614 | elems.country_elem, elems.country_elem_len); |
1781 | } | ||
1782 | |||
1783 | ieee80211_bss_info_change_notify(sdata, changed); | ||
1784 | } | ||
1785 | |||
1786 | |||
1787 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | ||
1788 | struct ieee80211_if_sta *ifsta, | ||
1789 | struct ieee80211_mgmt *mgmt, | ||
1790 | size_t len, | ||
1791 | struct ieee80211_rx_status *rx_status) | ||
1792 | { | ||
1793 | struct ieee80211_local *local = sdata->local; | ||
1794 | int tx_last_beacon; | ||
1795 | struct sk_buff *skb; | ||
1796 | struct ieee80211_mgmt *resp; | ||
1797 | u8 *pos, *end; | ||
1798 | 1615 | ||
1799 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC || | 1616 | /* TODO: IBSS also needs this */ |
1800 | ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || | 1617 | if (elems.pwr_constr_elem) |
1801 | len < 24 + 2 || !ifsta->probe_resp) | 1618 | ieee80211_handle_pwr_constr(sdata, |
1802 | return; | 1619 | le16_to_cpu(mgmt->u.probe_resp.capab_info), |
1803 | 1620 | elems.pwr_constr_elem, | |
1804 | if (local->ops->tx_last_beacon) | 1621 | elems.pwr_constr_elem_len); |
1805 | tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); | ||
1806 | else | ||
1807 | tx_last_beacon = 1; | ||
1808 | |||
1809 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1810 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" | ||
1811 | " (tx_last_beacon=%d)\n", | ||
1812 | sdata->dev->name, mgmt->sa, mgmt->da, | ||
1813 | mgmt->bssid, tx_last_beacon); | ||
1814 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
1815 | |||
1816 | if (!tx_last_beacon) | ||
1817 | return; | ||
1818 | |||
1819 | if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 && | ||
1820 | memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) | ||
1821 | return; | ||
1822 | |||
1823 | end = ((u8 *) mgmt) + len; | ||
1824 | pos = mgmt->u.probe_req.variable; | ||
1825 | if (pos[0] != WLAN_EID_SSID || | ||
1826 | pos + 2 + pos[1] > end) { | ||
1827 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1828 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " | ||
1829 | "from %pM\n", | ||
1830 | sdata->dev->name, mgmt->sa); | ||
1831 | #endif | ||
1832 | return; | ||
1833 | } | 1622 | } |
1834 | if (pos[1] != 0 && | ||
1835 | (pos[1] != ifsta->ssid_len || | ||
1836 | memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) { | ||
1837 | /* Ignore ProbeReq for foreign SSID */ | ||
1838 | return; | ||
1839 | } | ||
1840 | |||
1841 | /* Reply with ProbeResp */ | ||
1842 | skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); | ||
1843 | if (!skb) | ||
1844 | return; | ||
1845 | 1623 | ||
1846 | resp = (struct ieee80211_mgmt *) skb->data; | 1624 | ieee80211_bss_info_change_notify(sdata, changed); |
1847 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | ||
1848 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1849 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", | ||
1850 | sdata->dev->name, resp->da); | ||
1851 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
1852 | ieee80211_tx_skb(sdata, skb, 0); | ||
1853 | } | 1625 | } |
1854 | 1626 | ||
1855 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 1627 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, |
1856 | struct ieee80211_rx_status *rx_status) | 1628 | struct sk_buff *skb, |
1629 | struct ieee80211_rx_status *rx_status) | ||
1857 | { | 1630 | { |
1858 | struct ieee80211_local *local = sdata->local; | 1631 | struct ieee80211_local *local = sdata->local; |
1859 | struct ieee80211_if_sta *ifsta; | ||
1860 | struct ieee80211_mgmt *mgmt; | 1632 | struct ieee80211_mgmt *mgmt; |
1861 | u16 fc; | 1633 | u16 fc; |
1862 | 1634 | ||
1863 | if (skb->len < 24) | 1635 | if (skb->len < 24) |
1864 | goto fail; | 1636 | return RX_DROP_MONITOR; |
1865 | |||
1866 | ifsta = &sdata->u.sta; | ||
1867 | 1637 | ||
1868 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1638 | mgmt = (struct ieee80211_mgmt *) skb->data; |
1869 | fc = le16_to_cpu(mgmt->frame_control); | 1639 | fc = le16_to_cpu(mgmt->frame_control); |
@@ -1878,113 +1648,68 @@ void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff * | |||
1878 | case IEEE80211_STYPE_REASSOC_RESP: | 1648 | case IEEE80211_STYPE_REASSOC_RESP: |
1879 | case IEEE80211_STYPE_DEAUTH: | 1649 | case IEEE80211_STYPE_DEAUTH: |
1880 | case IEEE80211_STYPE_DISASSOC: | 1650 | case IEEE80211_STYPE_DISASSOC: |
1881 | skb_queue_tail(&ifsta->skb_queue, skb); | 1651 | skb_queue_tail(&sdata->u.mgd.skb_queue, skb); |
1882 | queue_work(local->hw.workqueue, &ifsta->work); | 1652 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); |
1883 | return; | 1653 | return RX_QUEUED; |
1884 | } | 1654 | } |
1885 | 1655 | ||
1886 | fail: | 1656 | return RX_DROP_MONITOR; |
1887 | kfree_skb(skb); | ||
1888 | } | 1657 | } |
1889 | 1658 | ||
1890 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1659 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1891 | struct sk_buff *skb) | 1660 | struct sk_buff *skb) |
1892 | { | 1661 | { |
1893 | struct ieee80211_rx_status *rx_status; | 1662 | struct ieee80211_rx_status *rx_status; |
1894 | struct ieee80211_if_sta *ifsta; | ||
1895 | struct ieee80211_mgmt *mgmt; | 1663 | struct ieee80211_mgmt *mgmt; |
1896 | u16 fc; | 1664 | u16 fc; |
1897 | 1665 | ||
1898 | ifsta = &sdata->u.sta; | ||
1899 | |||
1900 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 1666 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
1901 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1667 | mgmt = (struct ieee80211_mgmt *) skb->data; |
1902 | fc = le16_to_cpu(mgmt->frame_control); | 1668 | fc = le16_to_cpu(mgmt->frame_control); |
1903 | 1669 | ||
1904 | switch (fc & IEEE80211_FCTL_STYPE) { | 1670 | switch (fc & IEEE80211_FCTL_STYPE) { |
1905 | case IEEE80211_STYPE_PROBE_REQ: | ||
1906 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len, | ||
1907 | rx_status); | ||
1908 | break; | ||
1909 | case IEEE80211_STYPE_PROBE_RESP: | 1671 | case IEEE80211_STYPE_PROBE_RESP: |
1910 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); | 1672 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, |
1673 | rx_status); | ||
1911 | break; | 1674 | break; |
1912 | case IEEE80211_STYPE_BEACON: | 1675 | case IEEE80211_STYPE_BEACON: |
1913 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); | 1676 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
1677 | rx_status); | ||
1914 | break; | 1678 | break; |
1915 | case IEEE80211_STYPE_AUTH: | 1679 | case IEEE80211_STYPE_AUTH: |
1916 | ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len); | 1680 | ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); |
1917 | break; | 1681 | break; |
1918 | case IEEE80211_STYPE_ASSOC_RESP: | 1682 | case IEEE80211_STYPE_ASSOC_RESP: |
1919 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0); | 1683 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0); |
1920 | break; | 1684 | break; |
1921 | case IEEE80211_STYPE_REASSOC_RESP: | 1685 | case IEEE80211_STYPE_REASSOC_RESP: |
1922 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1); | 1686 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1); |
1923 | break; | 1687 | break; |
1924 | case IEEE80211_STYPE_DEAUTH: | 1688 | case IEEE80211_STYPE_DEAUTH: |
1925 | ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len); | 1689 | ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
1926 | break; | 1690 | break; |
1927 | case IEEE80211_STYPE_DISASSOC: | 1691 | case IEEE80211_STYPE_DISASSOC: |
1928 | ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len); | 1692 | ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
1929 | break; | 1693 | break; |
1930 | } | 1694 | } |
1931 | 1695 | ||
1932 | kfree_skb(skb); | 1696 | kfree_skb(skb); |
1933 | } | 1697 | } |
1934 | 1698 | ||
1935 | |||
1936 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
1937 | { | ||
1938 | struct ieee80211_local *local = sdata->local; | ||
1939 | int active = 0; | ||
1940 | struct sta_info *sta; | ||
1941 | |||
1942 | rcu_read_lock(); | ||
1943 | |||
1944 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
1945 | if (sta->sdata == sdata && | ||
1946 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
1947 | jiffies)) { | ||
1948 | active++; | ||
1949 | break; | ||
1950 | } | ||
1951 | } | ||
1952 | |||
1953 | rcu_read_unlock(); | ||
1954 | |||
1955 | return active; | ||
1956 | } | ||
1957 | |||
1958 | |||
1959 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata, | ||
1960 | struct ieee80211_if_sta *ifsta) | ||
1961 | { | ||
1962 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
1963 | |||
1964 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | ||
1965 | if (ieee80211_sta_active_ibss(sdata)) | ||
1966 | return; | ||
1967 | |||
1968 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | ||
1969 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | ||
1970 | ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len); | ||
1971 | } | ||
1972 | |||
1973 | |||
1974 | static void ieee80211_sta_timer(unsigned long data) | 1699 | static void ieee80211_sta_timer(unsigned long data) |
1975 | { | 1700 | { |
1976 | struct ieee80211_sub_if_data *sdata = | 1701 | struct ieee80211_sub_if_data *sdata = |
1977 | (struct ieee80211_sub_if_data *) data; | 1702 | (struct ieee80211_sub_if_data *) data; |
1978 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1703 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1979 | struct ieee80211_local *local = sdata->local; | 1704 | struct ieee80211_local *local = sdata->local; |
1980 | 1705 | ||
1981 | set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | 1706 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
1982 | queue_work(local->hw.workqueue, &ifsta->work); | 1707 | queue_work(local->hw.workqueue, &ifmgd->work); |
1983 | } | 1708 | } |
1984 | 1709 | ||
1985 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | 1710 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) |
1986 | struct ieee80211_if_sta *ifsta) | ||
1987 | { | 1711 | { |
1712 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1988 | struct ieee80211_local *local = sdata->local; | 1713 | struct ieee80211_local *local = sdata->local; |
1989 | 1714 | ||
1990 | if (local->ops->reset_tsf) { | 1715 | if (local->ops->reset_tsf) { |
@@ -1992,298 +1717,112 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | |||
1992 | local->ops->reset_tsf(local_to_hw(local)); | 1717 | local->ops->reset_tsf(local_to_hw(local)); |
1993 | } | 1718 | } |
1994 | 1719 | ||
1995 | ifsta->wmm_last_param_set = -1; /* allow any WMM update */ | 1720 | ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ |
1996 | 1721 | ||
1997 | 1722 | ||
1998 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) | 1723 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) |
1999 | ifsta->auth_alg = WLAN_AUTH_OPEN; | 1724 | ifmgd->auth_alg = WLAN_AUTH_OPEN; |
2000 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) | 1725 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) |
2001 | ifsta->auth_alg = WLAN_AUTH_SHARED_KEY; | 1726 | ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; |
2002 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1727 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
2003 | ifsta->auth_alg = WLAN_AUTH_LEAP; | 1728 | ifmgd->auth_alg = WLAN_AUTH_LEAP; |
1729 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_FT) | ||
1730 | ifmgd->auth_alg = WLAN_AUTH_FT; | ||
2004 | else | 1731 | else |
2005 | ifsta->auth_alg = WLAN_AUTH_OPEN; | 1732 | ifmgd->auth_alg = WLAN_AUTH_OPEN; |
2006 | ifsta->auth_transaction = -1; | 1733 | ifmgd->auth_transaction = -1; |
2007 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 1734 | ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; |
2008 | ifsta->assoc_scan_tries = 0; | 1735 | ifmgd->assoc_scan_tries = 0; |
2009 | ifsta->direct_probe_tries = 0; | 1736 | ifmgd->direct_probe_tries = 0; |
2010 | ifsta->auth_tries = 0; | 1737 | ifmgd->auth_tries = 0; |
2011 | ifsta->assoc_tries = 0; | 1738 | ifmgd->assoc_tries = 0; |
2012 | netif_tx_stop_all_queues(sdata->dev); | 1739 | netif_tx_stop_all_queues(sdata->dev); |
2013 | netif_carrier_off(sdata->dev); | 1740 | netif_carrier_off(sdata->dev); |
2014 | } | 1741 | } |
2015 | 1742 | ||
2016 | 1743 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) | |
2017 | static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, | ||
2018 | const char *ssid, int ssid_len) | ||
2019 | { | ||
2020 | int tmp, hidden_ssid; | ||
2021 | |||
2022 | if (ssid_len == ifsta->ssid_len && | ||
2023 | !memcmp(ifsta->ssid, ssid, ssid_len)) | ||
2024 | return 1; | ||
2025 | |||
2026 | if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) | ||
2027 | return 0; | ||
2028 | |||
2029 | hidden_ssid = 1; | ||
2030 | tmp = ssid_len; | ||
2031 | while (tmp--) { | ||
2032 | if (ssid[tmp] != '\0') { | ||
2033 | hidden_ssid = 0; | ||
2034 | break; | ||
2035 | } | ||
2036 | } | ||
2037 | |||
2038 | if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0)) | ||
2039 | return 1; | ||
2040 | |||
2041 | if (ssid_len == 1 && ssid[0] == ' ') | ||
2042 | return 1; | ||
2043 | |||
2044 | return 0; | ||
2045 | } | ||
2046 | |||
2047 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | ||
2048 | struct ieee80211_if_sta *ifsta) | ||
2049 | { | 1744 | { |
1745 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2050 | struct ieee80211_local *local = sdata->local; | 1746 | struct ieee80211_local *local = sdata->local; |
2051 | struct ieee80211_bss *bss; | 1747 | struct ieee80211_bss *bss; |
2052 | struct ieee80211_supported_band *sband; | 1748 | u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid; |
2053 | u8 bssid[ETH_ALEN], *pos; | 1749 | u8 ssid_len = ifmgd->ssid_len; |
2054 | int i; | 1750 | u16 capa_mask = WLAN_CAPABILITY_ESS; |
2055 | int ret; | 1751 | u16 capa_val = WLAN_CAPABILITY_ESS; |
2056 | 1752 | struct ieee80211_channel *chan = local->oper_channel; | |
2057 | #if 0 | ||
2058 | /* Easier testing, use fixed BSSID. */ | ||
2059 | memset(bssid, 0xfe, ETH_ALEN); | ||
2060 | #else | ||
2061 | /* Generate random, not broadcast, locally administered BSSID. Mix in | ||
2062 | * own MAC address to make sure that devices that do not have proper | ||
2063 | * random number generator get different BSSID. */ | ||
2064 | get_random_bytes(bssid, ETH_ALEN); | ||
2065 | for (i = 0; i < ETH_ALEN; i++) | ||
2066 | bssid[i] ^= sdata->dev->dev_addr[i]; | ||
2067 | bssid[0] &= ~0x01; | ||
2068 | bssid[0] |= 0x02; | ||
2069 | #endif | ||
2070 | |||
2071 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | ||
2072 | sdata->dev->name, bssid); | ||
2073 | |||
2074 | bss = ieee80211_rx_bss_add(local, bssid, | ||
2075 | local->hw.conf.channel->center_freq, | ||
2076 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); | ||
2077 | if (!bss) | ||
2078 | return -ENOMEM; | ||
2079 | |||
2080 | bss->band = local->hw.conf.channel->band; | ||
2081 | sband = local->hw.wiphy->bands[bss->band]; | ||
2082 | |||
2083 | if (local->hw.conf.beacon_int == 0) | ||
2084 | local->hw.conf.beacon_int = 100; | ||
2085 | bss->beacon_int = local->hw.conf.beacon_int; | ||
2086 | bss->last_update = jiffies; | ||
2087 | bss->capability = WLAN_CAPABILITY_IBSS; | ||
2088 | 1753 | ||
2089 | if (sdata->default_key) | 1754 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
2090 | bss->capability |= WLAN_CAPABILITY_PRIVACY; | 1755 | ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | |
2091 | else | 1756 | IEEE80211_STA_AUTO_BSSID_SEL | |
2092 | sdata->drop_unencrypted = 0; | 1757 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { |
2093 | 1758 | capa_mask |= WLAN_CAPABILITY_PRIVACY; | |
2094 | bss->supp_rates_len = sband->n_bitrates; | 1759 | if (sdata->default_key) |
2095 | pos = bss->supp_rates; | 1760 | capa_val |= WLAN_CAPABILITY_PRIVACY; |
2096 | for (i = 0; i < sband->n_bitrates; i++) { | ||
2097 | int rate = sband->bitrates[i].bitrate; | ||
2098 | *pos++ = (u8) (rate / 5); | ||
2099 | } | 1761 | } |
2100 | 1762 | ||
2101 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); | 1763 | if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) |
2102 | ieee80211_rx_bss_put(local, bss); | 1764 | chan = NULL; |
2103 | return ret; | ||
2104 | } | ||
2105 | 1765 | ||
1766 | if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL) | ||
1767 | bssid = NULL; | ||
2106 | 1768 | ||
2107 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | 1769 | if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) { |
2108 | struct ieee80211_if_sta *ifsta) | 1770 | ssid = NULL; |
2109 | { | 1771 | ssid_len = 0; |
2110 | struct ieee80211_local *local = sdata->local; | ||
2111 | struct ieee80211_bss *bss; | ||
2112 | int found = 0; | ||
2113 | u8 bssid[ETH_ALEN]; | ||
2114 | int active_ibss; | ||
2115 | |||
2116 | if (ifsta->ssid_len == 0) | ||
2117 | return -EINVAL; | ||
2118 | |||
2119 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
2120 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2121 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | ||
2122 | sdata->dev->name, active_ibss); | ||
2123 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2124 | spin_lock_bh(&local->bss_lock); | ||
2125 | list_for_each_entry(bss, &local->bss_list, list) { | ||
2126 | if (ifsta->ssid_len != bss->ssid_len || | ||
2127 | memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0 | ||
2128 | || !(bss->capability & WLAN_CAPABILITY_IBSS)) | ||
2129 | continue; | ||
2130 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2131 | printk(KERN_DEBUG " bssid=%pM found\n", bss->bssid); | ||
2132 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2133 | memcpy(bssid, bss->bssid, ETH_ALEN); | ||
2134 | found = 1; | ||
2135 | if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0) | ||
2136 | break; | ||
2137 | } | 1772 | } |
2138 | spin_unlock_bh(&local->bss_lock); | ||
2139 | 1773 | ||
2140 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1774 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, |
2141 | if (found) | 1775 | bssid, ssid, ssid_len, |
2142 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " | 1776 | capa_mask, capa_val); |
2143 | "%pM\n", bssid, ifsta->bssid); | ||
2144 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2145 | 1777 | ||
2146 | if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { | 1778 | if (bss) { |
2147 | int ret; | 1779 | ieee80211_set_freq(sdata, bss->cbss.channel->center_freq); |
2148 | int search_freq; | 1780 | if (!(ifmgd->flags & IEEE80211_STA_SSID_SET)) |
2149 | 1781 | ieee80211_sta_set_ssid(sdata, bss->ssid, | |
2150 | if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) | 1782 | bss->ssid_len); |
2151 | search_freq = bss->freq; | 1783 | ieee80211_sta_set_bssid(sdata, bss->cbss.bssid); |
1784 | ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, | ||
1785 | bss->supp_rates); | ||
1786 | if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED) | ||
1787 | sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; | ||
2152 | else | 1788 | else |
2153 | search_freq = local->hw.conf.channel->center_freq; | 1789 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; |
2154 | |||
2155 | bss = ieee80211_rx_bss_get(local, bssid, search_freq, | ||
2156 | ifsta->ssid, ifsta->ssid_len); | ||
2157 | if (!bss) | ||
2158 | goto dont_join; | ||
2159 | |||
2160 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | ||
2161 | " based on configured SSID\n", | ||
2162 | sdata->dev->name, bssid); | ||
2163 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); | ||
2164 | ieee80211_rx_bss_put(local, bss); | ||
2165 | return ret; | ||
2166 | } | ||
2167 | |||
2168 | dont_join: | ||
2169 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2170 | printk(KERN_DEBUG " did not try to join ibss\n"); | ||
2171 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2172 | |||
2173 | /* Selected IBSS not found in current scan results - try to scan */ | ||
2174 | if (ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED && | ||
2175 | !ieee80211_sta_active_ibss(sdata)) { | ||
2176 | mod_timer(&ifsta->timer, jiffies + | ||
2177 | IEEE80211_IBSS_MERGE_INTERVAL); | ||
2178 | } else if (time_after(jiffies, local->last_scan_completed + | ||
2179 | IEEE80211_SCAN_INTERVAL)) { | ||
2180 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | ||
2181 | "join\n", sdata->dev->name); | ||
2182 | return ieee80211_request_scan(sdata, ifsta->ssid, | ||
2183 | ifsta->ssid_len); | ||
2184 | } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) { | ||
2185 | int interval = IEEE80211_SCAN_INTERVAL; | ||
2186 | |||
2187 | if (time_after(jiffies, ifsta->ibss_join_req + | ||
2188 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | ||
2189 | if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && | ||
2190 | (!(local->oper_channel->flags & | ||
2191 | IEEE80211_CHAN_NO_IBSS))) | ||
2192 | return ieee80211_sta_create_ibss(sdata, ifsta); | ||
2193 | if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { | ||
2194 | printk(KERN_DEBUG "%s: IBSS not allowed on" | ||
2195 | " %d MHz\n", sdata->dev->name, | ||
2196 | local->hw.conf.channel->center_freq); | ||
2197 | } | ||
2198 | |||
2199 | /* No IBSS found - decrease scan interval and continue | ||
2200 | * scanning. */ | ||
2201 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | ||
2202 | } | ||
2203 | |||
2204 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | ||
2205 | mod_timer(&ifsta->timer, jiffies + interval); | ||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | return 0; | ||
2210 | } | ||
2211 | |||
2212 | |||
2213 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | ||
2214 | struct ieee80211_if_sta *ifsta) | ||
2215 | { | ||
2216 | struct ieee80211_local *local = sdata->local; | ||
2217 | struct ieee80211_bss *bss, *selected = NULL; | ||
2218 | int top_rssi = 0, freq; | ||
2219 | |||
2220 | spin_lock_bh(&local->bss_lock); | ||
2221 | freq = local->oper_channel->center_freq; | ||
2222 | list_for_each_entry(bss, &local->bss_list, list) { | ||
2223 | if (!(bss->capability & WLAN_CAPABILITY_ESS)) | ||
2224 | continue; | ||
2225 | |||
2226 | if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | ||
2227 | IEEE80211_STA_AUTO_BSSID_SEL | | ||
2228 | IEEE80211_STA_AUTO_CHANNEL_SEL)) && | ||
2229 | (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ | ||
2230 | !!sdata->default_key)) | ||
2231 | continue; | ||
2232 | |||
2233 | if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && | ||
2234 | bss->freq != freq) | ||
2235 | continue; | ||
2236 | |||
2237 | if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && | ||
2238 | memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) | ||
2239 | continue; | ||
2240 | |||
2241 | if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && | ||
2242 | !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) | ||
2243 | continue; | ||
2244 | |||
2245 | if (!selected || top_rssi < bss->signal) { | ||
2246 | selected = bss; | ||
2247 | top_rssi = bss->signal; | ||
2248 | } | ||
2249 | } | ||
2250 | if (selected) | ||
2251 | atomic_inc(&selected->users); | ||
2252 | spin_unlock_bh(&local->bss_lock); | ||
2253 | |||
2254 | if (selected) { | ||
2255 | ieee80211_set_freq(sdata, selected->freq); | ||
2256 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | ||
2257 | ieee80211_sta_set_ssid(sdata, selected->ssid, | ||
2258 | selected->ssid_len); | ||
2259 | ieee80211_sta_set_bssid(sdata, selected->bssid); | ||
2260 | ieee80211_sta_def_wmm_params(sdata, selected); | ||
2261 | 1790 | ||
2262 | /* Send out direct probe if no probe resp was received or | 1791 | /* Send out direct probe if no probe resp was received or |
2263 | * the one we have is outdated | 1792 | * the one we have is outdated |
2264 | */ | 1793 | */ |
2265 | if (!selected->last_probe_resp || | 1794 | if (!bss->last_probe_resp || |
2266 | time_after(jiffies, selected->last_probe_resp | 1795 | time_after(jiffies, bss->last_probe_resp |
2267 | + IEEE80211_SCAN_RESULT_EXPIRE)) | 1796 | + IEEE80211_SCAN_RESULT_EXPIRE)) |
2268 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1797 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
2269 | else | 1798 | else |
2270 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 1799 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2271 | 1800 | ||
2272 | ieee80211_rx_bss_put(local, selected); | 1801 | ieee80211_rx_bss_put(local, bss); |
2273 | ieee80211_sta_reset_auth(sdata, ifsta); | 1802 | ieee80211_sta_reset_auth(sdata); |
2274 | return 0; | 1803 | return 0; |
2275 | } else { | 1804 | } else { |
2276 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | 1805 | if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { |
2277 | ifsta->assoc_scan_tries++; | 1806 | ifmgd->assoc_scan_tries++; |
2278 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | 1807 | /* XXX maybe racy? */ |
2279 | ieee80211_start_scan(sdata, NULL, 0); | 1808 | if (local->scan_req) |
1809 | return -1; | ||
1810 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
1811 | ifmgd->ssid, IEEE80211_MAX_SSID_LEN); | ||
1812 | if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) | ||
1813 | local->int_scan_req.ssids[0].ssid_len = 0; | ||
2280 | else | 1814 | else |
2281 | ieee80211_start_scan(sdata, ifsta->ssid, | 1815 | local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len; |
2282 | ifsta->ssid_len); | 1816 | |
2283 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 1817 | if (ieee80211_start_scan(sdata, &local->int_scan_req)) |
2284 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 1818 | ieee80211_scan_failed(local); |
2285 | } else | 1819 | |
2286 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 1820 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
1821 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | ||
1822 | } else { | ||
1823 | ifmgd->assoc_scan_tries = 0; | ||
1824 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
1825 | } | ||
2287 | } | 1826 | } |
2288 | return -1; | 1827 | return -1; |
2289 | } | 1828 | } |
@@ -2292,9 +1831,9 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2292 | static void ieee80211_sta_work(struct work_struct *work) | 1831 | static void ieee80211_sta_work(struct work_struct *work) |
2293 | { | 1832 | { |
2294 | struct ieee80211_sub_if_data *sdata = | 1833 | struct ieee80211_sub_if_data *sdata = |
2295 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | 1834 | container_of(work, struct ieee80211_sub_if_data, u.mgd.work); |
2296 | struct ieee80211_local *local = sdata->local; | 1835 | struct ieee80211_local *local = sdata->local; |
2297 | struct ieee80211_if_sta *ifsta; | 1836 | struct ieee80211_if_managed *ifmgd; |
2298 | struct sk_buff *skb; | 1837 | struct sk_buff *skb; |
2299 | 1838 | ||
2300 | if (!netif_running(sdata->dev)) | 1839 | if (!netif_running(sdata->dev)) |
@@ -2303,61 +1842,60 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2303 | if (local->sw_scanning || local->hw_scanning) | 1842 | if (local->sw_scanning || local->hw_scanning) |
2304 | return; | 1843 | return; |
2305 | 1844 | ||
2306 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION && | 1845 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2307 | sdata->vif.type != NL80211_IFTYPE_ADHOC)) | ||
2308 | return; | 1846 | return; |
2309 | ifsta = &sdata->u.sta; | 1847 | ifmgd = &sdata->u.mgd; |
2310 | 1848 | ||
2311 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | 1849 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) |
2312 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | 1850 | ieee80211_sta_rx_queued_mgmt(sdata, skb); |
2313 | 1851 | ||
2314 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && | 1852 | if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE && |
2315 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 1853 | ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && |
2316 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | 1854 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && |
2317 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | 1855 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { |
2318 | ieee80211_start_scan(sdata, ifsta->scan_ssid, | 1856 | /* |
2319 | ifsta->scan_ssid_len); | 1857 | * The call to ieee80211_start_scan can fail but ieee80211_request_scan |
1858 | * (which queued ieee80211_sta_work) did not return an error. Thus, call | ||
1859 | * ieee80211_scan_failed here if ieee80211_start_scan fails in order to | ||
1860 | * notify the scan requester. | ||
1861 | */ | ||
1862 | if (ieee80211_start_scan(sdata, local->scan_req)) | ||
1863 | ieee80211_scan_failed(local); | ||
2320 | return; | 1864 | return; |
2321 | } | 1865 | } |
2322 | 1866 | ||
2323 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { | 1867 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) { |
2324 | if (ieee80211_sta_config_auth(sdata, ifsta)) | 1868 | if (ieee80211_sta_config_auth(sdata)) |
2325 | return; | 1869 | return; |
2326 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | 1870 | clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
2327 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) | 1871 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) |
2328 | return; | 1872 | return; |
2329 | 1873 | ||
2330 | switch (ifsta->state) { | 1874 | switch (ifmgd->state) { |
2331 | case IEEE80211_STA_MLME_DISABLED: | 1875 | case IEEE80211_STA_MLME_DISABLED: |
2332 | break; | 1876 | break; |
2333 | case IEEE80211_STA_MLME_DIRECT_PROBE: | 1877 | case IEEE80211_STA_MLME_DIRECT_PROBE: |
2334 | ieee80211_direct_probe(sdata, ifsta); | 1878 | ieee80211_direct_probe(sdata); |
2335 | break; | 1879 | break; |
2336 | case IEEE80211_STA_MLME_AUTHENTICATE: | 1880 | case IEEE80211_STA_MLME_AUTHENTICATE: |
2337 | ieee80211_authenticate(sdata, ifsta); | 1881 | ieee80211_authenticate(sdata); |
2338 | break; | 1882 | break; |
2339 | case IEEE80211_STA_MLME_ASSOCIATE: | 1883 | case IEEE80211_STA_MLME_ASSOCIATE: |
2340 | ieee80211_associate(sdata, ifsta); | 1884 | ieee80211_associate(sdata); |
2341 | break; | 1885 | break; |
2342 | case IEEE80211_STA_MLME_ASSOCIATED: | 1886 | case IEEE80211_STA_MLME_ASSOCIATED: |
2343 | ieee80211_associated(sdata, ifsta); | 1887 | ieee80211_associated(sdata); |
2344 | break; | ||
2345 | case IEEE80211_STA_MLME_IBSS_SEARCH: | ||
2346 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
2347 | break; | ||
2348 | case IEEE80211_STA_MLME_IBSS_JOINED: | ||
2349 | ieee80211_sta_merge_ibss(sdata, ifsta); | ||
2350 | break; | 1888 | break; |
2351 | default: | 1889 | default: |
2352 | WARN_ON(1); | 1890 | WARN_ON(1); |
2353 | break; | 1891 | break; |
2354 | } | 1892 | } |
2355 | 1893 | ||
2356 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | 1894 | if (ieee80211_privacy_mismatch(sdata)) { |
2357 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " | 1895 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " |
2358 | "mixed-cell disabled - disassociate\n", sdata->dev->name); | 1896 | "mixed-cell disabled - disassociate\n", sdata->dev->name); |
2359 | 1897 | ||
2360 | ieee80211_set_disassoc(sdata, ifsta, false, true, | 1898 | ieee80211_set_disassoc(sdata, false, true, |
2361 | WLAN_REASON_UNSPECIFIED); | 1899 | WLAN_REASON_UNSPECIFIED); |
2362 | } | 1900 | } |
2363 | } | 1901 | } |
@@ -2366,208 +1904,161 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
2366 | { | 1904 | { |
2367 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 1905 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
2368 | queue_work(sdata->local->hw.workqueue, | 1906 | queue_work(sdata->local->hw.workqueue, |
2369 | &sdata->u.sta.work); | 1907 | &sdata->u.mgd.work); |
2370 | } | 1908 | } |
2371 | 1909 | ||
2372 | /* interface setup */ | 1910 | /* interface setup */ |
2373 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 1911 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
2374 | { | 1912 | { |
2375 | struct ieee80211_if_sta *ifsta; | 1913 | struct ieee80211_if_managed *ifmgd; |
2376 | 1914 | ||
2377 | ifsta = &sdata->u.sta; | 1915 | ifmgd = &sdata->u.mgd; |
2378 | INIT_WORK(&ifsta->work, ieee80211_sta_work); | 1916 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
2379 | setup_timer(&ifsta->timer, ieee80211_sta_timer, | 1917 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1918 | INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); | ||
1919 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | ||
2380 | (unsigned long) sdata); | 1920 | (unsigned long) sdata); |
2381 | skb_queue_head_init(&ifsta->skb_queue); | 1921 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
1922 | (unsigned long) sdata); | ||
1923 | skb_queue_head_init(&ifmgd->skb_queue); | ||
2382 | 1924 | ||
2383 | ifsta->capab = WLAN_CAPABILITY_ESS; | 1925 | ifmgd->capab = WLAN_CAPABILITY_ESS; |
2384 | ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | | 1926 | ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN | |
2385 | IEEE80211_AUTH_ALG_SHARED_KEY; | 1927 | IEEE80211_AUTH_ALG_SHARED_KEY; |
2386 | ifsta->flags |= IEEE80211_STA_CREATE_IBSS | | 1928 | ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | |
2387 | IEEE80211_STA_AUTO_BSSID_SEL | | 1929 | IEEE80211_STA_AUTO_BSSID_SEL | |
2388 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 1930 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
2389 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) | 1931 | if (sdata->local->hw.queues >= 4) |
2390 | ifsta->flags |= IEEE80211_STA_WMM_ENABLED; | 1932 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; |
2391 | } | ||
2392 | |||
2393 | /* | ||
2394 | * Add a new IBSS station, will also be called by the RX code when, | ||
2395 | * in IBSS mode, receiving a frame from a yet-unknown station, hence | ||
2396 | * must be callable in atomic context. | ||
2397 | */ | ||
2398 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
2399 | u8 *bssid,u8 *addr, u64 supp_rates) | ||
2400 | { | ||
2401 | struct ieee80211_local *local = sdata->local; | ||
2402 | struct sta_info *sta; | ||
2403 | int band = local->hw.conf.channel->band; | ||
2404 | |||
2405 | /* TODO: Could consider removing the least recently used entry and | ||
2406 | * allow new one to be added. */ | ||
2407 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | ||
2408 | if (net_ratelimit()) { | ||
2409 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | ||
2410 | "entry %pM\n", sdata->dev->name, addr); | ||
2411 | } | ||
2412 | return NULL; | ||
2413 | } | ||
2414 | |||
2415 | if (compare_ether_addr(bssid, sdata->u.sta.bssid)) | ||
2416 | return NULL; | ||
2417 | |||
2418 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
2419 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", | ||
2420 | wiphy_name(local->hw.wiphy), addr, sdata->dev->name); | ||
2421 | #endif | ||
2422 | |||
2423 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
2424 | if (!sta) | ||
2425 | return NULL; | ||
2426 | |||
2427 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
2428 | |||
2429 | /* make sure mandatory rates are always added */ | ||
2430 | sta->sta.supp_rates[band] = supp_rates | | ||
2431 | ieee80211_mandatory_rates(local, band); | ||
2432 | |||
2433 | rate_control_rate_init(sta); | ||
2434 | |||
2435 | if (sta_info_insert(sta)) | ||
2436 | return NULL; | ||
2437 | |||
2438 | return sta; | ||
2439 | } | 1933 | } |
2440 | 1934 | ||
2441 | /* configuration hooks */ | 1935 | /* configuration hooks */ |
2442 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | 1936 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) |
2443 | struct ieee80211_if_sta *ifsta) | ||
2444 | { | 1937 | { |
1938 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2445 | struct ieee80211_local *local = sdata->local; | 1939 | struct ieee80211_local *local = sdata->local; |
2446 | 1940 | ||
2447 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1941 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2448 | return; | 1942 | return; |
2449 | 1943 | ||
2450 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | | 1944 | if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET | |
2451 | IEEE80211_STA_AUTO_BSSID_SEL)) && | 1945 | IEEE80211_STA_AUTO_BSSID_SEL)) && |
2452 | (ifsta->flags & (IEEE80211_STA_SSID_SET | | 1946 | (ifmgd->flags & (IEEE80211_STA_SSID_SET | |
2453 | IEEE80211_STA_AUTO_SSID_SEL))) { | 1947 | IEEE80211_STA_AUTO_SSID_SEL))) { |
2454 | 1948 | ||
2455 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) | 1949 | if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) |
2456 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 1950 | ieee80211_set_disassoc(sdata, true, true, |
2457 | WLAN_REASON_DEAUTH_LEAVING); | 1951 | WLAN_REASON_DEAUTH_LEAVING); |
2458 | 1952 | ||
2459 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 1953 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) || |
2460 | queue_work(local->hw.workqueue, &ifsta->work); | 1954 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) |
1955 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | ||
1956 | else if (ifmgd->flags & IEEE80211_STA_EXT_SME) | ||
1957 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | ||
1958 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
2461 | } | 1959 | } |
2462 | } | 1960 | } |
2463 | 1961 | ||
1962 | int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata) | ||
1963 | { | ||
1964 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1965 | |||
1966 | if (ifmgd->ssid_len) | ||
1967 | ifmgd->flags |= IEEE80211_STA_SSID_SET; | ||
1968 | else | ||
1969 | ifmgd->flags &= ~IEEE80211_STA_SSID_SET; | ||
1970 | |||
1971 | return 0; | ||
1972 | } | ||
1973 | |||
2464 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | 1974 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) |
2465 | { | 1975 | { |
2466 | struct ieee80211_if_sta *ifsta; | 1976 | struct ieee80211_if_managed *ifmgd; |
2467 | 1977 | ||
2468 | if (len > IEEE80211_MAX_SSID_LEN) | 1978 | if (len > IEEE80211_MAX_SSID_LEN) |
2469 | return -EINVAL; | 1979 | return -EINVAL; |
2470 | 1980 | ||
2471 | ifsta = &sdata->u.sta; | 1981 | ifmgd = &sdata->u.mgd; |
2472 | |||
2473 | if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { | ||
2474 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); | ||
2475 | memcpy(ifsta->ssid, ssid, len); | ||
2476 | ifsta->ssid_len = len; | ||
2477 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
2478 | } | ||
2479 | |||
2480 | if (len) | ||
2481 | ifsta->flags |= IEEE80211_STA_SSID_SET; | ||
2482 | else | ||
2483 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; | ||
2484 | 1982 | ||
2485 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 1983 | if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { |
2486 | !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { | 1984 | /* |
2487 | ifsta->ibss_join_req = jiffies; | 1985 | * Do not use reassociation if SSID is changed (different ESS). |
2488 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | 1986 | */ |
2489 | return ieee80211_sta_find_ibss(sdata, ifsta); | 1987 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
1988 | memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); | ||
1989 | memcpy(ifmgd->ssid, ssid, len); | ||
1990 | ifmgd->ssid_len = len; | ||
2490 | } | 1991 | } |
2491 | 1992 | ||
2492 | return 0; | 1993 | return ieee80211_sta_commit(sdata); |
2493 | } | 1994 | } |
2494 | 1995 | ||
2495 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | 1996 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) |
2496 | { | 1997 | { |
2497 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1998 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2498 | memcpy(ssid, ifsta->ssid, ifsta->ssid_len); | 1999 | memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len); |
2499 | *len = ifsta->ssid_len; | 2000 | *len = ifmgd->ssid_len; |
2500 | return 0; | 2001 | return 0; |
2501 | } | 2002 | } |
2502 | 2003 | ||
2503 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | 2004 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) |
2504 | { | 2005 | { |
2505 | struct ieee80211_if_sta *ifsta; | 2006 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2506 | int res; | ||
2507 | 2007 | ||
2508 | ifsta = &sdata->u.sta; | 2008 | if (is_valid_ether_addr(bssid)) { |
2009 | memcpy(ifmgd->bssid, bssid, ETH_ALEN); | ||
2010 | ifmgd->flags |= IEEE80211_STA_BSSID_SET; | ||
2011 | } else { | ||
2012 | memset(ifmgd->bssid, 0, ETH_ALEN); | ||
2013 | ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; | ||
2014 | } | ||
2509 | 2015 | ||
2510 | if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { | 2016 | if (netif_running(sdata->dev)) { |
2511 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | 2017 | if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { |
2512 | res = 0; | ||
2513 | /* | ||
2514 | * Hack! See also ieee80211_sta_set_ssid. | ||
2515 | */ | ||
2516 | if (netif_running(sdata->dev)) | ||
2517 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
2518 | if (res) { | ||
2519 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | 2018 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " |
2520 | "the low-level driver\n", sdata->dev->name); | 2019 | "the low-level driver\n", sdata->dev->name); |
2521 | return res; | ||
2522 | } | 2020 | } |
2523 | } | 2021 | } |
2524 | 2022 | ||
2525 | if (is_valid_ether_addr(bssid)) | 2023 | return ieee80211_sta_commit(sdata); |
2526 | ifsta->flags |= IEEE80211_STA_BSSID_SET; | ||
2527 | else | ||
2528 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; | ||
2529 | |||
2530 | return 0; | ||
2531 | } | 2024 | } |
2532 | 2025 | ||
2533 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 2026 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, |
2027 | const char *ie, size_t len) | ||
2534 | { | 2028 | { |
2535 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2029 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2536 | 2030 | ||
2537 | kfree(ifsta->extra_ie); | 2031 | kfree(ifmgd->extra_ie); |
2538 | if (len == 0) { | 2032 | if (len == 0) { |
2539 | ifsta->extra_ie = NULL; | 2033 | ifmgd->extra_ie = NULL; |
2540 | ifsta->extra_ie_len = 0; | 2034 | ifmgd->extra_ie_len = 0; |
2541 | return 0; | 2035 | return 0; |
2542 | } | 2036 | } |
2543 | ifsta->extra_ie = kmalloc(len, GFP_KERNEL); | 2037 | ifmgd->extra_ie = kmalloc(len, GFP_KERNEL); |
2544 | if (!ifsta->extra_ie) { | 2038 | if (!ifmgd->extra_ie) { |
2545 | ifsta->extra_ie_len = 0; | 2039 | ifmgd->extra_ie_len = 0; |
2546 | return -ENOMEM; | 2040 | return -ENOMEM; |
2547 | } | 2041 | } |
2548 | memcpy(ifsta->extra_ie, ie, len); | 2042 | memcpy(ifmgd->extra_ie, ie, len); |
2549 | ifsta->extra_ie_len = len; | 2043 | ifmgd->extra_ie_len = len; |
2550 | return 0; | 2044 | return 0; |
2551 | } | 2045 | } |
2552 | 2046 | ||
2553 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | 2047 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) |
2554 | { | 2048 | { |
2555 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2556 | |||
2557 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", | 2049 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", |
2558 | sdata->dev->name, reason); | 2050 | sdata->dev->name, reason); |
2559 | 2051 | ||
2560 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 2052 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2561 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
2562 | return -EINVAL; | 2053 | return -EINVAL; |
2563 | 2054 | ||
2564 | ieee80211_set_disassoc(sdata, ifsta, true, true, reason); | 2055 | ieee80211_set_disassoc(sdata, true, true, reason); |
2565 | return 0; | 2056 | return 0; |
2566 | } | 2057 | } |
2567 | 2058 | ||
2568 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | 2059 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) |
2569 | { | 2060 | { |
2570 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2061 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2571 | 2062 | ||
2572 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", | 2063 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", |
2573 | sdata->dev->name, reason); | 2064 | sdata->dev->name, reason); |
@@ -2575,10 +2066,10 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | |||
2575 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 2066 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2576 | return -EINVAL; | 2067 | return -EINVAL; |
2577 | 2068 | ||
2578 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) | 2069 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) |
2579 | return -1; | 2070 | return -ENOLINK; |
2580 | 2071 | ||
2581 | ieee80211_set_disassoc(sdata, ifsta, false, true, reason); | 2072 | ieee80211_set_disassoc(sdata, false, true, reason); |
2582 | return 0; | 2073 | return 0; |
2583 | } | 2074 | } |
2584 | 2075 | ||
@@ -2586,15 +2077,6 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | |||
2586 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | 2077 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) |
2587 | { | 2078 | { |
2588 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 2079 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
2589 | struct ieee80211_if_sta *ifsta; | ||
2590 | |||
2591 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
2592 | ifsta = &sdata->u.sta; | ||
2593 | if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || | ||
2594 | (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) && | ||
2595 | !ieee80211_sta_active_ibss(sdata))) | ||
2596 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
2597 | } | ||
2598 | 2080 | ||
2599 | /* Restart STA timers */ | 2081 | /* Restart STA timers */ |
2600 | rcu_read_lock(); | 2082 | rcu_read_lock(); |
@@ -2623,12 +2105,15 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
2623 | struct ieee80211_local *local = | 2105 | struct ieee80211_local *local = |
2624 | container_of(work, struct ieee80211_local, | 2106 | container_of(work, struct ieee80211_local, |
2625 | dynamic_ps_enable_work); | 2107 | dynamic_ps_enable_work); |
2108 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
2626 | 2109 | ||
2627 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 2110 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
2628 | return; | 2111 | return; |
2629 | 2112 | ||
2630 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 2113 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
2114 | ieee80211_send_nullfunc(local, sdata, 1); | ||
2631 | 2115 | ||
2116 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
2632 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 2117 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
2633 | } | 2118 | } |
2634 | 2119 | ||
@@ -2638,3 +2123,36 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
2638 | 2123 | ||
2639 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | 2124 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); |
2640 | } | 2125 | } |
2126 | |||
2127 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
2128 | struct ieee80211_sub_if_data *sdata, | ||
2129 | int powersave) | ||
2130 | { | ||
2131 | struct sk_buff *skb; | ||
2132 | struct ieee80211_hdr *nullfunc; | ||
2133 | __le16 fc; | ||
2134 | |||
2135 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
2136 | return; | ||
2137 | |||
2138 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
2139 | if (!skb) { | ||
2140 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
2141 | "frame\n", sdata->dev->name); | ||
2142 | return; | ||
2143 | } | ||
2144 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2145 | |||
2146 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
2147 | memset(nullfunc, 0, 24); | ||
2148 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
2149 | IEEE80211_FCTL_TODS); | ||
2150 | if (powersave) | ||
2151 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
2152 | nullfunc->frame_control = fc; | ||
2153 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); | ||
2154 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
2155 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); | ||
2156 | |||
2157 | ieee80211_tx_skb(sdata, skb, 0); | ||
2158 | } | ||