1 |
62 |
marcus.erl |
/*
|
2 |
|
|
* This file contains the softmac's association logic.
|
3 |
|
|
*
|
4 |
|
|
* Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
|
5 |
|
|
* Joseph Jezak <josejx@gentoo.org>
|
6 |
|
|
* Larry Finger <Larry.Finger@lwfinger.net>
|
7 |
|
|
* Danny van Dyk <kugelfang@gentoo.org>
|
8 |
|
|
* Michael Buesch <mbuesch@freenet.de>
|
9 |
|
|
*
|
10 |
|
|
* This program is free software; you can redistribute it and/or modify it
|
11 |
|
|
* under the terms of version 2 of the GNU General Public License as
|
12 |
|
|
* published by the Free Software Foundation.
|
13 |
|
|
*
|
14 |
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
15 |
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
16 |
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
17 |
|
|
* more details.
|
18 |
|
|
*
|
19 |
|
|
* You should have received a copy of the GNU General Public License
|
20 |
|
|
* along with this program; if not, write to the Free Software
|
21 |
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
22 |
|
|
*
|
23 |
|
|
* The full GNU General Public License is included in this distribution in the
|
24 |
|
|
* file called COPYING.
|
25 |
|
|
*/
|
26 |
|
|
|
27 |
|
|
#include "ieee80211softmac_priv.h"
|
28 |
|
|
|
29 |
|
|
/*
|
30 |
|
|
* Overview
|
31 |
|
|
*
|
32 |
|
|
* Before you can associate, you have to authenticate.
|
33 |
|
|
*
|
34 |
|
|
*/
|
35 |
|
|
|
36 |
|
|
/* Sends out an association request to the desired AP */
|
37 |
|
|
static void
|
38 |
|
|
ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
|
39 |
|
|
{
|
40 |
|
|
unsigned long flags;
|
41 |
|
|
|
42 |
|
|
/* Switch to correct channel for this network */
|
43 |
|
|
mac->set_channel(mac->dev, net->channel);
|
44 |
|
|
|
45 |
|
|
/* Send association request */
|
46 |
|
|
ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0);
|
47 |
|
|
|
48 |
|
|
dprintk(KERN_INFO PFX "sent association request!\n");
|
49 |
|
|
|
50 |
|
|
spin_lock_irqsave(&mac->lock, flags);
|
51 |
|
|
mac->associnfo.associated = 0; /* just to make sure */
|
52 |
|
|
|
53 |
|
|
/* Set a timer for timeout */
|
54 |
|
|
/* FIXME: make timeout configurable */
|
55 |
|
|
if (likely(mac->running))
|
56 |
|
|
queue_delayed_work(mac->wq, &mac->associnfo.timeout, 5 * HZ);
|
57 |
|
|
spin_unlock_irqrestore(&mac->lock, flags);
|
58 |
|
|
}
|
59 |
|
|
|
60 |
|
|
void
|
61 |
|
|
ieee80211softmac_assoc_timeout(struct work_struct *work)
|
62 |
|
|
{
|
63 |
|
|
struct ieee80211softmac_device *mac =
|
64 |
|
|
container_of(work, struct ieee80211softmac_device,
|
65 |
|
|
associnfo.timeout.work);
|
66 |
|
|
struct ieee80211softmac_network *n;
|
67 |
|
|
|
68 |
|
|
mutex_lock(&mac->associnfo.mutex);
|
69 |
|
|
/* we might race against ieee80211softmac_handle_assoc_response,
|
70 |
|
|
* so make sure only one of us does something */
|
71 |
|
|
if (!mac->associnfo.associating)
|
72 |
|
|
goto out;
|
73 |
|
|
mac->associnfo.associating = 0;
|
74 |
|
|
mac->associnfo.bssvalid = 0;
|
75 |
|
|
mac->associnfo.associated = 0;
|
76 |
|
|
|
77 |
|
|
n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
|
78 |
|
|
|
79 |
|
|
dprintk(KERN_INFO PFX "assoc request timed out!\n");
|
80 |
|
|
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
|
81 |
|
|
out:
|
82 |
|
|
mutex_unlock(&mac->associnfo.mutex);
|
83 |
|
|
}
|
84 |
|
|
|
85 |
|
|
void
|
86 |
|
|
ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
|
87 |
|
|
{
|
88 |
|
|
unsigned long flags;
|
89 |
|
|
|
90 |
|
|
spin_lock_irqsave(&mac->lock, flags);
|
91 |
|
|
if (mac->associnfo.associating)
|
92 |
|
|
cancel_delayed_work(&mac->associnfo.timeout);
|
93 |
|
|
|
94 |
|
|
netif_carrier_off(mac->dev);
|
95 |
|
|
|
96 |
|
|
mac->associnfo.associated = 0;
|
97 |
|
|
mac->associnfo.bssvalid = 0;
|
98 |
|
|
mac->associnfo.associating = 0;
|
99 |
|
|
ieee80211softmac_init_bss(mac);
|
100 |
|
|
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
|
101 |
|
|
spin_unlock_irqrestore(&mac->lock, flags);
|
102 |
|
|
}
|
103 |
|
|
|
104 |
|
|
/* Sends out a disassociation request to the desired AP */
|
105 |
|
|
void
|
106 |
|
|
ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason)
|
107 |
|
|
{
|
108 |
|
|
struct ieee80211softmac_network *found;
|
109 |
|
|
|
110 |
|
|
if (mac->associnfo.bssvalid && mac->associnfo.associated) {
|
111 |
|
|
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
|
112 |
|
|
if (found)
|
113 |
|
|
ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
|
114 |
|
|
}
|
115 |
|
|
|
116 |
|
|
ieee80211softmac_disassoc(mac);
|
117 |
|
|
}
|
118 |
|
|
|
119 |
|
|
static inline int
|
120 |
|
|
we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
|
121 |
|
|
{
|
122 |
|
|
int idx;
|
123 |
|
|
u8 rate;
|
124 |
|
|
|
125 |
|
|
for (idx = 0; idx < (from_len); idx++) {
|
126 |
|
|
rate = (from)[idx];
|
127 |
|
|
if (!(rate & IEEE80211_BASIC_RATE_MASK))
|
128 |
|
|
continue;
|
129 |
|
|
rate &= ~IEEE80211_BASIC_RATE_MASK;
|
130 |
|
|
if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
|
131 |
|
|
return 0;
|
132 |
|
|
}
|
133 |
|
|
return 1;
|
134 |
|
|
}
|
135 |
|
|
|
136 |
|
|
static int
|
137 |
|
|
network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
|
138 |
|
|
{
|
139 |
|
|
/* we cannot associate to networks whose name we don't know */
|
140 |
|
|
if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
|
141 |
|
|
return 0;
|
142 |
|
|
/* do not associate to a network whose BSSBasicRateSet we cannot support */
|
143 |
|
|
if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
|
144 |
|
|
return 0;
|
145 |
|
|
/* do we really need to check the ex rates? */
|
146 |
|
|
if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
|
147 |
|
|
return 0;
|
148 |
|
|
|
149 |
|
|
/* assume that users know what they're doing ...
|
150 |
|
|
* (note we don't let them select a net we're incompatible with) */
|
151 |
|
|
if (mac->associnfo.bssfixed) {
|
152 |
|
|
return !memcmp(mac->associnfo.bssid, net->bssid, ETH_ALEN);
|
153 |
|
|
}
|
154 |
|
|
|
155 |
|
|
/* if 'ANY' network requested, take any that doesn't have privacy enabled */
|
156 |
|
|
if (mac->associnfo.req_essid.len == 0
|
157 |
|
|
&& !(net->capability & WLAN_CAPABILITY_PRIVACY))
|
158 |
|
|
return 1;
|
159 |
|
|
if (net->ssid_len != mac->associnfo.req_essid.len)
|
160 |
|
|
return 0;
|
161 |
|
|
if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
|
162 |
|
|
return 1;
|
163 |
|
|
return 0;
|
164 |
|
|
}
|
165 |
|
|
|
166 |
|
|
static void
|
167 |
|
|
ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context)
|
168 |
|
|
{
|
169 |
|
|
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
|
170 |
|
|
ieee80211softmac_assoc_work(&mac->associnfo.work.work);
|
171 |
|
|
}
|
172 |
|
|
|
173 |
|
|
static void
|
174 |
|
|
ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context)
|
175 |
|
|
{
|
176 |
|
|
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
|
177 |
|
|
|
178 |
|
|
switch (event_type) {
|
179 |
|
|
case IEEE80211SOFTMAC_EVENT_AUTHENTICATED:
|
180 |
|
|
ieee80211softmac_assoc_work(&mac->associnfo.work.work);
|
181 |
|
|
break;
|
182 |
|
|
case IEEE80211SOFTMAC_EVENT_AUTH_FAILED:
|
183 |
|
|
case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT:
|
184 |
|
|
ieee80211softmac_disassoc(mac);
|
185 |
|
|
break;
|
186 |
|
|
}
|
187 |
|
|
}
|
188 |
|
|
|
189 |
|
|
/* This function is called to handle userspace requests (asynchronously) */
|
190 |
|
|
void
|
191 |
|
|
ieee80211softmac_assoc_work(struct work_struct *work)
|
192 |
|
|
{
|
193 |
|
|
struct ieee80211softmac_device *mac =
|
194 |
|
|
container_of(work, struct ieee80211softmac_device,
|
195 |
|
|
associnfo.work.work);
|
196 |
|
|
struct ieee80211softmac_network *found = NULL;
|
197 |
|
|
struct ieee80211_network *net = NULL, *best = NULL;
|
198 |
|
|
int bssvalid;
|
199 |
|
|
unsigned long flags;
|
200 |
|
|
|
201 |
|
|
mutex_lock(&mac->associnfo.mutex);
|
202 |
|
|
|
203 |
|
|
if (!mac->associnfo.associating)
|
204 |
|
|
goto out;
|
205 |
|
|
|
206 |
|
|
/* ieee80211_disassoc might clear this */
|
207 |
|
|
bssvalid = mac->associnfo.bssvalid;
|
208 |
|
|
|
209 |
|
|
/* meh */
|
210 |
|
|
if (mac->associnfo.associated)
|
211 |
|
|
ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
|
212 |
|
|
|
213 |
|
|
/* try to find the requested network in our list, if we found one already */
|
214 |
|
|
if (bssvalid || mac->associnfo.bssfixed)
|
215 |
|
|
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
|
216 |
|
|
|
217 |
|
|
/* Search the ieee80211 networks for this network if we didn't find it by bssid,
|
218 |
|
|
* but only if we've scanned at least once (to get a better list of networks to
|
219 |
|
|
* select from). If we have not scanned before, the !found logic below will be
|
220 |
|
|
* invoked and will scan. */
|
221 |
|
|
if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT))
|
222 |
|
|
{
|
223 |
|
|
s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning
|
224 |
|
|
because it cannot follow the best pointer logic. */
|
225 |
|
|
spin_lock_irqsave(&mac->ieee->lock, flags);
|
226 |
|
|
list_for_each_entry(net, &mac->ieee->network_list, list) {
|
227 |
|
|
/* we're supposed to find the network with
|
228 |
|
|
* the best signal here, as we're asked to join
|
229 |
|
|
* any network with a specific ESSID, and many
|
230 |
|
|
* different ones could have that.
|
231 |
|
|
*
|
232 |
|
|
* I'll for now just go with the reported rssi.
|
233 |
|
|
*
|
234 |
|
|
* We also should take into account the rateset
|
235 |
|
|
* here to find the best BSSID to try.
|
236 |
|
|
*/
|
237 |
|
|
if (network_matches_request(mac, net)) {
|
238 |
|
|
if (!best) {
|
239 |
|
|
best = net;
|
240 |
|
|
rssi = best->stats.rssi;
|
241 |
|
|
continue;
|
242 |
|
|
}
|
243 |
|
|
/* we already had a matching network, so
|
244 |
|
|
* compare their properties to get the
|
245 |
|
|
* better of the two ... (see above)
|
246 |
|
|
*/
|
247 |
|
|
if (rssi < net->stats.rssi) {
|
248 |
|
|
best = net;
|
249 |
|
|
rssi = best->stats.rssi;
|
250 |
|
|
}
|
251 |
|
|
}
|
252 |
|
|
}
|
253 |
|
|
/* if we unlock here, we might get interrupted and the `best'
|
254 |
|
|
* pointer could go stale */
|
255 |
|
|
if (best) {
|
256 |
|
|
found = ieee80211softmac_create_network(mac, best);
|
257 |
|
|
/* if found is still NULL, then we got -ENOMEM somewhere */
|
258 |
|
|
if (found)
|
259 |
|
|
ieee80211softmac_add_network(mac, found);
|
260 |
|
|
}
|
261 |
|
|
spin_unlock_irqrestore(&mac->ieee->lock, flags);
|
262 |
|
|
}
|
263 |
|
|
|
264 |
|
|
if (!found) {
|
265 |
|
|
if (mac->associnfo.scan_retry > 0) {
|
266 |
|
|
mac->associnfo.scan_retry--;
|
267 |
|
|
|
268 |
|
|
/* We know of no such network. Let's scan.
|
269 |
|
|
* NB: this also happens if we had no memory to copy the network info...
|
270 |
|
|
* Maybe we can hope to have more memory after scanning finishes ;)
|
271 |
|
|
*/
|
272 |
|
|
dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
|
273 |
|
|
ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
|
274 |
|
|
if (ieee80211softmac_start_scan(mac)) {
|
275 |
|
|
dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
|
276 |
|
|
}
|
277 |
|
|
goto out;
|
278 |
|
|
} else {
|
279 |
|
|
mac->associnfo.associating = 0;
|
280 |
|
|
mac->associnfo.associated = 0;
|
281 |
|
|
|
282 |
|
|
dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
|
283 |
|
|
/* reset the retry counter for the next user request since we
|
284 |
|
|
* break out and don't reschedule ourselves after this point. */
|
285 |
|
|
mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
|
286 |
|
|
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
|
287 |
|
|
goto out;
|
288 |
|
|
}
|
289 |
|
|
}
|
290 |
|
|
|
291 |
|
|
/* reset the retry counter for the next user request since we
|
292 |
|
|
* now found a net and will try to associate to it, but not
|
293 |
|
|
* schedule this function again. */
|
294 |
|
|
mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
|
295 |
|
|
mac->associnfo.bssvalid = 1;
|
296 |
|
|
memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
|
297 |
|
|
/* copy the ESSID for displaying it */
|
298 |
|
|
mac->associnfo.associate_essid.len = found->essid.len;
|
299 |
|
|
memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
|
300 |
|
|
|
301 |
|
|
/* we found a network! authenticate (if necessary) and associate to it. */
|
302 |
|
|
if (found->authenticating) {
|
303 |
|
|
dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
|
304 |
|
|
if(!mac->associnfo.assoc_wait) {
|
305 |
|
|
mac->associnfo.assoc_wait = 1;
|
306 |
|
|
ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
|
307 |
|
|
}
|
308 |
|
|
goto out;
|
309 |
|
|
}
|
310 |
|
|
if (!found->authenticated && !found->authenticating) {
|
311 |
|
|
/* This relies on the fact that _auth_req only queues the work,
|
312 |
|
|
* otherwise adding the notification would be racy. */
|
313 |
|
|
if (!ieee80211softmac_auth_req(mac, found)) {
|
314 |
|
|
if(!mac->associnfo.assoc_wait) {
|
315 |
|
|
dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
|
316 |
|
|
mac->associnfo.assoc_wait = 1;
|
317 |
|
|
ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
|
318 |
|
|
}
|
319 |
|
|
} else {
|
320 |
|
|
printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
|
321 |
|
|
mac->associnfo.assoc_wait = 0;
|
322 |
|
|
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
|
323 |
|
|
}
|
324 |
|
|
goto out;
|
325 |
|
|
}
|
326 |
|
|
/* finally! now we can start associating */
|
327 |
|
|
mac->associnfo.assoc_wait = 0;
|
328 |
|
|
ieee80211softmac_assoc(mac, found);
|
329 |
|
|
|
330 |
|
|
out:
|
331 |
|
|
mutex_unlock(&mac->associnfo.mutex);
|
332 |
|
|
}
|
333 |
|
|
|
334 |
|
|
/* call this to do whatever is necessary when we're associated */
|
335 |
|
|
static void
|
336 |
|
|
ieee80211softmac_associated(struct ieee80211softmac_device *mac,
|
337 |
|
|
struct ieee80211_assoc_response * resp,
|
338 |
|
|
struct ieee80211softmac_network *net)
|
339 |
|
|
{
|
340 |
|
|
u16 cap = le16_to_cpu(resp->capability);
|
341 |
|
|
u8 erp_value = net->erp_value;
|
342 |
|
|
|
343 |
|
|
mac->associnfo.associating = 0;
|
344 |
|
|
mac->bssinfo.supported_rates = net->supported_rates;
|
345 |
|
|
ieee80211softmac_recalc_txrates(mac);
|
346 |
|
|
|
347 |
|
|
mac->associnfo.associated = 1;
|
348 |
|
|
|
349 |
|
|
mac->associnfo.short_preamble_available =
|
350 |
|
|
(cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
|
351 |
|
|
ieee80211softmac_process_erp(mac, erp_value);
|
352 |
|
|
|
353 |
|
|
if (mac->set_bssid_filter)
|
354 |
|
|
mac->set_bssid_filter(mac->dev, net->bssid);
|
355 |
|
|
memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
|
356 |
|
|
netif_carrier_on(mac->dev);
|
357 |
|
|
|
358 |
|
|
mac->association_id = le16_to_cpup(&resp->aid);
|
359 |
|
|
}
|
360 |
|
|
|
361 |
|
|
/* received frame handling functions */
|
362 |
|
|
int
|
363 |
|
|
ieee80211softmac_handle_assoc_response(struct net_device * dev,
|
364 |
|
|
struct ieee80211_assoc_response * resp,
|
365 |
|
|
struct ieee80211_network * _ieee80211_network)
|
366 |
|
|
{
|
367 |
|
|
/* NOTE: the network parameter has to be mostly ignored by
|
368 |
|
|
* this code because it is the ieee80211's pointer
|
369 |
|
|
* to the struct, not ours (we made a copy)
|
370 |
|
|
*/
|
371 |
|
|
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
|
372 |
|
|
u16 status = le16_to_cpup(&resp->status);
|
373 |
|
|
struct ieee80211softmac_network *network = NULL;
|
374 |
|
|
unsigned long flags;
|
375 |
|
|
DECLARE_MAC_BUF(mac2);
|
376 |
|
|
|
377 |
|
|
if (unlikely(!mac->running))
|
378 |
|
|
return -ENODEV;
|
379 |
|
|
|
380 |
|
|
spin_lock_irqsave(&mac->lock, flags);
|
381 |
|
|
|
382 |
|
|
if (!mac->associnfo.associating) {
|
383 |
|
|
/* we race against the timeout function, so make sure
|
384 |
|
|
* only one of us can do work */
|
385 |
|
|
spin_unlock_irqrestore(&mac->lock, flags);
|
386 |
|
|
return 0;
|
387 |
|
|
}
|
388 |
|
|
network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
|
389 |
|
|
|
390 |
|
|
/* someone sending us things without us knowing him? Ignore. */
|
391 |
|
|
if (!network) {
|
392 |
|
|
dprintk(KERN_INFO PFX "Received unrequested assocation response from %s\n",
|
393 |
|
|
print_mac(mac2, resp->header.addr3));
|
394 |
|
|
spin_unlock_irqrestore(&mac->lock, flags);
|
395 |
|
|
return 0;
|
396 |
|
|
}
|
397 |
|
|
|
398 |
|
|
/* now that we know it was for us, we can cancel the timeout */
|
399 |
|
|
cancel_delayed_work(&mac->associnfo.timeout);
|
400 |
|
|
|
401 |
|
|
/* if the association response included an ERP IE, update our saved
|
402 |
|
|
* copy */
|
403 |
|
|
if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
|
404 |
|
|
network->erp_value = _ieee80211_network->erp_value;
|
405 |
|
|
|
406 |
|
|
switch (status) {
|
407 |
|
|
case 0:
|
408 |
|
|
dprintk(KERN_INFO PFX "associated!\n");
|
409 |
|
|
ieee80211softmac_associated(mac, resp, network);
|
410 |
|
|
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
|
411 |
|
|
break;
|
412 |
|
|
case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
|
413 |
|
|
if (!network->auth_desynced_once) {
|
414 |
|
|
/* there seem to be a few rare cases where our view of
|
415 |
|
|
* the world is obscured, or buggy APs that don't DEAUTH
|
416 |
|
|
* us properly. So we handle that, but allow it only once.
|
417 |
|
|
*/
|
418 |
|
|
printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
|
419 |
|
|
network->authenticated = 0;
|
420 |
|
|
/* we don't want to do this more than once ... */
|
421 |
|
|
network->auth_desynced_once = 1;
|
422 |
|
|
queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
|
423 |
|
|
break;
|
424 |
|
|
}
|
425 |
|
|
default:
|
426 |
|
|
dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
|
427 |
|
|
mac->associnfo.associating = 0;
|
428 |
|
|
mac->associnfo.bssvalid = 0;
|
429 |
|
|
mac->associnfo.associated = 0;
|
430 |
|
|
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
|
431 |
|
|
}
|
432 |
|
|
|
433 |
|
|
spin_unlock_irqrestore(&mac->lock, flags);
|
434 |
|
|
return 0;
|
435 |
|
|
}
|
436 |
|
|
|
437 |
|
|
void
|
438 |
|
|
ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
|
439 |
|
|
{
|
440 |
|
|
unsigned long flags;
|
441 |
|
|
|
442 |
|
|
spin_lock_irqsave(&mac->lock, flags);
|
443 |
|
|
mac->associnfo.associating = 1;
|
444 |
|
|
queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
|
445 |
|
|
spin_unlock_irqrestore(&mac->lock, flags);
|
446 |
|
|
}
|
447 |
|
|
|
448 |
|
|
int
|
449 |
|
|
ieee80211softmac_handle_disassoc(struct net_device * dev,
|
450 |
|
|
struct ieee80211_disassoc *disassoc)
|
451 |
|
|
{
|
452 |
|
|
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
|
453 |
|
|
|
454 |
|
|
if (unlikely(!mac->running))
|
455 |
|
|
return -ENODEV;
|
456 |
|
|
|
457 |
|
|
if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
|
458 |
|
|
return 0;
|
459 |
|
|
|
460 |
|
|
if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
|
461 |
|
|
return 0;
|
462 |
|
|
|
463 |
|
|
dprintk(KERN_INFO PFX "got disassoc frame\n");
|
464 |
|
|
ieee80211softmac_disassoc(mac);
|
465 |
|
|
|
466 |
|
|
ieee80211softmac_try_reassoc(mac);
|
467 |
|
|
|
468 |
|
|
return 0;
|
469 |
|
|
}
|
470 |
|
|
|
471 |
|
|
int
|
472 |
|
|
ieee80211softmac_handle_reassoc_req(struct net_device * dev,
|
473 |
|
|
struct ieee80211_reassoc_request * resp)
|
474 |
|
|
{
|
475 |
|
|
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
|
476 |
|
|
struct ieee80211softmac_network *network;
|
477 |
|
|
|
478 |
|
|
if (unlikely(!mac->running))
|
479 |
|
|
return -ENODEV;
|
480 |
|
|
|
481 |
|
|
network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
|
482 |
|
|
if (!network) {
|
483 |
|
|
dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
|
484 |
|
|
return 0;
|
485 |
|
|
}
|
486 |
|
|
queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
|
487 |
|
|
|
488 |
|
|
return 0;
|
489 |
|
|
}
|