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>
30 struct net_device *alloc_ieee80211softmac(int sizeof_priv)
32 struct ieee80211softmac_device *softmac;
33 struct net_device *dev;
35 dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
36 softmac = ieee80211_priv(dev);
38 softmac->ieee = netdev_priv(dev);
39 spin_lock_init(&softmac->lock);
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;
48 softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
50 /* TODO: initialise all the other callbacks in the ieee struct
51 * (once they're written)
54 INIT_LIST_HEAD(&softmac->auth_queue);
55 INIT_LIST_HEAD(&softmac->network_list);
56 INIT_LIST_HEAD(&softmac->events);
58 INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
59 INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
60 softmac->start_scan = ieee80211softmac_start_scan_implementation;
61 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
62 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
64 //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
65 // It has to be set to the highest rate all stations in the current network can handle.
66 softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
67 softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
68 /* This is reassigned in ieee80211softmac_start to sane values. */
69 softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
70 softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
72 /* to start with, we can't send anything ... */
73 netif_carrier_off(dev);
77 EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
79 /* Clears the pending work queue items, stops all scans, etc. */
81 ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
84 struct ieee80211softmac_event *eventptr, *eventtmp;
85 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
86 struct ieee80211softmac_network *netptr, *nettmp;
88 ieee80211softmac_stop_scan(sm);
89 ieee80211softmac_wait_for_scan(sm);
91 spin_lock_irqsave(&sm->lock, flags);
94 /* Free all pending assoc work items */
95 cancel_delayed_work(&sm->associnfo.work);
97 /* Free all pending scan work items */
98 if(sm->scaninfo != NULL)
99 cancel_delayed_work(&sm->scaninfo->softmac_scan);
101 /* Free all pending auth work items */
102 list_for_each_entry(authptr, &sm->auth_queue, list)
103 cancel_delayed_work(&authptr->work);
105 /* delete all pending event calls and work items */
106 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
107 cancel_delayed_work(&eventptr->work);
109 spin_unlock_irqrestore(&sm->lock, flags);
110 flush_scheduled_work();
112 /* now we should be save and no longer need locking... */
113 spin_lock_irqsave(&sm->lock, flags);
114 /* Free all pending auth work items */
115 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
116 list_del(&authptr->list);
120 /* delete all pending event calls and work items */
121 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
122 list_del(&eventptr->list);
126 /* Free all networks */
127 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
128 ieee80211softmac_del_network_locked(sm, netptr);
129 if(netptr->challenge != NULL)
130 kfree(netptr->challenge);
134 spin_unlock_irqrestore(&sm->lock, flags);
136 EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
138 void free_ieee80211softmac(struct net_device *dev)
140 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
141 ieee80211softmac_clear_pending_work(sm);
146 EXPORT_SYMBOL_GPL(free_ieee80211softmac);
148 static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
150 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
151 /* I took out the sorting check, we're seperating by modulation now. */
154 /* otherwise assume we hav'em all! */
155 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
156 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
157 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
158 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
159 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
161 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
162 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
163 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
164 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
165 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
166 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
167 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
168 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
169 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
173 void ieee80211softmac_start(struct net_device *dev)
175 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
176 struct ieee80211_device *ieee = mac->ieee;
178 struct ieee80211softmac_txrates oldrates;
180 ieee80211softmac_start_check_rates(mac);
182 /* TODO: We need some kind of state machine to lower the default rates
183 * if we loose too many packets.
185 /* Change the default txrate to the highest possible value.
186 * The txrate machine will lower it, if it is too high.
188 if (mac->txrates_change)
189 oldrates = mac->txrates;
190 /* FIXME: We don't correctly handle backing down to lower
191 rates, so 801.11g devices start off at 11M for now. People
192 can manually change it if they really need to, but 11M is
193 more reliable. Note similar logic in
194 ieee80211softmac_wx_set_rate() */
195 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
196 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
197 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
198 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
199 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
200 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
201 mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
202 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
203 mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
204 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
207 if (mac->txrates_change)
208 mac->txrates_change(dev, change, &oldrates);
212 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
214 void ieee80211softmac_stop(struct net_device *dev)
216 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
218 ieee80211softmac_clear_pending_work(mac);
220 EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
222 void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
224 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
227 spin_lock_irqsave(&mac->lock, flags);
228 memcpy(mac->ratesinfo.rates, rates, count);
229 mac->ratesinfo.count = count;
230 spin_unlock_irqrestore(&mac->lock, flags);
232 EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
234 static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
237 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
239 for (i=0; i<ri->count-1; i++) {
240 if (ri->rates[i] == rate)
241 return ri->rates[i+1];
243 /* I guess we can't go any higher... */
244 return ri->rates[ri->count];
247 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
250 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
252 for (i=delta; i<ri->count; i++) {
253 if (ri->rates[i] == rate)
254 return ri->rates[i-delta];
256 /* I guess we can't go any lower... */
260 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
263 struct ieee80211softmac_txrates oldrates;
264 u8 default_rate = mac->txrates.default_rate;
265 u8 default_fallback = mac->txrates.default_fallback;
268 //TODO: This is highly experimental code.
269 // Maybe the dynamic rate selection does not work
270 // and it has to be removed again.
272 printk("badness %d\n", mac->txrate_badness);
273 mac->txrate_badness += amount;
274 if (mac->txrate_badness <= -1000) {
275 /* Very small badness. Try a faster bitrate. */
276 if (mac->txrates_change)
277 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
278 default_rate = raise_rate(mac, default_rate);
279 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
280 default_fallback = get_fallback_rate(mac, default_rate);
281 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
282 mac->txrate_badness = 0;
283 printk("Bitrate raised to %u\n", default_rate);
284 } else if (mac->txrate_badness >= 10000) {
285 /* Very high badness. Try a slower bitrate. */
286 if (mac->txrates_change)
287 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
288 default_rate = lower_rate(mac, default_rate);
289 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
290 default_fallback = get_fallback_rate(mac, default_rate);
291 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
292 mac->txrate_badness = 0;
293 printk("Bitrate lowered to %u\n", default_rate);
296 mac->txrates.default_rate = default_rate;
297 mac->txrates.default_fallback = default_fallback;
299 if (changes && mac->txrates_change)
300 mac->txrates_change(mac->dev, changes, &oldrates);
303 void ieee80211softmac_fragment_lost(struct net_device *dev,
306 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
309 spin_lock_irqsave(&mac->lock, flags);
310 ieee80211softmac_add_txrates_badness(mac, 1000);
313 spin_unlock_irqrestore(&mac->lock, flags);
315 EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
317 static int rate_cmp(const void *a_, const void *b_) {
321 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
324 /* Allocate a softmac network struct and fill it from a network */
325 struct ieee80211softmac_network *
326 ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
327 struct ieee80211_network *net)
329 struct ieee80211softmac_network *softnet;
330 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
333 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
334 softnet->channel = net->channel;
335 softnet->essid.len = net->ssid_len;
336 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
338 /* copy rates over */
339 softnet->supported_rates.count = net->rates_len;
340 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
341 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
342 softnet->supported_rates.count += net->rates_ex_len;
343 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
345 softnet->capabilities = net->capability;
350 /* Add a network to the list, while locked */
352 ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
353 struct ieee80211softmac_network *add_net)
355 struct list_head *list_ptr;
356 struct ieee80211softmac_network *softmac_net = NULL;
358 list_for_each(list_ptr, &mac->network_list) {
359 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
360 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
365 if(softmac_net == NULL)
366 list_add(&(add_net->list), &mac->network_list);
369 /* Add a network to the list, with locking */
371 ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
372 struct ieee80211softmac_network *add_net)
375 spin_lock_irqsave(&mac->lock, flags);
376 ieee80211softmac_add_network_locked(mac, add_net);
377 spin_unlock_irqrestore(&mac->lock, flags);
381 /* Delete a network from the list, while locked*/
383 ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
384 struct ieee80211softmac_network *del_net)
386 list_del(&(del_net->list));
389 /* Delete a network from the list with locking */
391 ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
392 struct ieee80211softmac_network *del_net)
395 spin_lock_irqsave(&mac->lock, flags);
396 ieee80211softmac_del_network_locked(mac, del_net);
397 spin_unlock_irqrestore(&mac->lock, flags);
400 /* Get a network from the list by MAC while locked */
401 struct ieee80211softmac_network *
402 ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
405 struct list_head *list_ptr;
406 struct ieee80211softmac_network *softmac_net = NULL;
407 list_for_each(list_ptr, &mac->network_list) {
408 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
409 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
417 /* Get a network from the list by BSSID with locking */
418 struct ieee80211softmac_network *
419 ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
423 struct ieee80211softmac_network *softmac_net;
425 spin_lock_irqsave(&mac->lock, flags);
426 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
427 spin_unlock_irqrestore(&mac->lock, flags);
431 /* Get a network from the list by ESSID while locked */
432 struct ieee80211softmac_network *
433 ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
434 struct ieee80211softmac_essid *essid)
436 struct list_head *list_ptr;
437 struct ieee80211softmac_network *softmac_net = NULL;
439 list_for_each(list_ptr, &mac->network_list) {
440 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
441 if (softmac_net->essid.len == essid->len &&
442 !memcmp(softmac_net->essid.data, essid->data, essid->len))
448 /* Get a network from the list by ESSID with locking */
449 struct ieee80211softmac_network *
450 ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
451 struct ieee80211softmac_essid *essid)
454 struct ieee80211softmac_network *softmac_net = NULL;
456 spin_lock_irqsave(&mac->lock, flags);
457 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
458 spin_unlock_irqrestore(&mac->lock, flags);
462 MODULE_LICENSE("GPL");
463 MODULE_AUTHOR("Johannes Berg");
464 MODULE_AUTHOR("Joseph Jezak");
465 MODULE_AUTHOR("Larry Finger");
466 MODULE_AUTHOR("Danny van Dyk");
467 MODULE_AUTHOR("Michael Buesch");
468 MODULE_DESCRIPTION("802.11 software MAC");