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