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 u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
183 struct ieee80211softmac_ratesinfo *ri, int basic_only)
185 u8 user_rate = mac->txrates.user_rate;
189 return IEEE80211_CCK_RATE_1MB;
191 for (i = ri->count - 1; i >= 0; i--) {
192 u8 rate = ri->rates[i];
193 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
195 rate &= ~IEEE80211_BASIC_RATE_MASK;
196 if (rate > user_rate)
198 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
202 /* If we haven't found a suitable rate by now, just trust the user */
205 EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
207 void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
214 /* Barker preamble mode */
215 short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
216 && mac->associnfo.short_preamble_available) ? 1 : 0;
218 /* Protection needed? */
219 use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
221 if (mac->bssinfo.short_preamble != short_preamble) {
222 changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
223 mac->bssinfo.short_preamble = short_preamble;
226 if (mac->bssinfo.use_protection != use_protection) {
227 changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
228 mac->bssinfo.use_protection = use_protection;
231 if (mac->bssinfo_change && changes)
232 mac->bssinfo_change(mac->dev, changes);
235 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
237 struct ieee80211softmac_txrates *txrates = &mac->txrates;
240 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
241 txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
243 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
244 txrates->default_fallback = lower_rate(mac, txrates->default_rate);
246 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
247 txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
249 if (mac->txrates_change)
250 mac->txrates_change(mac->dev, change);
254 void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
256 struct ieee80211_device *ieee = mac->ieee;
258 struct ieee80211softmac_txrates *txrates = &mac->txrates;
259 struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
261 /* TODO: We need some kind of state machine to lower the default rates
262 * if we loose too many packets.
264 /* Change the default txrate to the highest possible value.
265 * The txrate machine will lower it, if it is too high.
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;
279 txrates->default_rate = IEEE80211_CCK_RATE_1MB;
280 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
282 txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
283 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
285 txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
286 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
288 txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
289 change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
291 if (mac->txrates_change)
292 mac->txrates_change(mac->dev, change);
296 bssinfo->supported_rates.count = 0;
297 memset(bssinfo->supported_rates.rates, 0,
298 sizeof(bssinfo->supported_rates.rates));
299 change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
301 bssinfo->short_preamble = 0;
302 change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
304 bssinfo->use_protection = 0;
305 change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
307 if (mac->bssinfo_change)
308 mac->bssinfo_change(mac->dev, change);
313 void ieee80211softmac_start(struct net_device *dev)
315 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
317 ieee80211softmac_start_check_rates(mac);
318 ieee80211softmac_init_bss(mac);
320 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
322 void ieee80211softmac_stop(struct net_device *dev)
324 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
326 ieee80211softmac_clear_pending_work(mac);
328 EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
330 void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
332 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
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);
340 EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
342 static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
345 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
347 for (i=0; i<ri->count-1; i++) {
348 if (ri->rates[i] == rate)
349 return ri->rates[i+1];
351 /* I guess we can't go any higher... */
352 return ri->rates[ri->count];
355 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
358 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
360 for (i=delta; i<ri->count; i++) {
361 if (ri->rates[i] == rate)
362 return ri->rates[i-delta];
364 /* I guess we can't go any lower... */
368 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
371 u8 default_rate = mac->txrates.default_rate;
372 u8 default_fallback = mac->txrates.default_fallback;
375 //TODO: This is highly experimental code.
376 // Maybe the dynamic rate selection does not work
377 // and it has to be removed again.
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);
399 mac->txrates.default_rate = default_rate;
400 mac->txrates.default_fallback = default_fallback;
402 if (changes && mac->txrates_change)
403 mac->txrates_change(mac->dev, changes);
406 void ieee80211softmac_fragment_lost(struct net_device *dev,
409 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
412 spin_lock_irqsave(&mac->lock, flags);
413 ieee80211softmac_add_txrates_badness(mac, 1000);
416 spin_unlock_irqrestore(&mac->lock, flags);
418 EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
420 static int rate_cmp(const void *a_, const void *b_) {
424 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
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)
432 struct ieee80211softmac_network *softnet;
433 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
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);
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);
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;
452 softnet->capabilities = net->capability;
457 /* Add a network to the list, while locked */
459 ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
460 struct ieee80211softmac_network *add_net)
462 struct list_head *list_ptr;
463 struct ieee80211softmac_network *softmac_net = NULL;
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))
472 if(softmac_net == NULL)
473 list_add(&(add_net->list), &mac->network_list);
476 /* Add a network to the list, with locking */
478 ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
479 struct ieee80211softmac_network *add_net)
482 spin_lock_irqsave(&mac->lock, flags);
483 ieee80211softmac_add_network_locked(mac, add_net);
484 spin_unlock_irqrestore(&mac->lock, flags);
488 /* Delete a network from the list, while locked*/
490 ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
491 struct ieee80211softmac_network *del_net)
493 list_del(&(del_net->list));
496 /* Delete a network from the list with locking */
498 ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
499 struct ieee80211softmac_network *del_net)
502 spin_lock_irqsave(&mac->lock, flags);
503 ieee80211softmac_del_network_locked(mac, del_net);
504 spin_unlock_irqrestore(&mac->lock, flags);
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,
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))
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,
530 struct ieee80211softmac_network *softmac_net;
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);
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)
543 struct list_head *list_ptr;
544 struct ieee80211softmac_network *softmac_net = NULL;
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))
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)
561 struct ieee80211softmac_network *softmac_net = NULL;
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);
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");