2 * Contains some basic softmac functions along with module registration code etc.
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>
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.
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
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
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
27 #include "ieee80211softmac_priv.h"
28 #include <linux/sort.h>
29 #include <linux/etherdevice.h>
31 struct net_device *alloc_ieee80211softmac(int sizeof_priv)
33 struct ieee80211softmac_device *softmac;
34 struct net_device *dev;
36 dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
37 softmac = ieee80211_priv(dev);
39 softmac->ieee = netdev_priv(dev);
40 spin_lock_init(&softmac->lock);
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;
50 softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
52 /* TODO: initialise all the other callbacks in the ieee struct
53 * (once they're written)
56 INIT_LIST_HEAD(&softmac->auth_queue);
57 INIT_LIST_HEAD(&softmac->network_list);
58 INIT_LIST_HEAD(&softmac->events);
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;
66 /* to start with, we can't send anything ... */
67 netif_carrier_off(dev);
71 EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
73 /* Clears the pending work queue items, stops all scans, etc. */
75 ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
78 struct ieee80211softmac_event *eventptr, *eventtmp;
79 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
80 struct ieee80211softmac_network *netptr, *nettmp;
82 ieee80211softmac_stop_scan(sm);
83 ieee80211softmac_wait_for_scan(sm);
85 spin_lock_irqsave(&sm->lock, flags);
88 /* Free all pending assoc work items */
89 cancel_delayed_work(&sm->associnfo.work);
91 /* Free all pending scan work items */
92 if(sm->scaninfo != NULL)
93 cancel_delayed_work(&sm->scaninfo->softmac_scan);
95 /* Free all pending auth work items */
96 list_for_each_entry(authptr, &sm->auth_queue, list)
97 cancel_delayed_work(&authptr->work);
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);
103 spin_unlock_irqrestore(&sm->lock, flags);
104 flush_scheduled_work();
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);
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);
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);
128 spin_unlock_irqrestore(&sm->lock, flags);
130 EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
132 void free_ieee80211softmac(struct net_device *dev)
134 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
135 ieee80211softmac_clear_pending_work(sm);
140 EXPORT_SYMBOL_GPL(free_ieee80211softmac);
142 static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
144 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
145 /* I took out the sorting check, we're seperating by modulation now. */
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;
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;
167 int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
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)
182 /* Finds the highest rate which is:
183 * 1. Present in ri (optionally a basic rate)
184 * 2. Supported by the device
185 * 3. Less than or equal to the user-defined rate
187 static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
188 struct ieee80211softmac_ratesinfo *ri, int basic_only)
190 u8 user_rate = mac->txrates.user_rate;
193 if (ri->count == 0) {
194 dprintk(KERN_ERR PFX "empty ratesinfo?\n");
195 return IEEE80211_CCK_RATE_1MB;
198 for (i = ri->count - 1; i >= 0; i--) {
199 u8 rate = ri->rates[i];
200 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
202 rate &= ~IEEE80211_BASIC_RATE_MASK;
203 if (rate > user_rate)
205 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
209 /* If we haven't found a suitable rate by now, just trust the user */
213 void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
220 /* Barker preamble mode */
221 short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
222 && mac->associnfo.short_preamble_available) ? 1 : 0;
224 /* Protection needed? */
225 use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
227 if (mac->bssinfo.short_preamble != short_preamble) {
228 changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
229 mac->bssinfo.short_preamble = short_preamble;
232 if (mac->bssinfo.use_protection != use_protection) {
233 changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
234 mac->bssinfo.use_protection = use_protection;
237 if (mac->bssinfo_change && changes)
238 mac->bssinfo_change(mac->dev, changes);
241 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
243 struct ieee80211softmac_txrates *txrates = &mac->txrates;
246 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
247 txrates->default_rate = highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
249 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
250 txrates->default_fallback = lower_rate(mac, txrates->default_rate);
252 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
253 txrates->mcast_rate = highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
255 if (mac->txrates_change)
256 mac->txrates_change(mac->dev, change);
260 void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
262 struct ieee80211_device *ieee = mac->ieee;
264 struct ieee80211softmac_txrates *txrates = &mac->txrates;
265 struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
267 /* TODO: We need some kind of state machine to lower the default rates
268 * if we loose too many packets.
270 /* Change the default txrate to the highest possible value.
271 * The txrate machine will lower it, if it is too high.
273 /* FIXME: We don't correctly handle backing down to lower
274 rates, so 801.11g devices start off at 11M for now. People
275 can manually change it if they really need to, but 11M is
276 more reliable. Note similar logic in
277 ieee80211softmac_wx_set_rate() */
278 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
279 txrates->user_rate = IEEE80211_CCK_RATE_11MB;
280 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
281 txrates->user_rate = IEEE80211_OFDM_RATE_54MB;
285 txrates->default_rate = IEEE80211_CCK_RATE_1MB;
286 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
288 txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
289 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
291 txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
292 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
294 txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
295 change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
297 if (mac->txrates_change)
298 mac->txrates_change(mac->dev, change);
302 bssinfo->supported_rates.count = 0;
303 memset(bssinfo->supported_rates.rates, 0,
304 sizeof(bssinfo->supported_rates.rates));
305 change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
307 bssinfo->short_preamble = 0;
308 change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
310 bssinfo->use_protection = 0;
311 change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
313 if (mac->bssinfo_change)
314 mac->bssinfo_change(mac->dev, change);
319 void ieee80211softmac_start(struct net_device *dev)
321 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
323 ieee80211softmac_start_check_rates(mac);
324 ieee80211softmac_init_bss(mac);
326 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
328 void ieee80211softmac_stop(struct net_device *dev)
330 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
332 ieee80211softmac_clear_pending_work(mac);
334 EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
336 void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
338 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
341 spin_lock_irqsave(&mac->lock, flags);
342 memcpy(mac->ratesinfo.rates, rates, count);
343 mac->ratesinfo.count = count;
344 spin_unlock_irqrestore(&mac->lock, flags);
346 EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
348 static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
351 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
353 for (i=0; i<ri->count-1; i++) {
354 if (ri->rates[i] == rate)
355 return ri->rates[i+1];
357 /* I guess we can't go any higher... */
358 return ri->rates[ri->count];
361 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
364 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
366 for (i=delta; i<ri->count; i++) {
367 if (ri->rates[i] == rate)
368 return ri->rates[i-delta];
370 /* I guess we can't go any lower... */
374 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
377 u8 default_rate = mac->txrates.default_rate;
378 u8 default_fallback = mac->txrates.default_fallback;
381 //TODO: This is highly experimental code.
382 // Maybe the dynamic rate selection does not work
383 // and it has to be removed again.
385 printk("badness %d\n", mac->txrate_badness);
386 mac->txrate_badness += amount;
387 if (mac->txrate_badness <= -1000) {
388 /* Very small badness. Try a faster bitrate. */
389 default_rate = raise_rate(mac, default_rate);
390 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
391 default_fallback = get_fallback_rate(mac, default_rate);
392 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
393 mac->txrate_badness = 0;
394 printk("Bitrate raised to %u\n", default_rate);
395 } else if (mac->txrate_badness >= 10000) {
396 /* Very high badness. Try a slower bitrate. */
397 default_rate = lower_rate(mac, default_rate);
398 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
399 default_fallback = get_fallback_rate(mac, default_rate);
400 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
401 mac->txrate_badness = 0;
402 printk("Bitrate lowered to %u\n", default_rate);
405 mac->txrates.default_rate = default_rate;
406 mac->txrates.default_fallback = default_fallback;
408 if (changes && mac->txrates_change)
409 mac->txrates_change(mac->dev, changes);
412 void ieee80211softmac_fragment_lost(struct net_device *dev,
415 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
418 spin_lock_irqsave(&mac->lock, flags);
419 ieee80211softmac_add_txrates_badness(mac, 1000);
422 spin_unlock_irqrestore(&mac->lock, flags);
424 EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
426 static int rate_cmp(const void *a_, const void *b_) {
430 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
433 /* Allocate a softmac network struct and fill it from a network */
434 struct ieee80211softmac_network *
435 ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
436 struct ieee80211_network *net)
438 struct ieee80211softmac_network *softnet;
439 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
442 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
443 softnet->channel = net->channel;
444 softnet->essid.len = net->ssid_len;
445 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
447 /* copy rates over */
448 softnet->supported_rates.count = net->rates_len;
449 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
450 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
451 softnet->supported_rates.count += net->rates_ex_len;
452 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
454 /* we save the ERP value because it is needed at association time, and
455 * many AP's do not include an ERP IE in the association response. */
456 softnet->erp_value = net->erp_value;
458 softnet->capabilities = net->capability;
463 /* Add a network to the list, while locked */
465 ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
466 struct ieee80211softmac_network *add_net)
468 struct list_head *list_ptr;
469 struct ieee80211softmac_network *softmac_net = NULL;
471 list_for_each(list_ptr, &mac->network_list) {
472 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
473 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
478 if(softmac_net == NULL)
479 list_add(&(add_net->list), &mac->network_list);
482 /* Add a network to the list, with locking */
484 ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
485 struct ieee80211softmac_network *add_net)
488 spin_lock_irqsave(&mac->lock, flags);
489 ieee80211softmac_add_network_locked(mac, add_net);
490 spin_unlock_irqrestore(&mac->lock, flags);
494 /* Delete a network from the list, while locked*/
496 ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
497 struct ieee80211softmac_network *del_net)
499 list_del(&(del_net->list));
502 /* Delete a network from the list with locking */
504 ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
505 struct ieee80211softmac_network *del_net)
508 spin_lock_irqsave(&mac->lock, flags);
509 ieee80211softmac_del_network_locked(mac, del_net);
510 spin_unlock_irqrestore(&mac->lock, flags);
513 /* Get a network from the list by MAC while locked */
514 struct ieee80211softmac_network *
515 ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
518 struct list_head *list_ptr;
519 struct ieee80211softmac_network *softmac_net = NULL;
520 list_for_each(list_ptr, &mac->network_list) {
521 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
522 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
530 /* Get a network from the list by BSSID with locking */
531 struct ieee80211softmac_network *
532 ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
536 struct ieee80211softmac_network *softmac_net;
538 spin_lock_irqsave(&mac->lock, flags);
539 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
540 spin_unlock_irqrestore(&mac->lock, flags);
544 /* Get a network from the list by ESSID while locked */
545 struct ieee80211softmac_network *
546 ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
547 struct ieee80211softmac_essid *essid)
549 struct list_head *list_ptr;
550 struct ieee80211softmac_network *softmac_net = NULL;
552 list_for_each(list_ptr, &mac->network_list) {
553 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
554 if (softmac_net->essid.len == essid->len &&
555 !memcmp(softmac_net->essid.data, essid->data, essid->len))
561 /* Get a network from the list by ESSID with locking */
562 struct ieee80211softmac_network *
563 ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
564 struct ieee80211softmac_essid *essid)
567 struct ieee80211softmac_network *softmac_net = NULL;
569 spin_lock_irqsave(&mac->lock, flags);
570 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
571 spin_unlock_irqrestore(&mac->lock, flags);
575 MODULE_LICENSE("GPL");
576 MODULE_AUTHOR("Johannes Berg");
577 MODULE_AUTHOR("Joseph Jezak");
578 MODULE_AUTHOR("Larry Finger");
579 MODULE_AUTHOR("Danny van Dyk");
580 MODULE_AUTHOR("Michael Buesch");
581 MODULE_DESCRIPTION("802.11 software MAC");