blob: c275646b22698ca19d077ca295c8de1da446deef [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 Drake5acd0c42006-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
182/* Finds the highest rate which is:
183 * 1. Present in ri (optionally a basic rate)
184 * 2. Supported by the device
185 * 3. Less than or equal to the user-defined rate
186 */
187static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
188 struct ieee80211softmac_ratesinfo *ri, int basic_only)
189{
190 u8 user_rate = mac->txrates.user_rate;
191 int i;
192
193 if (ri->count == 0) {
194 dprintk(KERN_ERR PFX "empty ratesinfo?\n");
195 return IEEE80211_CCK_RATE_1MB;
196 }
197
198 for (i = ri->count - 1; i >= 0; i--) {
199 u8 rate = ri->rates[i];
200 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
201 continue;
202 rate &= ~IEEE80211_BASIC_RATE_MASK;
203 if (rate > user_rate)
204 continue;
205 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
206 return rate;
207 }
208
209 /* If we haven't found a suitable rate by now, just trust the user */
210 return user_rate;
211}
212
Daniel Drake5acd0c42006-07-18 21:33:27 +0100213void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
214 u8 erp_value)
215{
216 int use_protection;
217 int short_preamble;
218 u32 changes = 0;
219
220 /* Barker preamble mode */
221 short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
222 && mac->associnfo.short_preamble_available) ? 1 : 0;
223
224 /* Protection needed? */
225 use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
226
227 if (mac->bssinfo.short_preamble != short_preamble) {
228 changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
229 mac->bssinfo.short_preamble = short_preamble;
230 }
231
232 if (mac->bssinfo.use_protection != use_protection) {
233 changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
234 mac->bssinfo.use_protection = use_protection;
235 }
236
237 if (mac->bssinfo_change && changes)
238 mac->bssinfo_change(mac->dev, changes);
239}
240
Daniel Drake8462fe32006-05-01 22:45:50 +0100241void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
242{
243 struct ieee80211softmac_txrates *txrates = &mac->txrates;
Daniel Drake8462fe32006-05-01 22:45:50 +0100244 u32 change = 0;
245
Daniel Drake8462fe32006-05-01 22:45:50 +0100246 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
Daniel Drake5acd0c42006-07-18 21:33:27 +0100247 txrates->default_rate = highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
Daniel Drake8462fe32006-05-01 22:45:50 +0100248
249 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
250 txrates->default_fallback = lower_rate(mac, txrates->default_rate);
251
252 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
Daniel Drake5acd0c42006-07-18 21:33:27 +0100253 txrates->mcast_rate = highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
Daniel Drake8462fe32006-05-01 22:45:50 +0100254
255 if (mac->txrates_change)
Daniel Drake5acd0c42006-07-18 21:33:27 +0100256 mac->txrates_change(mac->dev, change);
Daniel Drake8462fe32006-05-01 22:45:50 +0100257
258}
259
Daniel Drake5acd0c42006-07-18 21:33:27 +0100260void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
Daniel Drake8462fe32006-05-01 22:45:50 +0100261{
Johannes Berg370121e2006-01-04 16:32:16 +0100262 struct ieee80211_device *ieee = mac->ieee;
263 u32 change = 0;
Daniel Drake8462fe32006-05-01 22:45:50 +0100264 struct ieee80211softmac_txrates *txrates = &mac->txrates;
Daniel Drake5acd0c42006-07-18 21:33:27 +0100265 struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
Johannes Berg370121e2006-01-04 16:32:16 +0100266
Johannes Berg370121e2006-01-04 16:32:16 +0100267 /* TODO: We need some kind of state machine to lower the default rates
268 * if we loose too many packets.
269 */
270 /* Change the default txrate to the highest possible value.
271 * The txrate machine will lower it, if it is too high.
272 */
David Woodhouse2638fed2006-03-23 22:43:38 +0000273 /* FIXME: We don't correctly handle backing down to lower
274 rates, so 801.11g devices start off at 11M for now. People
275 can manually change it if they really need to, but 11M is
276 more reliable. Note similar logic in
277 ieee80211softmac_wx_set_rate() */
278 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
Daniel Drake8462fe32006-05-01 22:45:50 +0100279 txrates->user_rate = IEEE80211_CCK_RATE_11MB;
David Woodhouse2638fed2006-03-23 22:43:38 +0000280 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
Daniel Drake8462fe32006-05-01 22:45:50 +0100281 txrates->user_rate = IEEE80211_OFDM_RATE_54MB;
Johannes Berg370121e2006-01-04 16:32:16 +0100282 } else
283 assert(0);
Daniel Drake8462fe32006-05-01 22:45:50 +0100284
285 txrates->default_rate = IEEE80211_CCK_RATE_1MB;
286 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
287
288 txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
289 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
290
291 txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
292 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
293
294 txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
295 change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
296
Johannes Berg370121e2006-01-04 16:32:16 +0100297 if (mac->txrates_change)
Daniel Drake5acd0c42006-07-18 21:33:27 +0100298 mac->txrates_change(mac->dev, change);
299
300 change = 0;
301
302 bssinfo->supported_rates.count = 0;
303 memset(bssinfo->supported_rates.rates, 0,
304 sizeof(bssinfo->supported_rates.rates));
305 change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
306
307 bssinfo->short_preamble = 0;
308 change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
309
310 bssinfo->use_protection = 0;
311 change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
312
313 if (mac->bssinfo_change)
314 mac->bssinfo_change(mac->dev, change);
Daniel Draked57336e2006-04-30 22:09:07 +0100315
316 mac->running = 1;
Johannes Berg370121e2006-01-04 16:32:16 +0100317}
Daniel Drake8462fe32006-05-01 22:45:50 +0100318
319void ieee80211softmac_start(struct net_device *dev)
320{
321 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
322
323 ieee80211softmac_start_check_rates(mac);
Daniel Drake5acd0c42006-07-18 21:33:27 +0100324 ieee80211softmac_init_bss(mac);
Daniel Drake8462fe32006-05-01 22:45:50 +0100325}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100326EXPORT_SYMBOL_GPL(ieee80211softmac_start);
Johannes Berg370121e2006-01-04 16:32:16 +0100327
328void ieee80211softmac_stop(struct net_device *dev)
329{
330 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
331
332 ieee80211softmac_clear_pending_work(mac);
333}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100334EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
Johannes Berg370121e2006-01-04 16:32:16 +0100335
336void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
337{
338 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
339 unsigned long flags;
340
341 spin_lock_irqsave(&mac->lock, flags);
342 memcpy(mac->ratesinfo.rates, rates, count);
343 mac->ratesinfo.count = count;
344 spin_unlock_irqrestore(&mac->lock, flags);
345}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100346EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
Johannes Berg370121e2006-01-04 16:32:16 +0100347
348static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
349{
350 int i;
351 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
352
353 for (i=0; i<ri->count-1; i++) {
354 if (ri->rates[i] == rate)
355 return ri->rates[i+1];
356 }
357 /* I guess we can't go any higher... */
358 return ri->rates[ri->count];
359}
360
361u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
362{
363 int i;
364 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
365
366 for (i=delta; i<ri->count; i++) {
367 if (ri->rates[i] == rate)
368 return ri->rates[i-delta];
369 }
370 /* I guess we can't go any lower... */
371 return ri->rates[0];
372}
373
374static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
375 int amount)
376{
Johannes Berg370121e2006-01-04 16:32:16 +0100377 u8 default_rate = mac->txrates.default_rate;
378 u8 default_fallback = mac->txrates.default_fallback;
379 u32 changes = 0;
380
381 //TODO: This is highly experimental code.
382 // Maybe the dynamic rate selection does not work
383 // and it has to be removed again.
384
385printk("badness %d\n", mac->txrate_badness);
386 mac->txrate_badness += amount;
387 if (mac->txrate_badness <= -1000) {
388 /* Very small badness. Try a faster bitrate. */
Johannes Berg370121e2006-01-04 16:32:16 +0100389 default_rate = raise_rate(mac, default_rate);
390 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
391 default_fallback = get_fallback_rate(mac, default_rate);
392 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
393 mac->txrate_badness = 0;
394printk("Bitrate raised to %u\n", default_rate);
395 } else if (mac->txrate_badness >= 10000) {
396 /* Very high badness. Try a slower bitrate. */
Johannes Berg370121e2006-01-04 16:32:16 +0100397 default_rate = lower_rate(mac, default_rate);
398 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
399 default_fallback = get_fallback_rate(mac, default_rate);
400 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
401 mac->txrate_badness = 0;
402printk("Bitrate lowered to %u\n", default_rate);
403 }
404
405 mac->txrates.default_rate = default_rate;
406 mac->txrates.default_fallback = default_fallback;
407
408 if (changes && mac->txrates_change)
Daniel Drake5acd0c42006-07-18 21:33:27 +0100409 mac->txrates_change(mac->dev, changes);
Johannes Berg370121e2006-01-04 16:32:16 +0100410}
411
412void ieee80211softmac_fragment_lost(struct net_device *dev,
413 u16 wl_seq)
414{
415 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
416 unsigned long flags;
417
418 spin_lock_irqsave(&mac->lock, flags);
419 ieee80211softmac_add_txrates_badness(mac, 1000);
420 //TODO
421
422 spin_unlock_irqrestore(&mac->lock, flags);
423}
Johannes Berg4c718cf2006-01-12 21:19:48 +0100424EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
Johannes Berg370121e2006-01-04 16:32:16 +0100425
426static int rate_cmp(const void *a_, const void *b_) {
427 u8 *a, *b;
428 a = (u8*)a_;
429 b = (u8*)b_;
430 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
431}
432
433/* Allocate a softmac network struct and fill it from a network */
434struct ieee80211softmac_network *
435ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
436 struct ieee80211_network *net)
437{
438 struct ieee80211softmac_network *softnet;
439 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
440 if(softnet == NULL)
441 return NULL;
442 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
443 softnet->channel = net->channel;
444 softnet->essid.len = net->ssid_len;
445 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
446
447 /* copy rates over */
448 softnet->supported_rates.count = net->rates_len;
449 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
450 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
451 softnet->supported_rates.count += net->rates_ex_len;
452 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
Daniel Drake5acd0c42006-07-18 21:33:27 +0100453
454 /* we save the ERP value because it is needed at association time, and
455 * many AP's do not include an ERP IE in the association response. */
456 softnet->erp_value = net->erp_value;
457
Johannes Berg370121e2006-01-04 16:32:16 +0100458 softnet->capabilities = net->capability;
459 return softnet;
460}
461
462
463/* Add a network to the list, while locked */
464void
465ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
466 struct ieee80211softmac_network *add_net)
467{
468 struct list_head *list_ptr;
469 struct ieee80211softmac_network *softmac_net = NULL;
470
471 list_for_each(list_ptr, &mac->network_list) {
472 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
473 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
474 break;
475 else
476 softmac_net = NULL;
477 }
478 if(softmac_net == NULL)
479 list_add(&(add_net->list), &mac->network_list);
480}
481
482/* Add a network to the list, with locking */
483void
484ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
485 struct ieee80211softmac_network *add_net)
486{
487 unsigned long flags;
488 spin_lock_irqsave(&mac->lock, flags);
489 ieee80211softmac_add_network_locked(mac, add_net);
490 spin_unlock_irqrestore(&mac->lock, flags);
491}
492
493
494/* Delete a network from the list, while locked*/
495void
496ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
497 struct ieee80211softmac_network *del_net)
498{
499 list_del(&(del_net->list));
500}
501
502/* Delete a network from the list with locking */
503void
504ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
505 struct ieee80211softmac_network *del_net)
506{
507 unsigned long flags;
508 spin_lock_irqsave(&mac->lock, flags);
509 ieee80211softmac_del_network_locked(mac, del_net);
510 spin_unlock_irqrestore(&mac->lock, flags);
511}
512
513/* Get a network from the list by MAC while locked */
514struct ieee80211softmac_network *
515ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
516 u8 *bssid)
517{
518 struct list_head *list_ptr;
519 struct ieee80211softmac_network *softmac_net = NULL;
520 list_for_each(list_ptr, &mac->network_list) {
521 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
522 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
523 break;
524 else
525 softmac_net = NULL;
526 }
527 return softmac_net;
528}
529
530/* Get a network from the list by BSSID with locking */
531struct ieee80211softmac_network *
532ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
533 u8 *bssid)
534{
535 unsigned long flags;
536 struct ieee80211softmac_network *softmac_net;
537
538 spin_lock_irqsave(&mac->lock, flags);
539 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
540 spin_unlock_irqrestore(&mac->lock, flags);
541 return softmac_net;
542}
543
544/* Get a network from the list by ESSID while locked */
545struct ieee80211softmac_network *
546ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
547 struct ieee80211softmac_essid *essid)
548{
549 struct list_head *list_ptr;
550 struct ieee80211softmac_network *softmac_net = NULL;
551
552 list_for_each(list_ptr, &mac->network_list) {
553 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
554 if (softmac_net->essid.len == essid->len &&
555 !memcmp(softmac_net->essid.data, essid->data, essid->len))
556 return softmac_net;
557 }
558 return NULL;
559}
560
561/* Get a network from the list by ESSID with locking */
562struct ieee80211softmac_network *
563ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
564 struct ieee80211softmac_essid *essid)
565{
566 unsigned long flags;
567 struct ieee80211softmac_network *softmac_net = NULL;
568
569 spin_lock_irqsave(&mac->lock, flags);
570 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
571 spin_unlock_irqrestore(&mac->lock, flags);
572 return softmac_net;
573}
574
575MODULE_LICENSE("GPL");
Johannes Berg9ebdd462006-01-12 21:18:25 +0100576MODULE_AUTHOR("Johannes Berg");
577MODULE_AUTHOR("Joseph Jezak");
578MODULE_AUTHOR("Larry Finger");
579MODULE_AUTHOR("Danny van Dyk");
580MODULE_AUTHOR("Michael Buesch");
581MODULE_DESCRIPTION("802.11 software MAC");