blob: 60f06a31f0d1ada1bdaa1d7ae735f8fa607070d3 [file] [log] [blame]
Johannes Berg4855d252006-01-12 21:12:59 +01001/*
2 * Contains some basic softmac functions along with module registration code etc.
3 *
Johannes Berg79859052006-01-31 19:31:41 +01004 * 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>
Johannes Berg4855d252006-01-12 21:12:59 +01009 *
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.
13 *
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
17 * more details.
18 *
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
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
25 */
26
Johannes Berg370121e2006-01-04 16:32:16 +010027#include "ieee80211softmac_priv.h"
28#include <linux/sort.h>
29
30struct net_device *alloc_ieee80211softmac(int sizeof_priv)
31{
32 struct ieee80211softmac_device *softmac;
33 struct net_device *dev;
34
35 dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
36 softmac = ieee80211_priv(dev);
37 softmac->dev = dev;
38 softmac->ieee = netdev_priv(dev);
39 spin_lock_init(&softmac->lock);
40
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;
Johannes Bergb6c76582006-01-31 19:49:42 +010044 softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
Johannes Berg370121e2006-01-04 16:32:16 +010045 softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
46 softmac->scaninfo = NULL;
47
48 /* TODO: initialise all the other callbacks in the ieee struct
49 * (once they're written)
50 */
51
Johannes Berg370121e2006-01-04 16:32:16 +010052 INIT_LIST_HEAD(&softmac->auth_queue);
53 INIT_LIST_HEAD(&softmac->network_list);
54 INIT_LIST_HEAD(&softmac->events);
55
56 INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
57 INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
58 softmac->start_scan = ieee80211softmac_start_scan_implementation;
59 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
60 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
61
62 //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
63 // It has to be set to the highest rate all stations in the current network can handle.
64 softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
65 softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
66 /* This is reassigned in ieee80211softmac_start to sane values. */
67 softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
68 softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
69
Johannes Berg2dd50802006-01-06 18:11:23 +010070 /* to start with, we can't send anything ... */
71 netif_carrier_off(dev);
Johannes Berg370121e2006-01-04 16:32:16 +010072
Johannes Berg370121e2006-01-04 16:32:16 +010073 return dev;
Johannes Berg370121e2006-01-04 16:32:16 +010074}
Johannes Berg4c718cf2006-01-12 21:19:48 +010075EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
Johannes Berg370121e2006-01-04 16:32:16 +010076
77/* Clears the pending work queue items, stops all scans, etc. */
78void
79ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
80{
81 unsigned long flags;
82 struct ieee80211softmac_event *eventptr, *eventtmp;
83 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
84 struct ieee80211softmac_network *netptr, *nettmp;
85
86 ieee80211softmac_stop_scan(sm);
87 ieee80211softmac_wait_for_scan(sm);
88
89 spin_lock_irqsave(&sm->lock, flags);
90 /* Free all pending assoc work items */
91 cancel_delayed_work(&sm->associnfo.work);
92
93 /* Free all pending scan work items */
94 if(sm->scaninfo != NULL)
95 cancel_delayed_work(&sm->scaninfo->softmac_scan);
96
97 /* Free all pending auth work items */
98 list_for_each_entry(authptr, &sm->auth_queue, list)
99 cancel_delayed_work(&authptr->work);
100
101 /* delete all pending event calls and work items */
102 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
103 cancel_delayed_work(&eventptr->work);
104
105 spin_unlock_irqrestore(&sm->lock, flags);
Johannes Berg5c4df6d2006-01-06 01:43:45 +0100106 flush_scheduled_work();
Johannes Berg370121e2006-01-04 16:32:16 +0100107
Johannes Bergb2b9b6512006-01-11 19:32:02 +0100108 /* now we should be save and no longer need locking... */
Johannes Berg370121e2006-01-04 16:32:16 +0100109 spin_lock_irqsave(&sm->lock, flags);
110 /* Free all pending auth work items */
111 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
112 list_del(&authptr->list);
113 kfree(authptr);
114 }
115
116 /* delete all pending event calls and work items */
117 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
118 list_del(&eventptr->list);
119 kfree(eventptr);
120 }
121
122 /* Free all networks */
123 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
124 ieee80211softmac_del_network_locked(sm, netptr);
125 if(netptr->challenge != NULL)
126 kfree(netptr->challenge);
127 kfree(netptr);
128 }
129
130 spin_unlock_irqrestore(&sm->lock, flags);
131}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100132EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
Johannes Berg370121e2006-01-04 16:32:16 +0100133
134void free_ieee80211softmac(struct net_device *dev)
135{
136 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
137 ieee80211softmac_clear_pending_work(sm);
Johannes Berg370121e2006-01-04 16:32:16 +0100138 kfree(sm->scaninfo);
139 kfree(sm->wpa.IE);
140 free_ieee80211(dev);
141}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100142EXPORT_SYMBOL_GPL(free_ieee80211softmac);
Johannes Berg370121e2006-01-04 16:32:16 +0100143
144static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
145{
146 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
147 /* I took out the sorting check, we're seperating by modulation now. */
148 if (ri->count)
149 return;
150 /* otherwise assume we hav'em all! */
151 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
152 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
153 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
154 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
155 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
156 }
157 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
158 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
159 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
160 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
161 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
162 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
163 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
164 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
165 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
166 }
167}
168
169void ieee80211softmac_start(struct net_device *dev)
170{
171 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
172 struct ieee80211_device *ieee = mac->ieee;
173 u32 change = 0;
174 struct ieee80211softmac_txrates oldrates;
175
176 ieee80211softmac_start_check_rates(mac);
177
178 /* TODO: We need some kind of state machine to lower the default rates
179 * if we loose too many packets.
180 */
181 /* Change the default txrate to the highest possible value.
182 * The txrate machine will lower it, if it is too high.
183 */
184 if (mac->txrates_change)
185 oldrates = mac->txrates;
David Woodhouse2638fed2006-03-23 22:43:38 +0000186 /* FIXME: We don't correctly handle backing down to lower
187 rates, so 801.11g devices start off at 11M for now. People
188 can manually change it if they really need to, but 11M is
189 more reliable. Note similar logic in
190 ieee80211softmac_wx_set_rate() */
191 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
Johannes Berg370121e2006-01-04 16:32:16 +0100192 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
193 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
194 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
195 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
David Woodhouse2638fed2006-03-23 22:43:38 +0000196 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
197 mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
198 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
199 mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
200 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
Johannes Berg370121e2006-01-04 16:32:16 +0100201 } else
202 assert(0);
203 if (mac->txrates_change)
204 mac->txrates_change(dev, change, &oldrates);
205}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100206EXPORT_SYMBOL_GPL(ieee80211softmac_start);
Johannes Berg370121e2006-01-04 16:32:16 +0100207
208void ieee80211softmac_stop(struct net_device *dev)
209{
210 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
211
212 ieee80211softmac_clear_pending_work(mac);
213}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100214EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
Johannes Berg370121e2006-01-04 16:32:16 +0100215
216void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
217{
218 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
219 unsigned long flags;
220
221 spin_lock_irqsave(&mac->lock, flags);
222 memcpy(mac->ratesinfo.rates, rates, count);
223 mac->ratesinfo.count = count;
224 spin_unlock_irqrestore(&mac->lock, flags);
225}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100226EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
Johannes Berg370121e2006-01-04 16:32:16 +0100227
228static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
229{
230 int i;
231 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
232
233 for (i=0; i<ri->count-1; i++) {
234 if (ri->rates[i] == rate)
235 return ri->rates[i+1];
236 }
237 /* I guess we can't go any higher... */
238 return ri->rates[ri->count];
239}
240
241u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
242{
243 int i;
244 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
245
246 for (i=delta; i<ri->count; i++) {
247 if (ri->rates[i] == rate)
248 return ri->rates[i-delta];
249 }
250 /* I guess we can't go any lower... */
251 return ri->rates[0];
252}
253
254static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
255 int amount)
256{
257 struct ieee80211softmac_txrates oldrates;
258 u8 default_rate = mac->txrates.default_rate;
259 u8 default_fallback = mac->txrates.default_fallback;
260 u32 changes = 0;
261
262 //TODO: This is highly experimental code.
263 // Maybe the dynamic rate selection does not work
264 // and it has to be removed again.
265
266printk("badness %d\n", mac->txrate_badness);
267 mac->txrate_badness += amount;
268 if (mac->txrate_badness <= -1000) {
269 /* Very small badness. Try a faster bitrate. */
270 if (mac->txrates_change)
271 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
272 default_rate = raise_rate(mac, default_rate);
273 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
274 default_fallback = get_fallback_rate(mac, default_rate);
275 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
276 mac->txrate_badness = 0;
277printk("Bitrate raised to %u\n", default_rate);
278 } else if (mac->txrate_badness >= 10000) {
279 /* Very high badness. Try a slower bitrate. */
280 if (mac->txrates_change)
281 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
282 default_rate = lower_rate(mac, default_rate);
283 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
284 default_fallback = get_fallback_rate(mac, default_rate);
285 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
286 mac->txrate_badness = 0;
287printk("Bitrate lowered to %u\n", default_rate);
288 }
289
290 mac->txrates.default_rate = default_rate;
291 mac->txrates.default_fallback = default_fallback;
292
293 if (changes && mac->txrates_change)
294 mac->txrates_change(mac->dev, changes, &oldrates);
295}
296
297void ieee80211softmac_fragment_lost(struct net_device *dev,
298 u16 wl_seq)
299{
300 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
301 unsigned long flags;
302
303 spin_lock_irqsave(&mac->lock, flags);
304 ieee80211softmac_add_txrates_badness(mac, 1000);
305 //TODO
306
307 spin_unlock_irqrestore(&mac->lock, flags);
308}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100309EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
Johannes Berg370121e2006-01-04 16:32:16 +0100310
311static int rate_cmp(const void *a_, const void *b_) {
312 u8 *a, *b;
313 a = (u8*)a_;
314 b = (u8*)b_;
315 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
316}
317
318/* Allocate a softmac network struct and fill it from a network */
319struct ieee80211softmac_network *
320ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
321 struct ieee80211_network *net)
322{
323 struct ieee80211softmac_network *softnet;
324 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
325 if(softnet == NULL)
326 return NULL;
327 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
328 softnet->channel = net->channel;
329 softnet->essid.len = net->ssid_len;
330 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
331
332 /* copy rates over */
333 softnet->supported_rates.count = net->rates_len;
334 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
335 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
336 softnet->supported_rates.count += net->rates_ex_len;
337 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
338
339 softnet->capabilities = net->capability;
340 return softnet;
341}
342
343
344/* Add a network to the list, while locked */
345void
346ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
347 struct ieee80211softmac_network *add_net)
348{
349 struct list_head *list_ptr;
350 struct ieee80211softmac_network *softmac_net = NULL;
351
352 list_for_each(list_ptr, &mac->network_list) {
353 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
354 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
355 break;
356 else
357 softmac_net = NULL;
358 }
359 if(softmac_net == NULL)
360 list_add(&(add_net->list), &mac->network_list);
361}
362
363/* Add a network to the list, with locking */
364void
365ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
366 struct ieee80211softmac_network *add_net)
367{
368 unsigned long flags;
369 spin_lock_irqsave(&mac->lock, flags);
370 ieee80211softmac_add_network_locked(mac, add_net);
371 spin_unlock_irqrestore(&mac->lock, flags);
372}
373
374
375/* Delete a network from the list, while locked*/
376void
377ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
378 struct ieee80211softmac_network *del_net)
379{
380 list_del(&(del_net->list));
381}
382
383/* Delete a network from the list with locking */
384void
385ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
386 struct ieee80211softmac_network *del_net)
387{
388 unsigned long flags;
389 spin_lock_irqsave(&mac->lock, flags);
390 ieee80211softmac_del_network_locked(mac, del_net);
391 spin_unlock_irqrestore(&mac->lock, flags);
392}
393
394/* Get a network from the list by MAC while locked */
395struct ieee80211softmac_network *
396ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
397 u8 *bssid)
398{
399 struct list_head *list_ptr;
400 struct ieee80211softmac_network *softmac_net = NULL;
401 list_for_each(list_ptr, &mac->network_list) {
402 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
403 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
404 break;
405 else
406 softmac_net = NULL;
407 }
408 return softmac_net;
409}
410
411/* Get a network from the list by BSSID with locking */
412struct ieee80211softmac_network *
413ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
414 u8 *bssid)
415{
416 unsigned long flags;
417 struct ieee80211softmac_network *softmac_net;
418
419 spin_lock_irqsave(&mac->lock, flags);
420 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
421 spin_unlock_irqrestore(&mac->lock, flags);
422 return softmac_net;
423}
424
425/* Get a network from the list by ESSID while locked */
426struct ieee80211softmac_network *
427ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
428 struct ieee80211softmac_essid *essid)
429{
430 struct list_head *list_ptr;
431 struct ieee80211softmac_network *softmac_net = NULL;
432
433 list_for_each(list_ptr, &mac->network_list) {
434 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
435 if (softmac_net->essid.len == essid->len &&
436 !memcmp(softmac_net->essid.data, essid->data, essid->len))
437 return softmac_net;
438 }
439 return NULL;
440}
441
442/* Get a network from the list by ESSID with locking */
443struct ieee80211softmac_network *
444ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
445 struct ieee80211softmac_essid *essid)
446{
447 unsigned long flags;
448 struct ieee80211softmac_network *softmac_net = NULL;
449
450 spin_lock_irqsave(&mac->lock, flags);
451 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
452 spin_unlock_irqrestore(&mac->lock, flags);
453 return softmac_net;
454}
455
456MODULE_LICENSE("GPL");
Johannes Berg9ebdd462006-01-12 21:18:25 +0100457MODULE_AUTHOR("Johannes Berg");
458MODULE_AUTHOR("Joseph Jezak");
459MODULE_AUTHOR("Larry Finger");
460MODULE_AUTHOR("Danny van Dyk");
461MODULE_AUTHOR("Michael Buesch");
462MODULE_DESCRIPTION("802.11 software MAC");