[PATCH] orinoco: don't put PCI resource data to the network device
[deliverable/linux.git] / net / ieee80211 / softmac / ieee80211softmac_module.c
CommitLineData
4855d25b
JB
1/*
2 * Contains some basic softmac functions along with module registration code etc.
3 *
79859051
JB
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>
4855d25b
JB
9 *
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
370121e5
JB
27#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;
b6c7658e 44 softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
370121e5
JB
45 softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
46 softmac->scaninfo = NULL;
47
818667f7
JB
48 softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
49
370121e5
JB
50 /* TODO: initialise all the other callbacks in the ieee struct
51 * (once they're written)
52 */
53
370121e5
JB
54 INIT_LIST_HEAD(&softmac->auth_queue);
55 INIT_LIST_HEAD(&softmac->network_list);
56 INIT_LIST_HEAD(&softmac->events);
57
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;
63
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;
71
2dd50801
JB
72 /* to start with, we can't send anything ... */
73 netif_carrier_off(dev);
370121e5 74
370121e5 75 return dev;
370121e5 76}
4c718cfd 77EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
370121e5
JB
78
79/* Clears the pending work queue items, stops all scans, etc. */
80void
81ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
82{
83 unsigned long flags;
84 struct ieee80211softmac_event *eventptr, *eventtmp;
85 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
86 struct ieee80211softmac_network *netptr, *nettmp;
87
88 ieee80211softmac_stop_scan(sm);
89 ieee80211softmac_wait_for_scan(sm);
90
91 spin_lock_irqsave(&sm->lock, flags);
d57336e3
DD
92 sm->running = 0;
93
370121e5
JB
94 /* Free all pending assoc work items */
95 cancel_delayed_work(&sm->associnfo.work);
96
97 /* Free all pending scan work items */
98 if(sm->scaninfo != NULL)
99 cancel_delayed_work(&sm->scaninfo->softmac_scan);
100
101 /* Free all pending auth work items */
102 list_for_each_entry(authptr, &sm->auth_queue, list)
103 cancel_delayed_work(&authptr->work);
104
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);
108
109 spin_unlock_irqrestore(&sm->lock, flags);
5c4df6da 110 flush_scheduled_work();
370121e5 111
b2b9b651 112 /* now we should be save and no longer need locking... */
370121e5
JB
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);
117 kfree(authptr);
118 }
119
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);
123 kfree(eventptr);
124 }
125
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);
131 kfree(netptr);
132 }
133
134 spin_unlock_irqrestore(&sm->lock, flags);
135}
4c718cfd 136EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
370121e5
JB
137
138void free_ieee80211softmac(struct net_device *dev)
139{
140 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
141 ieee80211softmac_clear_pending_work(sm);
370121e5
JB
142 kfree(sm->scaninfo);
143 kfree(sm->wpa.IE);
144 free_ieee80211(dev);
145}
4c718cfd 146EXPORT_SYMBOL_GPL(free_ieee80211softmac);
370121e5
JB
147
148static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
149{
150 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
151 /* I took out the sorting check, we're seperating by modulation now. */
152 if (ri->count)
153 return;
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;
160 }
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;
170 }
171}
172
173void ieee80211softmac_start(struct net_device *dev)
174{
175 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
176 struct ieee80211_device *ieee = mac->ieee;
177 u32 change = 0;
178 struct ieee80211softmac_txrates oldrates;
179
180 ieee80211softmac_start_check_rates(mac);
181
182 /* TODO: We need some kind of state machine to lower the default rates
183 * if we loose too many packets.
184 */
185 /* Change the default txrate to the highest possible value.
186 * The txrate machine will lower it, if it is too high.
187 */
188 if (mac->txrates_change)
189 oldrates = mac->txrates;
2638fed7
DW
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) {
370121e5
JB
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;
2638fed7
DW
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;
370121e5
JB
205 } else
206 assert(0);
207 if (mac->txrates_change)
208 mac->txrates_change(dev, change, &oldrates);
d57336e3
DD
209
210 mac->running = 1;
370121e5 211}
4c718cfd 212EXPORT_SYMBOL_GPL(ieee80211softmac_start);
370121e5
JB
213
214void ieee80211softmac_stop(struct net_device *dev)
215{
216 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
217
218 ieee80211softmac_clear_pending_work(mac);
219}
4c718cfd 220EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
370121e5
JB
221
222void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
223{
224 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
225 unsigned long flags;
226
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);
231}
4c718cfd 232EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
370121e5
JB
233
234static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
235{
236 int i;
237 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
238
239 for (i=0; i<ri->count-1; i++) {
240 if (ri->rates[i] == rate)
241 return ri->rates[i+1];
242 }
243 /* I guess we can't go any higher... */
244 return ri->rates[ri->count];
245}
246
247u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
248{
249 int i;
250 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
251
252 for (i=delta; i<ri->count; i++) {
253 if (ri->rates[i] == rate)
254 return ri->rates[i-delta];
255 }
256 /* I guess we can't go any lower... */
257 return ri->rates[0];
258}
259
260static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
261 int amount)
262{
263 struct ieee80211softmac_txrates oldrates;
264 u8 default_rate = mac->txrates.default_rate;
265 u8 default_fallback = mac->txrates.default_fallback;
266 u32 changes = 0;
267
268 //TODO: This is highly experimental code.
269 // Maybe the dynamic rate selection does not work
270 // and it has to be removed again.
271
272printk("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;
283printk("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;
293printk("Bitrate lowered to %u\n", default_rate);
294 }
295
296 mac->txrates.default_rate = default_rate;
297 mac->txrates.default_fallback = default_fallback;
298
299 if (changes && mac->txrates_change)
300 mac->txrates_change(mac->dev, changes, &oldrates);
301}
302
303void ieee80211softmac_fragment_lost(struct net_device *dev,
304 u16 wl_seq)
305{
306 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
307 unsigned long flags;
308
309 spin_lock_irqsave(&mac->lock, flags);
310 ieee80211softmac_add_txrates_badness(mac, 1000);
311 //TODO
312
313 spin_unlock_irqrestore(&mac->lock, flags);
314}
4c718cfd 315EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
370121e5
JB
316
317static int rate_cmp(const void *a_, const void *b_) {
318 u8 *a, *b;
319 a = (u8*)a_;
320 b = (u8*)b_;
321 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
322}
323
324/* Allocate a softmac network struct and fill it from a network */
325struct ieee80211softmac_network *
326ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
327 struct ieee80211_network *net)
328{
329 struct ieee80211softmac_network *softnet;
330 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
331 if(softnet == NULL)
332 return NULL;
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);
337
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);
344
345 softnet->capabilities = net->capability;
346 return softnet;
347}
348
349
350/* Add a network to the list, while locked */
351void
352ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
353 struct ieee80211softmac_network *add_net)
354{
355 struct list_head *list_ptr;
356 struct ieee80211softmac_network *softmac_net = NULL;
357
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))
361 break;
362 else
363 softmac_net = NULL;
364 }
365 if(softmac_net == NULL)
366 list_add(&(add_net->list), &mac->network_list);
367}
368
369/* Add a network to the list, with locking */
370void
371ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
372 struct ieee80211softmac_network *add_net)
373{
374 unsigned long flags;
375 spin_lock_irqsave(&mac->lock, flags);
376 ieee80211softmac_add_network_locked(mac, add_net);
377 spin_unlock_irqrestore(&mac->lock, flags);
378}
379
380
381/* Delete a network from the list, while locked*/
382void
383ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
384 struct ieee80211softmac_network *del_net)
385{
386 list_del(&(del_net->list));
387}
388
389/* Delete a network from the list with locking */
390void
391ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
392 struct ieee80211softmac_network *del_net)
393{
394 unsigned long flags;
395 spin_lock_irqsave(&mac->lock, flags);
396 ieee80211softmac_del_network_locked(mac, del_net);
397 spin_unlock_irqrestore(&mac->lock, flags);
398}
399
400/* Get a network from the list by MAC while locked */
401struct ieee80211softmac_network *
402ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
403 u8 *bssid)
404{
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))
410 break;
411 else
412 softmac_net = NULL;
413 }
414 return softmac_net;
415}
416
417/* Get a network from the list by BSSID with locking */
418struct ieee80211softmac_network *
419ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
420 u8 *bssid)
421{
422 unsigned long flags;
423 struct ieee80211softmac_network *softmac_net;
424
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);
428 return softmac_net;
429}
430
431/* Get a network from the list by ESSID while locked */
432struct ieee80211softmac_network *
433ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
434 struct ieee80211softmac_essid *essid)
435{
436 struct list_head *list_ptr;
437 struct ieee80211softmac_network *softmac_net = NULL;
438
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))
443 return softmac_net;
444 }
445 return NULL;
446}
447
448/* Get a network from the list by ESSID with locking */
449struct ieee80211softmac_network *
450ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
451 struct ieee80211softmac_essid *essid)
452{
453 unsigned long flags;
454 struct ieee80211softmac_network *softmac_net = NULL;
455
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);
459 return softmac_net;
460}
461
462MODULE_LICENSE("GPL");
9ebdd466
JB
463MODULE_AUTHOR("Johannes Berg");
464MODULE_AUTHOR("Joseph Jezak");
465MODULE_AUTHOR("Larry Finger");
466MODULE_AUTHOR("Danny van Dyk");
467MODULE_AUTHOR("Michael Buesch");
468MODULE_DESCRIPTION("802.11 software MAC");
This page took 0.061139 seconds and 5 git commands to generate.