blob: 256207b71dc94ce135aca1d3adc36f5c49875305 [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>
Daniel Drake8462fe32006-05-01 22:45:50 +010029#include <linux/etherdevice.h>
Johannes Berg370121e2006-01-04 16:32:16 +010030
31struct net_device *alloc_ieee80211softmac(int sizeof_priv)
32{
33 struct ieee80211softmac_device *softmac;
34 struct net_device *dev;
35
36 dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
37 softmac = ieee80211_priv(dev);
38 softmac->dev = dev;
39 softmac->ieee = netdev_priv(dev);
40 spin_lock_init(&softmac->lock);
41
42 softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
43 softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
44 softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
Johannes Bergb6c76582006-01-31 19:49:42 +010045 softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
Johannes Berg370121e2006-01-04 16:32:16 +010046 softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
Daniel Drake5acd0c412006-07-18 21:33:27 +010047 softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
Johannes Berg370121e2006-01-04 16:32:16 +010048 softmac->scaninfo = NULL;
49
Johannes Berg818667f2006-04-20 20:02:03 +020050 softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
51
Johannes Berg370121e2006-01-04 16:32:16 +010052 /* TODO: initialise all the other callbacks in the ieee struct
53 * (once they're written)
54 */
55
Johannes Berg370121e2006-01-04 16:32:16 +010056 INIT_LIST_HEAD(&softmac->auth_queue);
57 INIT_LIST_HEAD(&softmac->network_list);
58 INIT_LIST_HEAD(&softmac->events);
59
Michael Buesch7c28ad22006-09-27 15:26:33 +030060 mutex_init(&softmac->associnfo.mutex);
David Howellsc4028952006-11-22 14:57:56 +000061 INIT_DELAYED_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work);
62 INIT_DELAYED_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout);
Johannes Berg370121e2006-01-04 16:32:16 +010063 softmac->start_scan = ieee80211softmac_start_scan_implementation;
64 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
65 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
66
Johannes Berg2dd50802006-01-06 18:11:23 +010067 /* to start with, we can't send anything ... */
68 netif_carrier_off(dev);
Johannes Berg370121e2006-01-04 16:32:16 +010069
Johannes Berg370121e2006-01-04 16:32:16 +010070 return dev;
Johannes Berg370121e2006-01-04 16:32:16 +010071}
Johannes Berg4c718cf2006-01-12 21:19:48 +010072EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
Johannes Berg370121e2006-01-04 16:32:16 +010073
74/* Clears the pending work queue items, stops all scans, etc. */
75void
76ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
77{
78 unsigned long flags;
79 struct ieee80211softmac_event *eventptr, *eventtmp;
80 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
81 struct ieee80211softmac_network *netptr, *nettmp;
82
83 ieee80211softmac_stop_scan(sm);
84 ieee80211softmac_wait_for_scan(sm);
85
86 spin_lock_irqsave(&sm->lock, flags);
Daniel Draked57336e2006-04-30 22:09:07 +010087 sm->running = 0;
88
Johannes Berg370121e2006-01-04 16:32:16 +010089 /* Free all pending assoc work items */
90 cancel_delayed_work(&sm->associnfo.work);
91
92 /* Free all pending scan work items */
93 if(sm->scaninfo != NULL)
94 cancel_delayed_work(&sm->scaninfo->softmac_scan);
95
96 /* Free all pending auth work items */
97 list_for_each_entry(authptr, &sm->auth_queue, list)
98 cancel_delayed_work(&authptr->work);
99
100 /* delete all pending event calls and work items */
101 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
102 cancel_delayed_work(&eventptr->work);
103
104 spin_unlock_irqrestore(&sm->lock, flags);
Johannes Berg5c4df6d2006-01-06 01:43:45 +0100105 flush_scheduled_work();
Johannes Berg370121e2006-01-04 16:32:16 +0100106
Johannes Bergb2b9b6512006-01-11 19:32:02 +0100107 /* now we should be save and no longer need locking... */
Johannes Berg370121e2006-01-04 16:32:16 +0100108 spin_lock_irqsave(&sm->lock, flags);
109 /* Free all pending auth work items */
110 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
111 list_del(&authptr->list);
112 kfree(authptr);
113 }
114
115 /* delete all pending event calls and work items */
116 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
117 list_del(&eventptr->list);
118 kfree(eventptr);
119 }
120
121 /* Free all networks */
122 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
123 ieee80211softmac_del_network_locked(sm, netptr);
124 if(netptr->challenge != NULL)
125 kfree(netptr->challenge);
126 kfree(netptr);
127 }
128
129 spin_unlock_irqrestore(&sm->lock, flags);
130}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100131EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
Johannes Berg370121e2006-01-04 16:32:16 +0100132
133void free_ieee80211softmac(struct net_device *dev)
134{
135 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
136 ieee80211softmac_clear_pending_work(sm);
Johannes Berg370121e2006-01-04 16:32:16 +0100137 kfree(sm->scaninfo);
138 kfree(sm->wpa.IE);
139 free_ieee80211(dev);
140}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100141EXPORT_SYMBOL_GPL(free_ieee80211softmac);
Johannes Berg370121e2006-01-04 16:32:16 +0100142
143static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
144{
145 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
146 /* I took out the sorting check, we're seperating by modulation now. */
147 if (ri->count)
148 return;
149 /* otherwise assume we hav'em all! */
150 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
151 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
152 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
153 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
154 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
155 }
156 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
157 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
158 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
159 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
160 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
161 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
162 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
163 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
164 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
165 }
166}
167
Daniel Drake8462fe32006-05-01 22:45:50 +0100168int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
Johannes Berg370121e2006-01-04 16:32:16 +0100169{
Daniel Drake8462fe32006-05-01 22:45:50 +0100170 int search;
171 u8 search_rate;
172
173 for (search = 0; search < ri->count; search++) {
174 search_rate = ri->rates[search];
175 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
176 if (rate == search_rate)
177 return 1;
178 }
179
180 return 0;
181}
182
Daniel Draked7712ac2006-07-18 21:34:56 +0100183u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
Daniel Drake8462fe32006-05-01 22:45:50 +0100184 struct ieee80211softmac_ratesinfo *ri, int basic_only)
185{
186 u8 user_rate = mac->txrates.user_rate;
187 int i;
188
Daniel Draked7712ac2006-07-18 21:34:56 +0100189 if (ri->count == 0)
Daniel Drake8462fe32006-05-01 22:45:50 +0100190 return IEEE80211_CCK_RATE_1MB;
Daniel Drake8462fe32006-05-01 22:45:50 +0100191
192 for (i = ri->count - 1; i >= 0; i--) {
193 u8 rate = ri->rates[i];
194 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
195 continue;
196 rate &= ~IEEE80211_BASIC_RATE_MASK;
197 if (rate > user_rate)
198 continue;
199 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
200 return rate;
201 }
202
203 /* If we haven't found a suitable rate by now, just trust the user */
204 return user_rate;
205}
Daniel Draked7712ac2006-07-18 21:34:56 +0100206EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
Daniel Drake8462fe32006-05-01 22:45:50 +0100207
Daniel Drake5acd0c412006-07-18 21:33:27 +0100208void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
209 u8 erp_value)
210{
211 int use_protection;
212 int short_preamble;
213 u32 changes = 0;
214
215 /* Barker preamble mode */
216 short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
217 && mac->associnfo.short_preamble_available) ? 1 : 0;
218
219 /* Protection needed? */
220 use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
221
222 if (mac->bssinfo.short_preamble != short_preamble) {
223 changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
224 mac->bssinfo.short_preamble = short_preamble;
225 }
226
227 if (mac->bssinfo.use_protection != use_protection) {
228 changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
229 mac->bssinfo.use_protection = use_protection;
230 }
231
232 if (mac->bssinfo_change && changes)
233 mac->bssinfo_change(mac->dev, changes);
234}
235
Daniel Drake8462fe32006-05-01 22:45:50 +0100236void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
237{
238 struct ieee80211softmac_txrates *txrates = &mac->txrates;
Daniel Drake8462fe32006-05-01 22:45:50 +0100239 u32 change = 0;
240
Daniel Drake8462fe32006-05-01 22:45:50 +0100241 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
Daniel Draked7712ac2006-07-18 21:34:56 +0100242 txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
Daniel Drake8462fe32006-05-01 22:45:50 +0100243
244 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
245 txrates->default_fallback = lower_rate(mac, txrates->default_rate);
246
247 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
Daniel Draked7712ac2006-07-18 21:34:56 +0100248 txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
Daniel Drake8462fe32006-05-01 22:45:50 +0100249
250 if (mac->txrates_change)
Daniel Drake5acd0c412006-07-18 21:33:27 +0100251 mac->txrates_change(mac->dev, change);
Daniel Drake8462fe32006-05-01 22:45:50 +0100252
253}
254
Daniel Drake5acd0c412006-07-18 21:33:27 +0100255void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
Daniel Drake8462fe32006-05-01 22:45:50 +0100256{
Johannes Berg370121e2006-01-04 16:32:16 +0100257 struct ieee80211_device *ieee = mac->ieee;
258 u32 change = 0;
Daniel Drake8462fe32006-05-01 22:45:50 +0100259 struct ieee80211softmac_txrates *txrates = &mac->txrates;
Daniel Drake5acd0c412006-07-18 21:33:27 +0100260 struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
Johannes Berg370121e2006-01-04 16:32:16 +0100261
Johannes Berg370121e2006-01-04 16:32:16 +0100262 /* TODO: We need some kind of state machine to lower the default rates
263 * if we loose too many packets.
264 */
265 /* Change the default txrate to the highest possible value.
266 * The txrate machine will lower it, if it is too high.
267 */
David Woodhouse2638fed2006-03-23 22:43:38 +0000268 /* FIXME: We don't correctly handle backing down to lower
269 rates, so 801.11g devices start off at 11M for now. People
270 can manually change it if they really need to, but 11M is
271 more reliable. Note similar logic in
272 ieee80211softmac_wx_set_rate() */
273 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
Daniel Drake8462fe32006-05-01 22:45:50 +0100274 txrates->user_rate = IEEE80211_CCK_RATE_11MB;
David Woodhouse2638fed2006-03-23 22:43:38 +0000275 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
Daniel Drake8462fe32006-05-01 22:45:50 +0100276 txrates->user_rate = IEEE80211_OFDM_RATE_54MB;
Johannes Berg370121e2006-01-04 16:32:16 +0100277 } else
278 assert(0);
Daniel Drake8462fe32006-05-01 22:45:50 +0100279
280 txrates->default_rate = IEEE80211_CCK_RATE_1MB;
281 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
282
283 txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
284 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
285
286 txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
287 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
288
289 txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
290 change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
291
Johannes Berg370121e2006-01-04 16:32:16 +0100292 if (mac->txrates_change)
Daniel Drake5acd0c412006-07-18 21:33:27 +0100293 mac->txrates_change(mac->dev, change);
294
295 change = 0;
296
297 bssinfo->supported_rates.count = 0;
298 memset(bssinfo->supported_rates.rates, 0,
299 sizeof(bssinfo->supported_rates.rates));
300 change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
301
302 bssinfo->short_preamble = 0;
303 change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
304
305 bssinfo->use_protection = 0;
306 change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
307
308 if (mac->bssinfo_change)
309 mac->bssinfo_change(mac->dev, change);
Daniel Draked57336e2006-04-30 22:09:07 +0100310
311 mac->running = 1;
Johannes Berg370121e2006-01-04 16:32:16 +0100312}
Daniel Drake8462fe32006-05-01 22:45:50 +0100313
314void ieee80211softmac_start(struct net_device *dev)
315{
316 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
317
318 ieee80211softmac_start_check_rates(mac);
Daniel Drake5acd0c412006-07-18 21:33:27 +0100319 ieee80211softmac_init_bss(mac);
Daniel Drake8462fe32006-05-01 22:45:50 +0100320}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100321EXPORT_SYMBOL_GPL(ieee80211softmac_start);
Johannes Berg370121e2006-01-04 16:32:16 +0100322
323void ieee80211softmac_stop(struct net_device *dev)
324{
325 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
326
327 ieee80211softmac_clear_pending_work(mac);
328}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100329EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
Johannes Berg370121e2006-01-04 16:32:16 +0100330
331void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
332{
333 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
334 unsigned long flags;
335
336 spin_lock_irqsave(&mac->lock, flags);
337 memcpy(mac->ratesinfo.rates, rates, count);
338 mac->ratesinfo.count = count;
339 spin_unlock_irqrestore(&mac->lock, flags);
340}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100341EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
Johannes Berg370121e2006-01-04 16:32:16 +0100342
343static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
344{
345 int i;
346 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
347
348 for (i=0; i<ri->count-1; i++) {
349 if (ri->rates[i] == rate)
350 return ri->rates[i+1];
351 }
352 /* I guess we can't go any higher... */
353 return ri->rates[ri->count];
354}
355
356u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
357{
358 int i;
359 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
360
361 for (i=delta; i<ri->count; i++) {
362 if (ri->rates[i] == rate)
363 return ri->rates[i-delta];
364 }
365 /* I guess we can't go any lower... */
366 return ri->rates[0];
367}
368
369static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
370 int amount)
371{
Johannes Berg370121e2006-01-04 16:32:16 +0100372 u8 default_rate = mac->txrates.default_rate;
373 u8 default_fallback = mac->txrates.default_fallback;
374 u32 changes = 0;
375
376 //TODO: This is highly experimental code.
377 // Maybe the dynamic rate selection does not work
378 // and it has to be removed again.
379
380printk("badness %d\n", mac->txrate_badness);
381 mac->txrate_badness += amount;
382 if (mac->txrate_badness <= -1000) {
383 /* Very small badness. Try a faster bitrate. */
Johannes Berg370121e2006-01-04 16:32:16 +0100384 default_rate = raise_rate(mac, default_rate);
385 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
386 default_fallback = get_fallback_rate(mac, default_rate);
387 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
388 mac->txrate_badness = 0;
389printk("Bitrate raised to %u\n", default_rate);
390 } else if (mac->txrate_badness >= 10000) {
391 /* Very high badness. Try a slower bitrate. */
Johannes Berg370121e2006-01-04 16:32:16 +0100392 default_rate = lower_rate(mac, default_rate);
393 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
394 default_fallback = get_fallback_rate(mac, default_rate);
395 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
396 mac->txrate_badness = 0;
397printk("Bitrate lowered to %u\n", default_rate);
398 }
399
400 mac->txrates.default_rate = default_rate;
401 mac->txrates.default_fallback = default_fallback;
402
403 if (changes && mac->txrates_change)
Daniel Drake5acd0c412006-07-18 21:33:27 +0100404 mac->txrates_change(mac->dev, changes);
Johannes Berg370121e2006-01-04 16:32:16 +0100405}
406
407void ieee80211softmac_fragment_lost(struct net_device *dev,
408 u16 wl_seq)
409{
410 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
411 unsigned long flags;
412
413 spin_lock_irqsave(&mac->lock, flags);
414 ieee80211softmac_add_txrates_badness(mac, 1000);
415 //TODO
416
417 spin_unlock_irqrestore(&mac->lock, flags);
418}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100419EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
Johannes Berg370121e2006-01-04 16:32:16 +0100420
421static int rate_cmp(const void *a_, const void *b_) {
422 u8 *a, *b;
423 a = (u8*)a_;
424 b = (u8*)b_;
425 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
426}
427
428/* Allocate a softmac network struct and fill it from a network */
429struct ieee80211softmac_network *
430ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
431 struct ieee80211_network *net)
432{
433 struct ieee80211softmac_network *softnet;
434 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
435 if(softnet == NULL)
436 return NULL;
437 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
438 softnet->channel = net->channel;
439 softnet->essid.len = net->ssid_len;
440 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
441
442 /* copy rates over */
443 softnet->supported_rates.count = net->rates_len;
444 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
445 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
446 softnet->supported_rates.count += net->rates_ex_len;
447 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
Daniel Drake5acd0c412006-07-18 21:33:27 +0100448
449 /* we save the ERP value because it is needed at association time, and
450 * many AP's do not include an ERP IE in the association response. */
451 softnet->erp_value = net->erp_value;
452
Johannes Berg370121e2006-01-04 16:32:16 +0100453 softnet->capabilities = net->capability;
454 return softnet;
455}
456
457
458/* Add a network to the list, while locked */
459void
460ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
461 struct ieee80211softmac_network *add_net)
462{
463 struct list_head *list_ptr;
464 struct ieee80211softmac_network *softmac_net = NULL;
465
466 list_for_each(list_ptr, &mac->network_list) {
467 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
468 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
469 break;
470 else
471 softmac_net = NULL;
472 }
473 if(softmac_net == NULL)
474 list_add(&(add_net->list), &mac->network_list);
475}
476
477/* Add a network to the list, with locking */
478void
479ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
480 struct ieee80211softmac_network *add_net)
481{
482 unsigned long flags;
483 spin_lock_irqsave(&mac->lock, flags);
484 ieee80211softmac_add_network_locked(mac, add_net);
485 spin_unlock_irqrestore(&mac->lock, flags);
486}
487
488
489/* Delete a network from the list, while locked*/
490void
491ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
492 struct ieee80211softmac_network *del_net)
493{
494 list_del(&(del_net->list));
495}
496
497/* Delete a network from the list with locking */
498void
499ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
500 struct ieee80211softmac_network *del_net)
501{
502 unsigned long flags;
503 spin_lock_irqsave(&mac->lock, flags);
504 ieee80211softmac_del_network_locked(mac, del_net);
505 spin_unlock_irqrestore(&mac->lock, flags);
506}
507
508/* Get a network from the list by MAC while locked */
509struct ieee80211softmac_network *
510ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
511 u8 *bssid)
512{
513 struct list_head *list_ptr;
514 struct ieee80211softmac_network *softmac_net = NULL;
515 list_for_each(list_ptr, &mac->network_list) {
516 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
517 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
518 break;
519 else
520 softmac_net = NULL;
521 }
522 return softmac_net;
523}
524
525/* Get a network from the list by BSSID with locking */
526struct ieee80211softmac_network *
527ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
528 u8 *bssid)
529{
530 unsigned long flags;
531 struct ieee80211softmac_network *softmac_net;
532
533 spin_lock_irqsave(&mac->lock, flags);
534 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
535 spin_unlock_irqrestore(&mac->lock, flags);
536 return softmac_net;
537}
538
539/* Get a network from the list by ESSID while locked */
540struct ieee80211softmac_network *
541ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
542 struct ieee80211softmac_essid *essid)
543{
544 struct list_head *list_ptr;
545 struct ieee80211softmac_network *softmac_net = NULL;
546
547 list_for_each(list_ptr, &mac->network_list) {
548 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
549 if (softmac_net->essid.len == essid->len &&
550 !memcmp(softmac_net->essid.data, essid->data, essid->len))
551 return softmac_net;
552 }
553 return NULL;
554}
555
556/* Get a network from the list by ESSID with locking */
557struct ieee80211softmac_network *
558ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
559 struct ieee80211softmac_essid *essid)
560{
561 unsigned long flags;
562 struct ieee80211softmac_network *softmac_net = NULL;
563
564 spin_lock_irqsave(&mac->lock, flags);
565 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
566 spin_unlock_irqrestore(&mac->lock, flags);
567 return softmac_net;
568}
569
570MODULE_LICENSE("GPL");
Johannes Berg9ebdd462006-01-12 21:18:25 +0100571MODULE_AUTHOR("Johannes Berg");
572MODULE_AUTHOR("Joseph Jezak");
573MODULE_AUTHOR("Larry Finger");
574MODULE_AUTHOR("Danny van Dyk");
575MODULE_AUTHOR("Michael Buesch");
576MODULE_DESCRIPTION("802.11 software MAC");