OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [ieee80211/] [softmac/] [ieee80211softmac_assoc.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.