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