2 * Contains some basic softmac functions along with module registration code etc.
4 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
5 * Joseph Jezak <josejx@gentoo.org>
6 * Larry Finger <Larry.Finger@lwfinger.net>
7 * Danny van Dyk <kugelfang@gentoo.org>
8 * Michael Buesch <mbuesch@freenet.de>
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.
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
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
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
27 #include "ieee80211softmac_priv.h"
28 #include <linux/sort.h>
29 #include <linux/etherdevice.h>
31 struct net_device
*alloc_ieee80211softmac(int sizeof_priv
)
33 struct ieee80211softmac_device
*softmac
;
34 struct net_device
*dev
;
36 dev
= alloc_ieee80211(sizeof(struct ieee80211softmac_device
) + sizeof_priv
);
37 softmac
= ieee80211_priv(dev
);
39 softmac
->ieee
= netdev_priv(dev
);
40 spin_lock_init(&softmac
->lock
);
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
;
45 softmac
->ieee
->handle_reassoc_request
= ieee80211softmac_handle_reassoc_req
;
46 softmac
->ieee
->handle_disassoc
= ieee80211softmac_handle_disassoc
;
47 softmac
->ieee
->handle_beacon
= ieee80211softmac_handle_beacon
;
48 softmac
->scaninfo
= NULL
;
50 softmac
->associnfo
.scan_retry
= IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT
;
52 /* TODO: initialise all the other callbacks in the ieee struct
53 * (once they're written)
56 INIT_LIST_HEAD(&softmac
->auth_queue
);
57 INIT_LIST_HEAD(&softmac
->network_list
);
58 INIT_LIST_HEAD(&softmac
->events
);
60 mutex_init(&softmac
->associnfo
.mutex
);
61 INIT_DELAYED_WORK(&softmac
->associnfo
.work
, ieee80211softmac_assoc_work
);
62 INIT_DELAYED_WORK(&softmac
->associnfo
.timeout
, ieee80211softmac_assoc_timeout
);
63 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
;
67 /* to start with, we can't send anything ... */
68 netif_carrier_off(dev
);
72 EXPORT_SYMBOL_GPL(alloc_ieee80211softmac
);
74 /* Clears the pending work queue items, stops all scans, etc. */
76 ieee80211softmac_clear_pending_work(struct ieee80211softmac_device
*sm
)
79 struct ieee80211softmac_event
*eventptr
, *eventtmp
;
80 struct ieee80211softmac_auth_queue_item
*authptr
, *authtmp
;
81 struct ieee80211softmac_network
*netptr
, *nettmp
;
83 ieee80211softmac_stop_scan(sm
);
84 ieee80211softmac_wait_for_scan(sm
);
86 spin_lock_irqsave(&sm
->lock
, flags
);
89 /* Free all pending assoc work items */
90 cancel_delayed_work(&sm
->associnfo
.work
);
92 /* Free all pending scan work items */
93 if(sm
->scaninfo
!= NULL
)
94 cancel_delayed_work(&sm
->scaninfo
->softmac_scan
);
96 /* Free all pending auth work items */
97 list_for_each_entry(authptr
, &sm
->auth_queue
, list
)
98 cancel_delayed_work(&authptr
->work
);
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
);
104 spin_unlock_irqrestore(&sm
->lock
, flags
);
105 flush_scheduled_work();
107 /* now we should be save and no longer need locking... */
108 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
);
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
);
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
);
129 spin_unlock_irqrestore(&sm
->lock
, flags
);
131 EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work
);
133 void free_ieee80211softmac(struct net_device
*dev
)
135 struct ieee80211softmac_device
*sm
= ieee80211_priv(dev
);
136 ieee80211softmac_clear_pending_work(sm
);
141 EXPORT_SYMBOL_GPL(free_ieee80211softmac
);
143 static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device
*mac
)
145 struct ieee80211softmac_ratesinfo
*ri
= &mac
->ratesinfo
;
146 /* I took out the sorting check, we're seperating by modulation now. */
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
;
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
;
168 int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo
*ri
, u8 rate
)
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
)
183 u8
ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device
*mac
,
184 struct ieee80211softmac_ratesinfo
*ri
, int basic_only
)
186 u8 user_rate
= mac
->txrates
.user_rate
;
190 return IEEE80211_CCK_RATE_1MB
;
192 for (i
= ri
->count
- 1; i
>= 0; i
--) {
193 u8 rate
= ri
->rates
[i
];
194 if (basic_only
&& !(rate
& IEEE80211_BASIC_RATE_MASK
))
196 rate
&= ~IEEE80211_BASIC_RATE_MASK
;
197 if (rate
> user_rate
)
199 if (ieee80211softmac_ratesinfo_rate_supported(&mac
->ratesinfo
, rate
))
203 /* If we haven't found a suitable rate by now, just trust the user */
206 EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate
);
208 void ieee80211softmac_process_erp(struct ieee80211softmac_device
*mac
,
215 /* Barker preamble mode */
216 short_preamble
= ((erp_value
& WLAN_ERP_BARKER_PREAMBLE
) == 0
217 && mac
->associnfo
.short_preamble_available
) ? 1 : 0;
219 /* Protection needed? */
220 use_protection
= (erp_value
& WLAN_ERP_USE_PROTECTION
) != 0;
222 if (mac
->bssinfo
.short_preamble
!= short_preamble
) {
223 changes
|= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE
;
224 mac
->bssinfo
.short_preamble
= short_preamble
;
227 if (mac
->bssinfo
.use_protection
!= use_protection
) {
228 changes
|= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION
;
229 mac
->bssinfo
.use_protection
= use_protection
;
232 if (mac
->bssinfo_change
&& changes
)
233 mac
->bssinfo_change(mac
->dev
, changes
);
236 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device
*mac
)
238 struct ieee80211softmac_txrates
*txrates
= &mac
->txrates
;
241 change
|= IEEE80211SOFTMAC_TXRATECHG_DEFAULT
;
242 txrates
->default_rate
= ieee80211softmac_highest_supported_rate(mac
, &mac
->bssinfo
.supported_rates
, 0);
244 change
|= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK
;
245 txrates
->default_fallback
= lower_rate(mac
, txrates
->default_rate
);
247 change
|= IEEE80211SOFTMAC_TXRATECHG_MCAST
;
248 txrates
->mcast_rate
= ieee80211softmac_highest_supported_rate(mac
, &mac
->bssinfo
.supported_rates
, 1);
250 if (mac
->txrates_change
)
251 mac
->txrates_change(mac
->dev
, change
);
255 void ieee80211softmac_init_bss(struct ieee80211softmac_device
*mac
)
257 struct ieee80211_device
*ieee
= mac
->ieee
;
259 struct ieee80211softmac_txrates
*txrates
= &mac
->txrates
;
260 struct ieee80211softmac_bss_info
*bssinfo
= &mac
->bssinfo
;
262 /* TODO: We need some kind of state machine to lower the default rates
263 * if we loose too many packets.
265 /* Change the default txrate to the highest possible value.
266 * The txrate machine will lower it, if it is too high.
268 /* 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
) {
274 txrates
->user_rate
= IEEE80211_CCK_RATE_11MB
;
275 } else if (ieee
->modulation
& IEEE80211_OFDM_MODULATION
) {
276 txrates
->user_rate
= IEEE80211_OFDM_RATE_54MB
;
280 txrates
->default_rate
= IEEE80211_CCK_RATE_1MB
;
281 change
|= IEEE80211SOFTMAC_TXRATECHG_DEFAULT
;
283 txrates
->default_fallback
= IEEE80211_CCK_RATE_1MB
;
284 change
|= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK
;
286 txrates
->mcast_rate
= IEEE80211_CCK_RATE_1MB
;
287 change
|= IEEE80211SOFTMAC_TXRATECHG_MCAST
;
289 txrates
->mgt_mcast_rate
= IEEE80211_CCK_RATE_1MB
;
290 change
|= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST
;
292 if (mac
->txrates_change
)
293 mac
->txrates_change(mac
->dev
, change
);
297 bssinfo
->supported_rates
.count
= 0;
298 memset(bssinfo
->supported_rates
.rates
, 0,
299 sizeof(bssinfo
->supported_rates
.rates
));
300 change
|= IEEE80211SOFTMAC_BSSINFOCHG_RATES
;
302 bssinfo
->short_preamble
= 0;
303 change
|= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE
;
305 bssinfo
->use_protection
= 0;
306 change
|= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION
;
308 if (mac
->bssinfo_change
)
309 mac
->bssinfo_change(mac
->dev
, change
);
314 void ieee80211softmac_start(struct net_device
*dev
)
316 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
318 ieee80211softmac_start_check_rates(mac
);
319 ieee80211softmac_init_bss(mac
);
321 EXPORT_SYMBOL_GPL(ieee80211softmac_start
);
323 void ieee80211softmac_stop(struct net_device
*dev
)
325 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
327 ieee80211softmac_clear_pending_work(mac
);
329 EXPORT_SYMBOL_GPL(ieee80211softmac_stop
);
331 void ieee80211softmac_set_rates(struct net_device
*dev
, u8 count
, u8
*rates
)
333 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
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
);
341 EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates
);
343 static u8
raise_rate(struct ieee80211softmac_device
*mac
, u8 rate
)
346 struct ieee80211softmac_ratesinfo
*ri
= &mac
->ratesinfo
;
348 for (i
=0; i
<ri
->count
-1; i
++) {
349 if (ri
->rates
[i
] == rate
)
350 return ri
->rates
[i
+1];
352 /* I guess we can't go any higher... */
353 return ri
->rates
[ri
->count
];
356 u8
ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device
*mac
, u8 rate
, int delta
)
359 struct ieee80211softmac_ratesinfo
*ri
= &mac
->ratesinfo
;
361 for (i
=delta
; i
<ri
->count
; i
++) {
362 if (ri
->rates
[i
] == rate
)
363 return ri
->rates
[i
-delta
];
365 /* I guess we can't go any lower... */
369 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device
*mac
,
372 u8 default_rate
= mac
->txrates
.default_rate
;
373 u8 default_fallback
= mac
->txrates
.default_fallback
;
376 //TODO: This is highly experimental code.
377 // Maybe the dynamic rate selection does not work
378 // and it has to be removed again.
380 printk("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. */
384 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;
389 printk("Bitrate raised to %u\n", default_rate
);
390 } else if (mac
->txrate_badness
>= 10000) {
391 /* Very high badness. Try a slower bitrate. */
392 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;
397 printk("Bitrate lowered to %u\n", default_rate
);
400 mac
->txrates
.default_rate
= default_rate
;
401 mac
->txrates
.default_fallback
= default_fallback
;
403 if (changes
&& mac
->txrates_change
)
404 mac
->txrates_change(mac
->dev
, changes
);
407 void ieee80211softmac_fragment_lost(struct net_device
*dev
,
410 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
413 spin_lock_irqsave(&mac
->lock
, flags
);
414 ieee80211softmac_add_txrates_badness(mac
, 1000);
417 spin_unlock_irqrestore(&mac
->lock
, flags
);
419 EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost
);
421 static int rate_cmp(const void *a_
, const void *b_
) {
425 return ((*a
& ~IEEE80211_BASIC_RATE_MASK
) - (*b
& ~IEEE80211_BASIC_RATE_MASK
));
428 /* Allocate a softmac network struct and fill it from a network */
429 struct ieee80211softmac_network
*
430 ieee80211softmac_create_network(struct ieee80211softmac_device
*mac
,
431 struct ieee80211_network
*net
)
433 struct ieee80211softmac_network
*softnet
;
434 softnet
= kzalloc(sizeof(struct ieee80211softmac_network
), GFP_ATOMIC
);
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
);
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
);
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
;
453 softnet
->capabilities
= net
->capability
;
458 /* Add a network to the list, while locked */
460 ieee80211softmac_add_network_locked(struct ieee80211softmac_device
*mac
,
461 struct ieee80211softmac_network
*add_net
)
463 struct list_head
*list_ptr
;
464 struct ieee80211softmac_network
*softmac_net
= NULL
;
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
))
473 if(softmac_net
== NULL
)
474 list_add(&(add_net
->list
), &mac
->network_list
);
477 /* Add a network to the list, with locking */
479 ieee80211softmac_add_network(struct ieee80211softmac_device
*mac
,
480 struct ieee80211softmac_network
*add_net
)
483 spin_lock_irqsave(&mac
->lock
, flags
);
484 ieee80211softmac_add_network_locked(mac
, add_net
);
485 spin_unlock_irqrestore(&mac
->lock
, flags
);
489 /* Delete a network from the list, while locked*/
491 ieee80211softmac_del_network_locked(struct ieee80211softmac_device
*mac
,
492 struct ieee80211softmac_network
*del_net
)
494 list_del(&(del_net
->list
));
497 /* Delete a network from the list with locking */
499 ieee80211softmac_del_network(struct ieee80211softmac_device
*mac
,
500 struct ieee80211softmac_network
*del_net
)
503 spin_lock_irqsave(&mac
->lock
, flags
);
504 ieee80211softmac_del_network_locked(mac
, del_net
);
505 spin_unlock_irqrestore(&mac
->lock
, flags
);
508 /* Get a network from the list by MAC while locked */
509 struct ieee80211softmac_network
*
510 ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device
*mac
,
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
))
525 /* Get a network from the list by BSSID with locking */
526 struct ieee80211softmac_network
*
527 ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device
*mac
,
531 struct ieee80211softmac_network
*softmac_net
;
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
);
539 /* Get a network from the list by ESSID while locked */
540 struct ieee80211softmac_network
*
541 ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device
*mac
,
542 struct ieee80211softmac_essid
*essid
)
544 struct list_head
*list_ptr
;
545 struct ieee80211softmac_network
*softmac_net
= NULL
;
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
))
556 /* Get a network from the list by ESSID with locking */
557 struct ieee80211softmac_network
*
558 ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device
*mac
,
559 struct ieee80211softmac_essid
*essid
)
562 struct ieee80211softmac_network
*softmac_net
= NULL
;
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
);
570 MODULE_LICENSE("GPL");
571 MODULE_AUTHOR("Johannes Berg");
572 MODULE_AUTHOR("Joseph Jezak");
573 MODULE_AUTHOR("Larry Finger");
574 MODULE_AUTHOR("Danny van Dyk");
575 MODULE_AUTHOR("Michael Buesch");
576 MODULE_DESCRIPTION("802.11 software MAC");