blob: 4b2e57d12418a901185b6124ac3104dbd0e8d69a [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;
47 softmac->scaninfo = NULL;
48
Johannes Berg818667f2006-04-20 20:02:03 +020049 softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
50
Johannes Berg370121e2006-01-04 16:32:16 +010051 /* TODO: initialise all the other callbacks in the ieee struct
52 * (once they're written)
53 */
54
Johannes Berg370121e2006-01-04 16:32:16 +010055 INIT_LIST_HEAD(&softmac->auth_queue);
56 INIT_LIST_HEAD(&softmac->network_list);
57 INIT_LIST_HEAD(&softmac->events);
58
59 INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
60 INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
61 softmac->start_scan = ieee80211softmac_start_scan_implementation;
62 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
63 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
64
Johannes Berg2dd50802006-01-06 18:11:23 +010065 /* to start with, we can't send anything ... */
66 netif_carrier_off(dev);
Johannes Berg370121e2006-01-04 16:32:16 +010067
Johannes Berg370121e2006-01-04 16:32:16 +010068 return dev;
Johannes Berg370121e2006-01-04 16:32:16 +010069}
Johannes Berg4c718cf2006-01-12 21:19:48 +010070EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
Johannes Berg370121e2006-01-04 16:32:16 +010071
72/* Clears the pending work queue items, stops all scans, etc. */
73void
74ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
75{
76 unsigned long flags;
77 struct ieee80211softmac_event *eventptr, *eventtmp;
78 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
79 struct ieee80211softmac_network *netptr, *nettmp;
80
81 ieee80211softmac_stop_scan(sm);
82 ieee80211softmac_wait_for_scan(sm);
83
84 spin_lock_irqsave(&sm->lock, flags);
Daniel Draked57336e2006-04-30 22:09:07 +010085 sm->running = 0;
86
Johannes Berg370121e2006-01-04 16:32:16 +010087 /* Free all pending assoc work items */
88 cancel_delayed_work(&sm->associnfo.work);
89
90 /* Free all pending scan work items */
91 if(sm->scaninfo != NULL)
92 cancel_delayed_work(&sm->scaninfo->softmac_scan);
93
94 /* Free all pending auth work items */
95 list_for_each_entry(authptr, &sm->auth_queue, list)
96 cancel_delayed_work(&authptr->work);
97
98 /* delete all pending event calls and work items */
99 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
100 cancel_delayed_work(&eventptr->work);
101
102 spin_unlock_irqrestore(&sm->lock, flags);
Johannes Berg5c4df6d2006-01-06 01:43:45 +0100103 flush_scheduled_work();
Johannes Berg370121e2006-01-04 16:32:16 +0100104
Johannes Bergb2b9b6512006-01-11 19:32:02 +0100105 /* now we should be save and no longer need locking... */
Johannes Berg370121e2006-01-04 16:32:16 +0100106 spin_lock_irqsave(&sm->lock, flags);
107 /* Free all pending auth work items */
108 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
109 list_del(&authptr->list);
110 kfree(authptr);
111 }
112
113 /* delete all pending event calls and work items */
114 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
115 list_del(&eventptr->list);
116 kfree(eventptr);
117 }
118
119 /* Free all networks */
120 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
121 ieee80211softmac_del_network_locked(sm, netptr);
122 if(netptr->challenge != NULL)
123 kfree(netptr->challenge);
124 kfree(netptr);
125 }
126
127 spin_unlock_irqrestore(&sm->lock, flags);
128}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100129EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
Johannes Berg370121e2006-01-04 16:32:16 +0100130
131void free_ieee80211softmac(struct net_device *dev)
132{
133 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
134 ieee80211softmac_clear_pending_work(sm);
Johannes Berg370121e2006-01-04 16:32:16 +0100135 kfree(sm->scaninfo);
136 kfree(sm->wpa.IE);
137 free_ieee80211(dev);
138}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100139EXPORT_SYMBOL_GPL(free_ieee80211softmac);
Johannes Berg370121e2006-01-04 16:32:16 +0100140
141static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
142{
143 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
144 /* I took out the sorting check, we're seperating by modulation now. */
145 if (ri->count)
146 return;
147 /* otherwise assume we hav'em all! */
148 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
149 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
150 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
151 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
152 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
153 }
154 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
155 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
156 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
157 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
158 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
159 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
160 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
161 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
162 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
163 }
164}
165
Daniel Drake8462fe32006-05-01 22:45:50 +0100166int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
Johannes Berg370121e2006-01-04 16:32:16 +0100167{
Daniel Drake8462fe32006-05-01 22:45:50 +0100168 int search;
169 u8 search_rate;
170
171 for (search = 0; search < ri->count; search++) {
172 search_rate = ri->rates[search];
173 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
174 if (rate == search_rate)
175 return 1;
176 }
177
178 return 0;
179}
180
181/* Finds the highest rate which is:
182 * 1. Present in ri (optionally a basic rate)
183 * 2. Supported by the device
184 * 3. Less than or equal to the user-defined rate
185 */
186static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
187 struct ieee80211softmac_ratesinfo *ri, int basic_only)
188{
189 u8 user_rate = mac->txrates.user_rate;
190 int i;
191
192 if (ri->count == 0) {
193 dprintk(KERN_ERR PFX "empty ratesinfo?\n");
194 return IEEE80211_CCK_RATE_1MB;
195 }
196
197 for (i = ri->count - 1; i >= 0; i--) {
198 u8 rate = ri->rates[i];
199 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
200 continue;
201 rate &= ~IEEE80211_BASIC_RATE_MASK;
202 if (rate > user_rate)
203 continue;
204 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
205 return rate;
206 }
207
208 /* If we haven't found a suitable rate by now, just trust the user */
209 return user_rate;
210}
211
212void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
213{
214 struct ieee80211softmac_txrates *txrates = &mac->txrates;
215 struct ieee80211softmac_txrates oldrates;
216 u32 change = 0;
217
218 if (mac->txrates_change)
219 oldrates = mac->txrates;
220
221 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
222 txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
223
224 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
225 txrates->default_fallback = lower_rate(mac, txrates->default_rate);
226
227 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
228 txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
229
230 if (mac->txrates_change)
231 mac->txrates_change(mac->dev, change, &oldrates);
232
233}
234
235void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
236{
Johannes Berg370121e2006-01-04 16:32:16 +0100237 struct ieee80211_device *ieee = mac->ieee;
238 u32 change = 0;
Daniel Drake8462fe32006-05-01 22:45:50 +0100239 struct ieee80211softmac_txrates *txrates = &mac->txrates;
Johannes Berg370121e2006-01-04 16:32:16 +0100240 struct ieee80211softmac_txrates oldrates;
241
Johannes Berg370121e2006-01-04 16:32:16 +0100242 /* TODO: We need some kind of state machine to lower the default rates
243 * if we loose too many packets.
244 */
245 /* Change the default txrate to the highest possible value.
246 * The txrate machine will lower it, if it is too high.
247 */
248 if (mac->txrates_change)
249 oldrates = mac->txrates;
David Woodhouse2638fed2006-03-23 22:43:38 +0000250 /* FIXME: We don't correctly handle backing down to lower
251 rates, so 801.11g devices start off at 11M for now. People
252 can manually change it if they really need to, but 11M is
253 more reliable. Note similar logic in
254 ieee80211softmac_wx_set_rate() */
255 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
Daniel Drake8462fe32006-05-01 22:45:50 +0100256 txrates->user_rate = IEEE80211_CCK_RATE_11MB;
David Woodhouse2638fed2006-03-23 22:43:38 +0000257 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
Daniel Drake8462fe32006-05-01 22:45:50 +0100258 txrates->user_rate = IEEE80211_OFDM_RATE_54MB;
Johannes Berg370121e2006-01-04 16:32:16 +0100259 } else
260 assert(0);
Daniel Drake8462fe32006-05-01 22:45:50 +0100261
262 txrates->default_rate = IEEE80211_CCK_RATE_1MB;
263 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
264
265 txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
266 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
267
268 txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
269 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
270
271 txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
272 change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
273
Johannes Berg370121e2006-01-04 16:32:16 +0100274 if (mac->txrates_change)
Daniel Drake8462fe32006-05-01 22:45:50 +0100275 mac->txrates_change(mac->dev, change, &oldrates);
Daniel Draked57336e2006-04-30 22:09:07 +0100276
277 mac->running = 1;
Johannes Berg370121e2006-01-04 16:32:16 +0100278}
Daniel Drake8462fe32006-05-01 22:45:50 +0100279
280void ieee80211softmac_start(struct net_device *dev)
281{
282 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
283
284 ieee80211softmac_start_check_rates(mac);
285 ieee80211softmac_init_txrates(mac);
286}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100287EXPORT_SYMBOL_GPL(ieee80211softmac_start);
Johannes Berg370121e2006-01-04 16:32:16 +0100288
289void ieee80211softmac_stop(struct net_device *dev)
290{
291 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
292
293 ieee80211softmac_clear_pending_work(mac);
294}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100295EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
Johannes Berg370121e2006-01-04 16:32:16 +0100296
297void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
298{
299 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
300 unsigned long flags;
301
302 spin_lock_irqsave(&mac->lock, flags);
303 memcpy(mac->ratesinfo.rates, rates, count);
304 mac->ratesinfo.count = count;
305 spin_unlock_irqrestore(&mac->lock, flags);
306}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100307EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
Johannes Berg370121e2006-01-04 16:32:16 +0100308
309static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
310{
311 int i;
312 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
313
314 for (i=0; i<ri->count-1; i++) {
315 if (ri->rates[i] == rate)
316 return ri->rates[i+1];
317 }
318 /* I guess we can't go any higher... */
319 return ri->rates[ri->count];
320}
321
322u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
323{
324 int i;
325 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
326
327 for (i=delta; i<ri->count; i++) {
328 if (ri->rates[i] == rate)
329 return ri->rates[i-delta];
330 }
331 /* I guess we can't go any lower... */
332 return ri->rates[0];
333}
334
335static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
336 int amount)
337{
338 struct ieee80211softmac_txrates oldrates;
339 u8 default_rate = mac->txrates.default_rate;
340 u8 default_fallback = mac->txrates.default_fallback;
341 u32 changes = 0;
342
343 //TODO: This is highly experimental code.
344 // Maybe the dynamic rate selection does not work
345 // and it has to be removed again.
346
347printk("badness %d\n", mac->txrate_badness);
348 mac->txrate_badness += amount;
349 if (mac->txrate_badness <= -1000) {
350 /* Very small badness. Try a faster bitrate. */
351 if (mac->txrates_change)
352 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
353 default_rate = raise_rate(mac, default_rate);
354 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
355 default_fallback = get_fallback_rate(mac, default_rate);
356 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
357 mac->txrate_badness = 0;
358printk("Bitrate raised to %u\n", default_rate);
359 } else if (mac->txrate_badness >= 10000) {
360 /* Very high badness. Try a slower bitrate. */
361 if (mac->txrates_change)
362 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
363 default_rate = lower_rate(mac, default_rate);
364 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
365 default_fallback = get_fallback_rate(mac, default_rate);
366 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
367 mac->txrate_badness = 0;
368printk("Bitrate lowered to %u\n", default_rate);
369 }
370
371 mac->txrates.default_rate = default_rate;
372 mac->txrates.default_fallback = default_fallback;
373
374 if (changes && mac->txrates_change)
375 mac->txrates_change(mac->dev, changes, &oldrates);
376}
377
378void ieee80211softmac_fragment_lost(struct net_device *dev,
379 u16 wl_seq)
380{
381 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
382 unsigned long flags;
383
384 spin_lock_irqsave(&mac->lock, flags);
385 ieee80211softmac_add_txrates_badness(mac, 1000);
386 //TODO
387
388 spin_unlock_irqrestore(&mac->lock, flags);
389}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100390EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
Johannes Berg370121e2006-01-04 16:32:16 +0100391
392static int rate_cmp(const void *a_, const void *b_) {
393 u8 *a, *b;
394 a = (u8*)a_;
395 b = (u8*)b_;
396 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
397}
398
399/* Allocate a softmac network struct and fill it from a network */
400struct ieee80211softmac_network *
401ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
402 struct ieee80211_network *net)
403{
404 struct ieee80211softmac_network *softnet;
405 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
406 if(softnet == NULL)
407 return NULL;
408 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
409 softnet->channel = net->channel;
410 softnet->essid.len = net->ssid_len;
411 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
412
413 /* copy rates over */
414 softnet->supported_rates.count = net->rates_len;
415 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
416 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
417 softnet->supported_rates.count += net->rates_ex_len;
418 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
419
420 softnet->capabilities = net->capability;
421 return softnet;
422}
423
424
425/* Add a network to the list, while locked */
426void
427ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
428 struct ieee80211softmac_network *add_net)
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(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
436 break;
437 else
438 softmac_net = NULL;
439 }
440 if(softmac_net == NULL)
441 list_add(&(add_net->list), &mac->network_list);
442}
443
444/* Add a network to the list, with locking */
445void
446ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
447 struct ieee80211softmac_network *add_net)
448{
449 unsigned long flags;
450 spin_lock_irqsave(&mac->lock, flags);
451 ieee80211softmac_add_network_locked(mac, add_net);
452 spin_unlock_irqrestore(&mac->lock, flags);
453}
454
455
456/* Delete a network from the list, while locked*/
457void
458ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
459 struct ieee80211softmac_network *del_net)
460{
461 list_del(&(del_net->list));
462}
463
464/* Delete a network from the list with locking */
465void
466ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
467 struct ieee80211softmac_network *del_net)
468{
469 unsigned long flags;
470 spin_lock_irqsave(&mac->lock, flags);
471 ieee80211softmac_del_network_locked(mac, del_net);
472 spin_unlock_irqrestore(&mac->lock, flags);
473}
474
475/* Get a network from the list by MAC while locked */
476struct ieee80211softmac_network *
477ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
478 u8 *bssid)
479{
480 struct list_head *list_ptr;
481 struct ieee80211softmac_network *softmac_net = NULL;
482 list_for_each(list_ptr, &mac->network_list) {
483 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
484 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
485 break;
486 else
487 softmac_net = NULL;
488 }
489 return softmac_net;
490}
491
492/* Get a network from the list by BSSID with locking */
493struct ieee80211softmac_network *
494ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
495 u8 *bssid)
496{
497 unsigned long flags;
498 struct ieee80211softmac_network *softmac_net;
499
500 spin_lock_irqsave(&mac->lock, flags);
501 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
502 spin_unlock_irqrestore(&mac->lock, flags);
503 return softmac_net;
504}
505
506/* Get a network from the list by ESSID while locked */
507struct ieee80211softmac_network *
508ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
509 struct ieee80211softmac_essid *essid)
510{
511 struct list_head *list_ptr;
512 struct ieee80211softmac_network *softmac_net = NULL;
513
514 list_for_each(list_ptr, &mac->network_list) {
515 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
516 if (softmac_net->essid.len == essid->len &&
517 !memcmp(softmac_net->essid.data, essid->data, essid->len))
518 return softmac_net;
519 }
520 return NULL;
521}
522
523/* Get a network from the list by ESSID with locking */
524struct ieee80211softmac_network *
525ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
526 struct ieee80211softmac_essid *essid)
527{
528 unsigned long flags;
529 struct ieee80211softmac_network *softmac_net = NULL;
530
531 spin_lock_irqsave(&mac->lock, flags);
532 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
533 spin_unlock_irqrestore(&mac->lock, flags);
534 return softmac_net;
535}
536
537MODULE_LICENSE("GPL");
Johannes Berg9ebdd462006-01-12 21:18:25 +0100538MODULE_AUTHOR("Johannes Berg");
539MODULE_AUTHOR("Joseph Jezak");
540MODULE_AUTHOR("Larry Finger");
541MODULE_AUTHOR("Danny van Dyk");
542MODULE_AUTHOR("Michael Buesch");
543MODULE_DESCRIPTION("802.11 software MAC");