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);
92 /* Free all pending assoc work items */
93 cancel_delayed_work(&sm->associnfo.work);
95 /* Free all pending scan work items */
96 if(sm->scaninfo != NULL)
97 cancel_delayed_work(&sm->scaninfo->softmac_scan);
99 /* Free all pending auth work items */
100 list_for_each_entry(authptr, &sm->auth_queue, list)
101 cancel_delayed_work(&authptr->work);
103 /* delete all pending event calls and work items */
104 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
105 cancel_delayed_work(&eventptr->work);
107 spin_unlock_irqrestore(&sm->lock, flags);
108 flush_scheduled_work();
110 /* now we should be save and no longer need locking... */
111 spin_lock_irqsave(&sm->lock, flags);
112 /* Free all pending auth work items */
113 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
114 list_del(&authptr->list);
118 /* delete all pending event calls and work items */
119 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
120 list_del(&eventptr->list);
124 /* Free all networks */
125 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
126 ieee80211softmac_del_network_locked(sm, netptr);
127 if(netptr->challenge != NULL)
128 kfree(netptr->challenge);
132 spin_unlock_irqrestore(&sm->lock, flags);
134 EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
136 void free_ieee80211softmac(struct net_device *dev)
138 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
139 ieee80211softmac_clear_pending_work(sm);
144 EXPORT_SYMBOL_GPL(free_ieee80211softmac);
146 static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
148 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
149 /* I took out the sorting check, we're seperating by modulation now. */
152 /* otherwise assume we hav'em all! */
153 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
154 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
155 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
156 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
157 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
159 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
160 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
161 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
162 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
163 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
164 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
165 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
166 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
167 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
171 void ieee80211softmac_start(struct net_device *dev)
173 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
174 struct ieee80211_device *ieee = mac->ieee;
176 struct ieee80211softmac_txrates oldrates;
178 ieee80211softmac_start_check_rates(mac);
180 /* TODO: We need some kind of state machine to lower the default rates
181 * if we loose too many packets.
183 /* Change the default txrate to the highest possible value.
184 * The txrate machine will lower it, if it is too high.
186 if (mac->txrates_change)
187 oldrates = mac->txrates;
188 /* FIXME: We don't correctly handle backing down to lower
189 rates, so 801.11g devices start off at 11M for now. People
190 can manually change it if they really need to, but 11M is
191 more reliable. Note similar logic in
192 ieee80211softmac_wx_set_rate() */
193 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
194 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
195 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
196 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
197 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
198 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
199 mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
200 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
201 mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
202 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
205 if (mac->txrates_change)
206 mac->txrates_change(dev, change, &oldrates);
208 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
210 void ieee80211softmac_stop(struct net_device *dev)
212 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
214 ieee80211softmac_clear_pending_work(mac);
216 EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
218 void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
220 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
223 spin_lock_irqsave(&mac->lock, flags);
224 memcpy(mac->ratesinfo.rates, rates, count);
225 mac->ratesinfo.count = count;
226 spin_unlock_irqrestore(&mac->lock, flags);
228 EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
230 static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
233 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
235 for (i=0; i<ri->count-1; i++) {
236 if (ri->rates[i] == rate)
237 return ri->rates[i+1];
239 /* I guess we can't go any higher... */
240 return ri->rates[ri->count];
243 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
246 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
248 for (i=delta; i<ri->count; i++) {
249 if (ri->rates[i] == rate)
250 return ri->rates[i-delta];
252 /* I guess we can't go any lower... */
256 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
259 struct ieee80211softmac_txrates oldrates;
260 u8 default_rate = mac->txrates.default_rate;
261 u8 default_fallback = mac->txrates.default_fallback;
264 //TODO: This is highly experimental code.
265 // Maybe the dynamic rate selection does not work
266 // and it has to be removed again.
268 printk("badness %d\n", mac->txrate_badness);
269 mac->txrate_badness += amount;
270 if (mac->txrate_badness <= -1000) {
271 /* Very small badness. Try a faster bitrate. */
272 if (mac->txrates_change)
273 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
274 default_rate = raise_rate(mac, default_rate);
275 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
276 default_fallback = get_fallback_rate(mac, default_rate);
277 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
278 mac->txrate_badness = 0;
279 printk("Bitrate raised to %u\n", default_rate);
280 } else if (mac->txrate_badness >= 10000) {
281 /* Very high badness. Try a slower bitrate. */
282 if (mac->txrates_change)
283 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
284 default_rate = lower_rate(mac, default_rate);
285 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
286 default_fallback = get_fallback_rate(mac, default_rate);
287 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
288 mac->txrate_badness = 0;
289 printk("Bitrate lowered to %u\n", default_rate);
292 mac->txrates.default_rate = default_rate;
293 mac->txrates.default_fallback = default_fallback;
295 if (changes && mac->txrates_change)
296 mac->txrates_change(mac->dev, changes, &oldrates);
299 void ieee80211softmac_fragment_lost(struct net_device *dev,
302 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
305 spin_lock_irqsave(&mac->lock, flags);
306 ieee80211softmac_add_txrates_badness(mac, 1000);
309 spin_unlock_irqrestore(&mac->lock, flags);
311 EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
313 static int rate_cmp(const void *a_, const void *b_) {
317 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
320 /* Allocate a softmac network struct and fill it from a network */
321 struct ieee80211softmac_network *
322 ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
323 struct ieee80211_network *net)
325 struct ieee80211softmac_network *softnet;
326 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
329 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
330 softnet->channel = net->channel;
331 softnet->essid.len = net->ssid_len;
332 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
334 /* copy rates over */
335 softnet->supported_rates.count = net->rates_len;
336 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
337 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
338 softnet->supported_rates.count += net->rates_ex_len;
339 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
341 softnet->capabilities = net->capability;
346 /* Add a network to the list, while locked */
348 ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
349 struct ieee80211softmac_network *add_net)
351 struct list_head *list_ptr;
352 struct ieee80211softmac_network *softmac_net = NULL;
354 list_for_each(list_ptr, &mac->network_list) {
355 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
356 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
361 if(softmac_net == NULL)
362 list_add(&(add_net->list), &mac->network_list);
365 /* Add a network to the list, with locking */
367 ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
368 struct ieee80211softmac_network *add_net)
371 spin_lock_irqsave(&mac->lock, flags);
372 ieee80211softmac_add_network_locked(mac, add_net);
373 spin_unlock_irqrestore(&mac->lock, flags);
377 /* Delete a network from the list, while locked*/
379 ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
380 struct ieee80211softmac_network *del_net)
382 list_del(&(del_net->list));
385 /* Delete a network from the list with locking */
387 ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
388 struct ieee80211softmac_network *del_net)
391 spin_lock_irqsave(&mac->lock, flags);
392 ieee80211softmac_del_network_locked(mac, del_net);
393 spin_unlock_irqrestore(&mac->lock, flags);
396 /* Get a network from the list by MAC while locked */
397 struct ieee80211softmac_network *
398 ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
401 struct list_head *list_ptr;
402 struct ieee80211softmac_network *softmac_net = NULL;
403 list_for_each(list_ptr, &mac->network_list) {
404 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
405 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
413 /* Get a network from the list by BSSID with locking */
414 struct ieee80211softmac_network *
415 ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
419 struct ieee80211softmac_network *softmac_net;
421 spin_lock_irqsave(&mac->lock, flags);
422 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
423 spin_unlock_irqrestore(&mac->lock, flags);
427 /* Get a network from the list by ESSID while locked */
428 struct ieee80211softmac_network *
429 ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
430 struct ieee80211softmac_essid *essid)
432 struct list_head *list_ptr;
433 struct ieee80211softmac_network *softmac_net = NULL;
435 list_for_each(list_ptr, &mac->network_list) {
436 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
437 if (softmac_net->essid.len == essid->len &&
438 !memcmp(softmac_net->essid.data, essid->data, essid->len))
444 /* Get a network from the list by ESSID with locking */
445 struct ieee80211softmac_network *
446 ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
447 struct ieee80211softmac_essid *essid)
450 struct ieee80211softmac_network *softmac_net = NULL;
452 spin_lock_irqsave(&mac->lock, flags);
453 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
454 spin_unlock_irqrestore(&mac->lock, flags);
458 MODULE_LICENSE("GPL");
459 MODULE_AUTHOR("Johannes Berg");
460 MODULE_AUTHOR("Joseph Jezak");
461 MODULE_AUTHOR("Larry Finger");
462 MODULE_AUTHOR("Danny van Dyk");
463 MODULE_AUTHOR("Michael Buesch");
464 MODULE_DESCRIPTION("802.11 software MAC");