]> err.no Git - linux-2.6/blob - net/ieee80211/softmac/ieee80211softmac_module.c
Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/pasem...
[linux-2.6] / net / ieee80211 / softmac / ieee80211softmac_module.c
1 /*
2  * Contains some basic softmac functions along with module registration code etc.
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 #include <linux/sort.h>
29 #include <linux/etherdevice.h>
30
31 struct net_device *alloc_ieee80211softmac(int sizeof_priv)
32 {
33         struct ieee80211softmac_device *softmac;
34         struct net_device *dev;
35
36         dev = alloc_ieee80211(sizeof(*softmac) + sizeof_priv);
37         if (!dev)
38                 return NULL;
39         softmac = ieee80211_priv(dev);
40         softmac->wq = create_freezeable_workqueue("softmac");
41         if (!softmac->wq) {
42                 free_ieee80211(dev);
43                 return NULL;
44         }
45
46         softmac->dev = dev;
47         softmac->ieee = netdev_priv(dev);
48         spin_lock_init(&softmac->lock);
49
50         softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
51         softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
52         softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
53         softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
54         softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
55         softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
56         softmac->scaninfo = NULL;
57
58         softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
59
60         /* TODO: initialise all the other callbacks in the ieee struct
61          *       (once they're written)
62          */
63
64         INIT_LIST_HEAD(&softmac->auth_queue);
65         INIT_LIST_HEAD(&softmac->network_list);
66         INIT_LIST_HEAD(&softmac->events);
67
68         mutex_init(&softmac->associnfo.mutex);
69         INIT_DELAYED_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work);
70         INIT_DELAYED_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout);
71         softmac->start_scan = ieee80211softmac_start_scan_implementation;
72         softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
73         softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
74
75         /* to start with, we can't send anything ... */
76         netif_carrier_off(dev);
77
78         return dev;
79 }
80 EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
81
82 /* Clears the pending work queue items, stops all scans, etc. */
83 void
84 ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
85 {
86         unsigned long flags;
87         struct ieee80211softmac_event *eventptr, *eventtmp;
88         struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
89         struct ieee80211softmac_network *netptr, *nettmp;
90
91         ieee80211softmac_stop_scan(sm);
92         ieee80211softmac_wait_for_scan(sm);
93
94         spin_lock_irqsave(&sm->lock, flags);
95         sm->running = 0;
96
97         /* Free all pending assoc work items */
98         cancel_delayed_work(&sm->associnfo.work);
99
100         /* Free all pending scan work items */
101         if(sm->scaninfo != NULL)
102                 cancel_delayed_work(&sm->scaninfo->softmac_scan);
103
104         /* Free all pending auth work items */
105         list_for_each_entry(authptr, &sm->auth_queue, list)
106                 cancel_delayed_work(&authptr->work);
107
108         /* delete all pending event calls and work items */
109         list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
110                 cancel_delayed_work(&eventptr->work);
111
112         spin_unlock_irqrestore(&sm->lock, flags);
113         flush_workqueue(sm->wq);
114
115         /* now we should be save and no longer need locking... */
116         spin_lock_irqsave(&sm->lock, flags);
117         /* Free all pending auth work items */
118         list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
119                 list_del(&authptr->list);
120                 kfree(authptr);
121         }
122
123         /* delete all pending event calls and work items */
124         list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
125                 list_del(&eventptr->list);
126                 kfree(eventptr);
127         }
128
129         /* Free all networks */
130         list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
131                 ieee80211softmac_del_network_locked(sm, netptr);
132                 if(netptr->challenge != NULL)
133                         kfree(netptr->challenge);
134                 kfree(netptr);
135         }
136
137         spin_unlock_irqrestore(&sm->lock, flags);
138 }
139 EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
140
141 void free_ieee80211softmac(struct net_device *dev)
142 {
143         struct ieee80211softmac_device *sm = ieee80211_priv(dev);
144         ieee80211softmac_clear_pending_work(sm);
145         kfree(sm->scaninfo);
146         kfree(sm->wpa.IE);
147         destroy_workqueue(sm->wq);
148         free_ieee80211(dev);
149 }
150 EXPORT_SYMBOL_GPL(free_ieee80211softmac);
151
152 static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
153 {
154         struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
155         /* I took out the sorting check, we're seperating by modulation now. */
156         if (ri->count)
157                 return;
158         /* otherwise assume we hav'em all! */
159         if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
160                 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
161                 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
162                 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
163                 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
164         }
165         if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
166                 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
167                 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
168                 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
169                 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
170                 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
171                 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
172                 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
173                 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
174         }
175 }
176
177 int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
178 {
179         int search;
180         u8 search_rate;
181
182         for (search = 0; search < ri->count; search++) {
183                 search_rate = ri->rates[search];
184                 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
185                 if (rate == search_rate)
186                         return 1;
187         }
188
189         return 0;
190 }
191
192 u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
193         struct ieee80211softmac_ratesinfo *ri, int basic_only)
194 {
195         u8 user_rate = mac->txrates.user_rate;
196         int i;
197
198         if (ri->count == 0)
199                 return IEEE80211_CCK_RATE_1MB;
200
201         for (i = ri->count - 1; i >= 0; i--) {
202                 u8 rate = ri->rates[i];
203                 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
204                         continue;
205                 rate &= ~IEEE80211_BASIC_RATE_MASK;
206                 if (rate > user_rate)
207                         continue;
208                 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
209                         return rate;
210         }
211
212         /* If we haven't found a suitable rate by now, just trust the user */
213         return user_rate;
214 }
215 EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
216
217 void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
218         u8 erp_value)
219 {
220         int use_protection;
221         int short_preamble;
222         u32 changes = 0;
223
224         /* Barker preamble mode */
225         short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
226                           && mac->associnfo.short_preamble_available) ? 1 : 0;
227
228         /* Protection needed? */
229         use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
230
231         if (mac->bssinfo.short_preamble != short_preamble) {
232                 changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
233                 mac->bssinfo.short_preamble = short_preamble;
234         }
235
236         if (mac->bssinfo.use_protection != use_protection) {
237                 changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
238                 mac->bssinfo.use_protection = use_protection;
239         }
240
241         if (mac->bssinfo_change && changes)
242                 mac->bssinfo_change(mac->dev, changes);
243 }
244
245 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
246 {
247         struct ieee80211softmac_txrates *txrates = &mac->txrates;
248         u32 change = 0;
249
250         change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
251         txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
252
253         change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
254         txrates->default_fallback = lower_rate(mac, txrates->default_rate);
255
256         change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
257         txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
258
259         if (mac->txrates_change)
260                 mac->txrates_change(mac->dev, change);
261
262 }
263
264 void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
265 {
266         struct ieee80211_device *ieee = mac->ieee;
267         u32 change = 0;
268         struct ieee80211softmac_txrates *txrates = &mac->txrates;
269         struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
270
271         /* TODO: We need some kind of state machine to lower the default rates
272          *       if we loose too many packets.
273          */
274         /* Change the default txrate to the highest possible value.
275          * The txrate machine will lower it, if it is too high.
276          */
277         if (ieee->modulation & IEEE80211_OFDM_MODULATION)
278                 txrates->user_rate = IEEE80211_OFDM_RATE_24MB;
279         else
280                 txrates->user_rate = IEEE80211_CCK_RATE_11MB;
281
282         txrates->default_rate = IEEE80211_CCK_RATE_1MB;
283         change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
284
285         txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
286         change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
287
288         txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
289         change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
290
291         txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
292         change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
293
294         if (mac->txrates_change)
295                 mac->txrates_change(mac->dev, change);
296
297         change = 0;
298
299         bssinfo->supported_rates.count = 0;
300         memset(bssinfo->supported_rates.rates, 0,
301                 sizeof(bssinfo->supported_rates.rates));
302         change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
303
304         bssinfo->short_preamble = 0;
305         change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
306
307         bssinfo->use_protection = 0;
308         change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
309
310         if (mac->bssinfo_change)
311                 mac->bssinfo_change(mac->dev, change);
312
313         mac->running = 1;
314 }
315
316 void ieee80211softmac_start(struct net_device *dev)
317 {
318         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
319
320         ieee80211softmac_start_check_rates(mac);
321         ieee80211softmac_init_bss(mac);
322 }
323 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
324
325 void ieee80211softmac_stop(struct net_device *dev)
326 {
327         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
328
329         ieee80211softmac_clear_pending_work(mac);
330 }
331 EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
332
333 void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
334 {
335         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
336         unsigned long flags;
337
338         spin_lock_irqsave(&mac->lock, flags);
339         memcpy(mac->ratesinfo.rates, rates, count);
340         mac->ratesinfo.count = count;
341         spin_unlock_irqrestore(&mac->lock, flags);
342 }
343 EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
344
345 static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
346 {
347         int i;
348         struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
349
350         for (i=0; i<ri->count-1; i++) {
351                 if (ri->rates[i] == rate)
352                         return ri->rates[i+1];
353         }
354         /* I guess we can't go any higher... */
355         return ri->rates[ri->count];
356 }
357
358 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
359 {
360         int i;
361         struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
362
363         for (i=delta; i<ri->count; i++) {
364                 if (ri->rates[i] == rate)
365                         return ri->rates[i-delta];
366         }
367         /* I guess we can't go any lower... */
368         return ri->rates[0];
369 }
370
371 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
372                                                  int amount)
373 {
374         u8 default_rate = mac->txrates.default_rate;
375         u8 default_fallback = mac->txrates.default_fallback;
376         u32 changes = 0;
377
378         //TODO: This is highly experimental code.
379         //      Maybe the dynamic rate selection does not work
380         //      and it has to be removed again.
381
382 printk("badness %d\n", mac->txrate_badness);
383         mac->txrate_badness += amount;
384         if (mac->txrate_badness <= -1000) {
385                 /* Very small badness. Try a faster bitrate. */
386                 default_rate = raise_rate(mac, default_rate);
387                 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
388                 default_fallback = get_fallback_rate(mac, default_rate);
389                 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
390                 mac->txrate_badness = 0;
391 printk("Bitrate raised to %u\n", default_rate);
392         } else if (mac->txrate_badness >= 10000) {
393                 /* Very high badness. Try a slower bitrate. */
394                 default_rate = lower_rate(mac, default_rate);
395                 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
396                 default_fallback = get_fallback_rate(mac, default_rate);
397                 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
398                 mac->txrate_badness = 0;
399 printk("Bitrate lowered to %u\n", default_rate);
400         }
401
402         mac->txrates.default_rate = default_rate;
403         mac->txrates.default_fallback = default_fallback;
404
405         if (changes && mac->txrates_change)
406                 mac->txrates_change(mac->dev, changes);
407 }
408
409 void ieee80211softmac_fragment_lost(struct net_device *dev,
410                                     u16 wl_seq)
411 {
412         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
413         unsigned long flags;
414
415         spin_lock_irqsave(&mac->lock, flags);
416         ieee80211softmac_add_txrates_badness(mac, 1000);
417         //TODO
418
419         spin_unlock_irqrestore(&mac->lock, flags);
420 }
421 EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
422
423 static int rate_cmp(const void *a_, const void *b_) {
424         u8 *a, *b;
425         a = (u8*)a_;
426         b = (u8*)b_;
427         return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
428 }
429
430 /* Allocate a softmac network struct and fill it from a network */
431 struct ieee80211softmac_network *
432 ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
433         struct ieee80211_network *net)
434 {
435         struct ieee80211softmac_network *softnet;
436         softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
437         if(softnet == NULL)
438                 return NULL;
439         memcpy(softnet->bssid, net->bssid, ETH_ALEN);
440         softnet->channel = net->channel;
441         softnet->essid.len = net->ssid_len;
442         memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
443
444         /* copy rates over */
445         softnet->supported_rates.count = net->rates_len;
446         memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
447         memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
448         softnet->supported_rates.count += net->rates_ex_len;
449         sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
450
451         /* we save the ERP value because it is needed at association time, and
452          * many AP's do not include an ERP IE in the association response. */
453         softnet->erp_value = net->erp_value;
454
455         softnet->capabilities = net->capability;
456         return softnet;
457 }
458
459
460 /* Add a network to the list, while locked */
461 void
462 ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
463         struct ieee80211softmac_network *add_net)
464 {
465         struct ieee80211softmac_network *softmac_net;
466
467         list_for_each_entry(softmac_net, &mac->network_list, list) {
468                 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
469                         return;
470         }
471         list_add(&(add_net->list), &mac->network_list);
472 }
473
474 /* Add a network to the list, with locking */
475 void
476 ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
477         struct ieee80211softmac_network *add_net)
478 {
479         unsigned long flags;
480         spin_lock_irqsave(&mac->lock, flags);
481         ieee80211softmac_add_network_locked(mac, add_net);
482         spin_unlock_irqrestore(&mac->lock, flags);
483 }
484
485
486 /* Delete a network from the list, while locked*/
487 void
488 ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
489         struct ieee80211softmac_network *del_net)
490 {
491         list_del(&(del_net->list));
492 }
493
494 /* Delete a network from the list with locking */
495 void
496 ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
497         struct ieee80211softmac_network *del_net)
498 {
499         unsigned long flags;
500         spin_lock_irqsave(&mac->lock, flags);
501         ieee80211softmac_del_network_locked(mac, del_net);
502         spin_unlock_irqrestore(&mac->lock, flags);
503 }
504
505 /* Get a network from the list by MAC while locked */
506 struct ieee80211softmac_network *
507 ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
508         u8 *bssid)
509 {
510         struct ieee80211softmac_network *softmac_net;
511
512         list_for_each_entry(softmac_net, &mac->network_list, list) {
513                 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
514                         return softmac_net;
515         }
516         return NULL;
517 }
518
519 /* Get a network from the list by BSSID with locking */
520 struct ieee80211softmac_network *
521 ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
522         u8 *bssid)
523 {
524         unsigned long flags;
525         struct ieee80211softmac_network *softmac_net;
526
527         spin_lock_irqsave(&mac->lock, flags);
528         softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
529         spin_unlock_irqrestore(&mac->lock, flags);
530         return softmac_net;
531 }
532
533 /* Get a network from the list by ESSID while locked */
534 struct ieee80211softmac_network *
535 ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
536         struct ieee80211softmac_essid *essid)
537 {
538         struct ieee80211softmac_network *softmac_net;
539
540         list_for_each_entry(softmac_net, &mac->network_list, list) {
541                 if (softmac_net->essid.len == essid->len &&
542                         !memcmp(softmac_net->essid.data, essid->data, essid->len))
543                         return softmac_net;
544         }
545         return NULL;
546 }
547
548 /* Get a network from the list by ESSID with locking */
549 struct ieee80211softmac_network *
550 ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
551         struct ieee80211softmac_essid *essid)
552 {
553         unsigned long flags;
554         struct ieee80211softmac_network *softmac_net = NULL;
555
556         spin_lock_irqsave(&mac->lock, flags);
557         softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
558         spin_unlock_irqrestore(&mac->lock, flags);
559         return softmac_net;
560 }
561
562 MODULE_LICENSE("GPL");
563 MODULE_AUTHOR("Johannes Berg");
564 MODULE_AUTHOR("Joseph Jezak");
565 MODULE_AUTHOR("Larry Finger");
566 MODULE_AUTHOR("Danny van Dyk");
567 MODULE_AUTHOR("Michael Buesch");
568 MODULE_DESCRIPTION("802.11 software MAC");