blob: addea1cf73ae3f5ba9f2787af8503bb354b97778 [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
60 INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
61 INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
62 softmac->start_scan = ieee80211softmac_start_scan_implementation;
63 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
64 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
65
Johannes Berg2dd50802006-01-06 18:11:23 +010066 /* to start with, we can't send anything ... */
67 netif_carrier_off(dev);
Johannes Berg370121e2006-01-04 16:32:16 +010068
Johannes Berg370121e2006-01-04 16:32:16 +010069 return dev;
Johannes Berg370121e2006-01-04 16:32:16 +010070}
Johannes Berg4c718cf2006-01-12 21:19:48 +010071EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
Johannes Berg370121e2006-01-04 16:32:16 +010072
73/* Clears the pending work queue items, stops all scans, etc. */
74void
75ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
76{
77 unsigned long flags;
78 struct ieee80211softmac_event *eventptr, *eventtmp;
79 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
80 struct ieee80211softmac_network *netptr, *nettmp;
81
82 ieee80211softmac_stop_scan(sm);
83 ieee80211softmac_wait_for_scan(sm);
84
85 spin_lock_irqsave(&sm->lock, flags);
Daniel Draked57336e2006-04-30 22:09:07 +010086 sm->running = 0;
87
Johannes Berg370121e2006-01-04 16:32:16 +010088 /* Free all pending assoc work items */
89 cancel_delayed_work(&sm->associnfo.work);
90
91 /* Free all pending scan work items */
92 if(sm->scaninfo != NULL)
93 cancel_delayed_work(&sm->scaninfo->softmac_scan);
94
95 /* Free all pending auth work items */
96 list_for_each_entry(authptr, &sm->auth_queue, list)
97 cancel_delayed_work(&authptr->work);
98
99 /* delete all pending event calls and work items */
100 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
101 cancel_delayed_work(&eventptr->work);
102
103 spin_unlock_irqrestore(&sm->lock, flags);
Johannes Berg5c4df6d2006-01-06 01:43:45 +0100104 flush_scheduled_work();
Johannes Berg370121e2006-01-04 16:32:16 +0100105
Johannes Bergb2b9b6512006-01-11 19:32:02 +0100106 /* now we should be save and no longer need locking... */
Johannes Berg370121e2006-01-04 16:32:16 +0100107 spin_lock_irqsave(&sm->lock, flags);
108 /* Free all pending auth work items */
109 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
110 list_del(&authptr->list);
111 kfree(authptr);
112 }
113
114 /* delete all pending event calls and work items */
115 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
116 list_del(&eventptr->list);
117 kfree(eventptr);
118 }
119
120 /* Free all networks */
121 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
122 ieee80211softmac_del_network_locked(sm, netptr);
123 if(netptr->challenge != NULL)
124 kfree(netptr->challenge);
125 kfree(netptr);
126 }
127
128 spin_unlock_irqrestore(&sm->lock, flags);
129}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100130EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
Johannes Berg370121e2006-01-04 16:32:16 +0100131
132void free_ieee80211softmac(struct net_device *dev)
133{
134 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
135 ieee80211softmac_clear_pending_work(sm);
Johannes Berg370121e2006-01-04 16:32:16 +0100136 kfree(sm->scaninfo);
137 kfree(sm->wpa.IE);
138 free_ieee80211(dev);
139}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100140EXPORT_SYMBOL_GPL(free_ieee80211softmac);
Johannes Berg370121e2006-01-04 16:32:16 +0100141
142static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
143{
144 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
145 /* I took out the sorting check, we're seperating by modulation now. */
146 if (ri->count)
147 return;
148 /* otherwise assume we hav'em all! */
149 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
150 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
151 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
152 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
153 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
154 }
155 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
156 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
157 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
158 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
159 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
160 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
161 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
162 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
163 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
164 }
165}
166
Daniel Drake8462fe32006-05-01 22:45:50 +0100167int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
Johannes Berg370121e2006-01-04 16:32:16 +0100168{
Daniel Drake8462fe32006-05-01 22:45:50 +0100169 int search;
170 u8 search_rate;
171
172 for (search = 0; search < ri->count; search++) {
173 search_rate = ri->rates[search];
174 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
175 if (rate == search_rate)
176 return 1;
177 }
178
179 return 0;
180}
181
Daniel Draked7712ac2006-07-18 21:34:56 +0100182u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
Daniel Drake8462fe32006-05-01 22:45:50 +0100183 struct ieee80211softmac_ratesinfo *ri, int basic_only)
184{
185 u8 user_rate = mac->txrates.user_rate;
186 int i;
187
Daniel Draked7712ac2006-07-18 21:34:56 +0100188 if (ri->count == 0)
Daniel Drake8462fe32006-05-01 22:45:50 +0100189 return IEEE80211_CCK_RATE_1MB;
Daniel Drake8462fe32006-05-01 22:45:50 +0100190
191 for (i = ri->count - 1; i >= 0; i--) {
192 u8 rate = ri->rates[i];
193 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
194 continue;
195 rate &= ~IEEE80211_BASIC_RATE_MASK;
196 if (rate > user_rate)
197 continue;
198 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
199 return rate;
200 }
201
202 /* If we haven't found a suitable rate by now, just trust the user */
203 return user_rate;
204}
Daniel Draked7712ac2006-07-18 21:34:56 +0100205EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
Daniel Drake8462fe32006-05-01 22:45:50 +0100206
Daniel Drake5acd0c412006-07-18 21:33:27 +0100207void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
208 u8 erp_value)
209{
210 int use_protection;
211 int short_preamble;
212 u32 changes = 0;
213
214 /* Barker preamble mode */
215 short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
216 && mac->associnfo.short_preamble_available) ? 1 : 0;
217
218 /* Protection needed? */
219 use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
220
221 if (mac->bssinfo.short_preamble != short_preamble) {
222 changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
223 mac->bssinfo.short_preamble = short_preamble;
224 }
225
226 if (mac->bssinfo.use_protection != use_protection) {
227 changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
228 mac->bssinfo.use_protection = use_protection;
229 }
230
231 if (mac->bssinfo_change && changes)
232 mac->bssinfo_change(mac->dev, changes);
233}
234
Daniel Drake8462fe32006-05-01 22:45:50 +0100235void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
236{
237 struct ieee80211softmac_txrates *txrates = &mac->txrates;
Daniel Drake8462fe32006-05-01 22:45:50 +0100238 u32 change = 0;
239
Daniel Drake8462fe32006-05-01 22:45:50 +0100240 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
Daniel Draked7712ac2006-07-18 21:34:56 +0100241 txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
Daniel Drake8462fe32006-05-01 22:45:50 +0100242
243 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
244 txrates->default_fallback = lower_rate(mac, txrates->default_rate);
245
246 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
Daniel Draked7712ac2006-07-18 21:34:56 +0100247 txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
Daniel Drake8462fe32006-05-01 22:45:50 +0100248
249 if (mac->txrates_change)
Daniel Drake5acd0c412006-07-18 21:33:27 +0100250 mac->txrates_change(mac->dev, change);
Daniel Drake8462fe32006-05-01 22:45:50 +0100251
252}
253
Daniel Drake5acd0c412006-07-18 21:33:27 +0100254void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
Daniel Drake8462fe32006-05-01 22:45:50 +0100255{
Johannes Berg370121e2006-01-04 16:32:16 +0100256 struct ieee80211_device *ieee = mac->ieee;
257 u32 change = 0;
Daniel Drake8462fe32006-05-01 22:45:50 +0100258 struct ieee80211softmac_txrates *txrates = &mac->txrates;
Daniel Drake5acd0c412006-07-18 21:33:27 +0100259 struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
Johannes Berg370121e2006-01-04 16:32:16 +0100260
Johannes Berg370121e2006-01-04 16:32:16 +0100261 /* TODO: We need some kind of state machine to lower the default rates
262 * if we loose too many packets.
263 */
264 /* Change the default txrate to the highest possible value.
265 * The txrate machine will lower it, if it is too high.
266 */
David Woodhouse2638fed2006-03-23 22:43:38 +0000267 /* FIXME: We don't correctly handle backing down to lower
268 rates, so 801.11g devices start off at 11M for now. People
269 can manually change it if they really need to, but 11M is
270 more reliable. Note similar logic in
271 ieee80211softmac_wx_set_rate() */
272 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
Daniel Drake8462fe32006-05-01 22:45:50 +0100273 txrates->user_rate = IEEE80211_CCK_RATE_11MB;
David Woodhouse2638fed2006-03-23 22:43:38 +0000274 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
Daniel Drake8462fe32006-05-01 22:45:50 +0100275 txrates->user_rate = IEEE80211_OFDM_RATE_54MB;
Johannes Berg370121e2006-01-04 16:32:16 +0100276 } else
277 assert(0);
Daniel Drake8462fe32006-05-01 22:45:50 +0100278
279 txrates->default_rate = IEEE80211_CCK_RATE_1MB;
280 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
281
282 txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
283 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
284
285 txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
286 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
287
288 txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
289 change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
290
Johannes Berg370121e2006-01-04 16:32:16 +0100291 if (mac->txrates_change)
Daniel Drake5acd0c412006-07-18 21:33:27 +0100292 mac->txrates_change(mac->dev, change);
293
294 change = 0;
295
296 bssinfo->supported_rates.count = 0;
297 memset(bssinfo->supported_rates.rates, 0,
298 sizeof(bssinfo->supported_rates.rates));
299 change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
300
301 bssinfo->short_preamble = 0;
302 change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
303
304 bssinfo->use_protection = 0;
305 change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
306
307 if (mac->bssinfo_change)
308 mac->bssinfo_change(mac->dev, change);
Daniel Draked57336e2006-04-30 22:09:07 +0100309
310 mac->running = 1;
Johannes Berg370121e2006-01-04 16:32:16 +0100311}
Daniel Drake8462fe32006-05-01 22:45:50 +0100312
313void ieee80211softmac_start(struct net_device *dev)
314{
315 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
316
317 ieee80211softmac_start_check_rates(mac);
Daniel Drake5acd0c412006-07-18 21:33:27 +0100318 ieee80211softmac_init_bss(mac);
Daniel Drake8462fe32006-05-01 22:45:50 +0100319}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100320EXPORT_SYMBOL_GPL(ieee80211softmac_start);
Johannes Berg370121e2006-01-04 16:32:16 +0100321
322void ieee80211softmac_stop(struct net_device *dev)
323{
324 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
325
326 ieee80211softmac_clear_pending_work(mac);
327}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100328EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
Johannes Berg370121e2006-01-04 16:32:16 +0100329
330void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
331{
332 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
333 unsigned long flags;
334
335 spin_lock_irqsave(&mac->lock, flags);
336 memcpy(mac->ratesinfo.rates, rates, count);
337 mac->ratesinfo.count = count;
338 spin_unlock_irqrestore(&mac->lock, flags);
339}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100340EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
Johannes Berg370121e2006-01-04 16:32:16 +0100341
342static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
343{
344 int i;
345 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
346
347 for (i=0; i<ri->count-1; i++) {
348 if (ri->rates[i] == rate)
349 return ri->rates[i+1];
350 }
351 /* I guess we can't go any higher... */
352 return ri->rates[ri->count];
353}
354
355u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
356{
357 int i;
358 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
359
360 for (i=delta; i<ri->count; i++) {
361 if (ri->rates[i] == rate)
362 return ri->rates[i-delta];
363 }
364 /* I guess we can't go any lower... */
365 return ri->rates[0];
366}
367
368static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
369 int amount)
370{
Johannes Berg370121e2006-01-04 16:32:16 +0100371 u8 default_rate = mac->txrates.default_rate;
372 u8 default_fallback = mac->txrates.default_fallback;
373 u32 changes = 0;
374
375 //TODO: This is highly experimental code.
376 // Maybe the dynamic rate selection does not work
377 // and it has to be removed again.
378
379printk("badness %d\n", mac->txrate_badness);
380 mac->txrate_badness += amount;
381 if (mac->txrate_badness <= -1000) {
382 /* Very small badness. Try a faster bitrate. */
Johannes Berg370121e2006-01-04 16:32:16 +0100383 default_rate = raise_rate(mac, default_rate);
384 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
385 default_fallback = get_fallback_rate(mac, default_rate);
386 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
387 mac->txrate_badness = 0;
388printk("Bitrate raised to %u\n", default_rate);
389 } else if (mac->txrate_badness >= 10000) {
390 /* Very high badness. Try a slower bitrate. */
Johannes Berg370121e2006-01-04 16:32:16 +0100391 default_rate = lower_rate(mac, default_rate);
392 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
393 default_fallback = get_fallback_rate(mac, default_rate);
394 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
395 mac->txrate_badness = 0;
396printk("Bitrate lowered to %u\n", default_rate);
397 }
398
399 mac->txrates.default_rate = default_rate;
400 mac->txrates.default_fallback = default_fallback;
401
402 if (changes && mac->txrates_change)
Daniel Drake5acd0c412006-07-18 21:33:27 +0100403 mac->txrates_change(mac->dev, changes);
Johannes Berg370121e2006-01-04 16:32:16 +0100404}
405
406void ieee80211softmac_fragment_lost(struct net_device *dev,
407 u16 wl_seq)
408{
409 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
410 unsigned long flags;
411
412 spin_lock_irqsave(&mac->lock, flags);
413 ieee80211softmac_add_txrates_badness(mac, 1000);
414 //TODO
415
416 spin_unlock_irqrestore(&mac->lock, flags);
417}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100418EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
Johannes Berg370121e2006-01-04 16:32:16 +0100419
420static int rate_cmp(const void *a_, const void *b_) {
421 u8 *a, *b;
422 a = (u8*)a_;
423 b = (u8*)b_;
424 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
425}
426
427/* Allocate a softmac network struct and fill it from a network */
428struct ieee80211softmac_network *
429ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
430 struct ieee80211_network *net)
431{
432 struct ieee80211softmac_network *softnet;
433 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
434 if(softnet == NULL)
435 return NULL;
436 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
437 softnet->channel = net->channel;
438 softnet->essid.len = net->ssid_len;
439 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
440
441 /* copy rates over */
442 softnet->supported_rates.count = net->rates_len;
443 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
444 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
445 softnet->supported_rates.count += net->rates_ex_len;
446 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 +0100447
448 /* we save the ERP value because it is needed at association time, and
449 * many AP's do not include an ERP IE in the association response. */
450 softnet->erp_value = net->erp_value;
451
Johannes Berg370121e2006-01-04 16:32:16 +0100452 softnet->capabilities = net->capability;
453 return softnet;
454}
455
456
457/* Add a network to the list, while locked */
458void
459ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
460 struct ieee80211softmac_network *add_net)
461{
462 struct list_head *list_ptr;
463 struct ieee80211softmac_network *softmac_net = NULL;
464
465 list_for_each(list_ptr, &mac->network_list) {
466 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
467 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
468 break;
469 else
470 softmac_net = NULL;
471 }
472 if(softmac_net == NULL)
473 list_add(&(add_net->list), &mac->network_list);
474}
475
476/* Add a network to the list, with locking */
477void
478ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
479 struct ieee80211softmac_network *add_net)
480{
481 unsigned long flags;
482 spin_lock_irqsave(&mac->lock, flags);
483 ieee80211softmac_add_network_locked(mac, add_net);
484 spin_unlock_irqrestore(&mac->lock, flags);
485}
486
487
488/* Delete a network from the list, while locked*/
489void
490ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
491 struct ieee80211softmac_network *del_net)
492{
493 list_del(&(del_net->list));
494}
495
496/* Delete a network from the list with locking */
497void
498ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
499 struct ieee80211softmac_network *del_net)
500{
501 unsigned long flags;
502 spin_lock_irqsave(&mac->lock, flags);
503 ieee80211softmac_del_network_locked(mac, del_net);
504 spin_unlock_irqrestore(&mac->lock, flags);
505}
506
507/* Get a network from the list by MAC while locked */
508struct ieee80211softmac_network *
509ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
510 u8 *bssid)
511{
512 struct list_head *list_ptr;
513 struct ieee80211softmac_network *softmac_net = NULL;
514 list_for_each(list_ptr, &mac->network_list) {
515 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
516 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
517 break;
518 else
519 softmac_net = NULL;
520 }
521 return softmac_net;
522}
523
524/* Get a network from the list by BSSID with locking */
525struct ieee80211softmac_network *
526ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
527 u8 *bssid)
528{
529 unsigned long flags;
530 struct ieee80211softmac_network *softmac_net;
531
532 spin_lock_irqsave(&mac->lock, flags);
533 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
534 spin_unlock_irqrestore(&mac->lock, flags);
535 return softmac_net;
536}
537
538/* Get a network from the list by ESSID while locked */
539struct ieee80211softmac_network *
540ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
541 struct ieee80211softmac_essid *essid)
542{
543 struct list_head *list_ptr;
544 struct ieee80211softmac_network *softmac_net = NULL;
545
546 list_for_each(list_ptr, &mac->network_list) {
547 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
548 if (softmac_net->essid.len == essid->len &&
549 !memcmp(softmac_net->essid.data, essid->data, essid->len))
550 return softmac_net;
551 }
552 return NULL;
553}
554
555/* Get a network from the list by ESSID with locking */
556struct ieee80211softmac_network *
557ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
558 struct ieee80211softmac_essid *essid)
559{
560 unsigned long flags;
561 struct ieee80211softmac_network *softmac_net = NULL;
562
563 spin_lock_irqsave(&mac->lock, flags);
564 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
565 spin_unlock_irqrestore(&mac->lock, flags);
566 return softmac_net;
567}
568
569MODULE_LICENSE("GPL");
Johannes Berg9ebdd462006-01-12 21:18:25 +0100570MODULE_AUTHOR("Johannes Berg");
571MODULE_AUTHOR("Joseph Jezak");
572MODULE_AUTHOR("Larry Finger");
573MODULE_AUTHOR("Danny van Dyk");
574MODULE_AUTHOR("Michael Buesch");
575MODULE_DESCRIPTION("802.11 software MAC");