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