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