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