1 #include "ieee80211softmac_priv.h"
2 #include <linux/sort.h>
4 struct net_device *alloc_ieee80211softmac(int sizeof_priv)
6 struct ieee80211softmac_device *softmac;
7 struct net_device *dev;
9 dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
10 softmac = ieee80211_priv(dev);
12 softmac->ieee = netdev_priv(dev);
13 spin_lock_init(&softmac->lock);
15 softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
16 softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
17 softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
18 softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
19 softmac->scaninfo = NULL;
21 /* TODO: initialise all the other callbacks in the ieee struct
22 * (once they're written)
25 INIT_LIST_HEAD(&softmac->auth_queue);
26 INIT_LIST_HEAD(&softmac->network_list);
27 INIT_LIST_HEAD(&softmac->events);
29 INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
30 INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
31 softmac->start_scan = ieee80211softmac_start_scan_implementation;
32 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
33 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
35 //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
36 // It has to be set to the highest rate all stations in the current network can handle.
37 softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
38 softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
39 /* This is reassigned in ieee80211softmac_start to sane values. */
40 softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
41 softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
43 /* should we also assign softmac->mgmt_xmit here so
44 * that it is always valid? If so, we probably want
45 * to define a new function for that which just
46 * wraps ieee80211_tx_frame
49 /* until associated, we're not ready */
50 dev->flags &= ~IFF_RUNNING;
60 /* Clears the pending work queue items, stops all scans, etc. */
62 ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
65 struct ieee80211softmac_event *eventptr, *eventtmp;
66 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
67 struct ieee80211softmac_network *netptr, *nettmp;
69 ieee80211softmac_stop_scan(sm);
70 ieee80211softmac_wait_for_scan(sm);
72 spin_lock_irqsave(&sm->lock, flags);
73 /* Free all pending assoc work items */
74 cancel_delayed_work(&sm->associnfo.work);
76 /* Free all pending scan work items */
77 if(sm->scaninfo != NULL)
78 cancel_delayed_work(&sm->scaninfo->softmac_scan);
80 /* Free all pending auth work items */
81 list_for_each_entry(authptr, &sm->auth_queue, list)
82 cancel_delayed_work(&authptr->work);
84 /* delete all pending event calls and work items */
85 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
86 cancel_delayed_work(&eventptr->work);
88 spin_unlock_irqrestore(&sm->lock, flags);
89 flush_scheduled_work();
91 // now we should be save and no longer need locking...
92 spin_lock_irqsave(&sm->lock, flags);
93 /* Free all pending auth work items */
94 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
95 list_del(&authptr->list);
99 /* delete all pending event calls and work items */
100 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
101 list_del(&eventptr->list);
105 /* Free all networks */
106 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
107 ieee80211softmac_del_network_locked(sm, netptr);
108 if(netptr->challenge != NULL)
109 kfree(netptr->challenge);
113 spin_unlock_irqrestore(&sm->lock, flags);
116 void free_ieee80211softmac(struct net_device *dev)
118 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
119 ieee80211softmac_clear_pending_work(sm);
125 static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
127 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
128 /* I took out the sorting check, we're seperating by modulation now. */
131 /* otherwise assume we hav'em all! */
132 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
133 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
134 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
135 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
136 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
138 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
139 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
140 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
141 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
142 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
143 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
144 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
145 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
146 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
150 void ieee80211softmac_start(struct net_device *dev)
152 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
153 struct ieee80211_device *ieee = mac->ieee;
155 struct ieee80211softmac_txrates oldrates;
157 ieee80211softmac_start_check_rates(mac);
159 /* TODO: We need some kind of state machine to lower the default rates
160 * if we loose too many packets.
162 /* Change the default txrate to the highest possible value.
163 * The txrate machine will lower it, if it is too high.
165 if (mac->txrates_change)
166 oldrates = mac->txrates;
167 if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
168 mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
169 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
170 mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
171 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
172 } else if (ieee->modulation & IEEE80211_CCK_MODULATION) {
173 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
174 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
175 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
176 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
179 if (mac->txrates_change)
180 mac->txrates_change(dev, change, &oldrates);
183 void ieee80211softmac_stop(struct net_device *dev)
185 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
187 ieee80211softmac_clear_pending_work(mac);
190 void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
192 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
195 spin_lock_irqsave(&mac->lock, flags);
196 memcpy(mac->ratesinfo.rates, rates, count);
197 mac->ratesinfo.count = count;
198 spin_unlock_irqrestore(&mac->lock, flags);
201 static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
204 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
206 for (i=0; i<ri->count-1; i++) {
207 if (ri->rates[i] == rate)
208 return ri->rates[i+1];
210 /* I guess we can't go any higher... */
211 return ri->rates[ri->count];
214 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
217 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
219 for (i=delta; i<ri->count; i++) {
220 if (ri->rates[i] == rate)
221 return ri->rates[i-delta];
223 /* I guess we can't go any lower... */
227 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
230 struct ieee80211softmac_txrates oldrates;
231 u8 default_rate = mac->txrates.default_rate;
232 u8 default_fallback = mac->txrates.default_fallback;
235 //TODO: This is highly experimental code.
236 // Maybe the dynamic rate selection does not work
237 // and it has to be removed again.
239 printk("badness %d\n", mac->txrate_badness);
240 mac->txrate_badness += amount;
241 if (mac->txrate_badness <= -1000) {
242 /* Very small badness. Try a faster bitrate. */
243 if (mac->txrates_change)
244 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
245 default_rate = raise_rate(mac, default_rate);
246 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
247 default_fallback = get_fallback_rate(mac, default_rate);
248 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
249 mac->txrate_badness = 0;
250 printk("Bitrate raised to %u\n", default_rate);
251 } else if (mac->txrate_badness >= 10000) {
252 /* Very high badness. Try a slower bitrate. */
253 if (mac->txrates_change)
254 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
255 default_rate = lower_rate(mac, default_rate);
256 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
257 default_fallback = get_fallback_rate(mac, default_rate);
258 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
259 mac->txrate_badness = 0;
260 printk("Bitrate lowered to %u\n", default_rate);
263 mac->txrates.default_rate = default_rate;
264 mac->txrates.default_fallback = default_fallback;
266 if (changes && mac->txrates_change)
267 mac->txrates_change(mac->dev, changes, &oldrates);
270 void ieee80211softmac_fragment_lost(struct net_device *dev,
273 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
276 spin_lock_irqsave(&mac->lock, flags);
277 ieee80211softmac_add_txrates_badness(mac, 1000);
280 spin_unlock_irqrestore(&mac->lock, flags);
283 static int rate_cmp(const void *a_, const void *b_) {
287 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
290 /* Allocate a softmac network struct and fill it from a network */
291 struct ieee80211softmac_network *
292 ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
293 struct ieee80211_network *net)
295 struct ieee80211softmac_network *softnet;
296 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
299 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
300 softnet->channel = net->channel;
301 softnet->essid.len = net->ssid_len;
302 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
304 /* copy rates over */
305 softnet->supported_rates.count = net->rates_len;
306 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
307 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
308 softnet->supported_rates.count += net->rates_ex_len;
309 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
311 softnet->capabilities = net->capability;
316 /* Add a network to the list, while locked */
318 ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
319 struct ieee80211softmac_network *add_net)
321 struct list_head *list_ptr;
322 struct ieee80211softmac_network *softmac_net = NULL;
324 list_for_each(list_ptr, &mac->network_list) {
325 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
326 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
331 if(softmac_net == NULL)
332 list_add(&(add_net->list), &mac->network_list);
335 /* Add a network to the list, with locking */
337 ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
338 struct ieee80211softmac_network *add_net)
341 spin_lock_irqsave(&mac->lock, flags);
342 ieee80211softmac_add_network_locked(mac, add_net);
343 spin_unlock_irqrestore(&mac->lock, flags);
347 /* Delete a network from the list, while locked*/
349 ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
350 struct ieee80211softmac_network *del_net)
352 list_del(&(del_net->list));
355 /* Delete a network from the list with locking */
357 ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
358 struct ieee80211softmac_network *del_net)
361 spin_lock_irqsave(&mac->lock, flags);
362 ieee80211softmac_del_network_locked(mac, del_net);
363 spin_unlock_irqrestore(&mac->lock, flags);
366 /* Get a network from the list by MAC while locked */
367 struct ieee80211softmac_network *
368 ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
371 struct list_head *list_ptr;
372 struct ieee80211softmac_network *softmac_net = NULL;
373 list_for_each(list_ptr, &mac->network_list) {
374 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
375 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
383 /* Get a network from the list by BSSID with locking */
384 struct ieee80211softmac_network *
385 ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
389 struct ieee80211softmac_network *softmac_net;
391 spin_lock_irqsave(&mac->lock, flags);
392 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
393 spin_unlock_irqrestore(&mac->lock, flags);
397 /* Get a network from the list by ESSID while locked */
398 struct ieee80211softmac_network *
399 ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
400 struct ieee80211softmac_essid *essid)
402 struct list_head *list_ptr;
403 struct ieee80211softmac_network *softmac_net = NULL;
405 list_for_each(list_ptr, &mac->network_list) {
406 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
407 if (softmac_net->essid.len == essid->len &&
408 !memcmp(softmac_net->essid.data, essid->data, essid->len))
414 /* Get a network from the list by ESSID with locking */
415 struct ieee80211softmac_network *
416 ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
417 struct ieee80211softmac_essid *essid)
420 struct ieee80211softmac_network *softmac_net = NULL;
422 spin_lock_irqsave(&mac->lock, flags);
423 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
424 spin_unlock_irqrestore(&mac->lock, flags);
428 MODULE_LICENSE("GPL");
430 EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
431 EXPORT_SYMBOL_GPL(free_ieee80211softmac);
432 EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
433 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
434 EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
435 EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
436 EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);