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