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