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