aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee80211')
-rw-r--r--net/ieee80211/Kconfig1
-rw-r--r--net/ieee80211/Makefile1
-rw-r--r--net/ieee80211/softmac/Kconfig12
-rw-r--r--net/ieee80211/softmac/Makefile9
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c489
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c413
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_event.c189
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_io.c488
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c568
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_priv.h244
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_scan.c254
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c508
12 files changed, 0 insertions, 3176 deletions
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
index bd501046c9c0..94ed7d3cd9da 100644
--- a/net/ieee80211/Kconfig
+++ b/net/ieee80211/Kconfig
@@ -71,4 +71,3 @@ config IEEE80211_CRYPT_TKIP
71 This can be compiled as a module and it will be called 71 This can be compiled as a module and it will be called
72 "ieee80211_crypt_tkip". 72 "ieee80211_crypt_tkip".
73 73
74source "net/ieee80211/softmac/Kconfig"
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile
index 796a7c76ee48..f988417121da 100644
--- a/net/ieee80211/Makefile
+++ b/net/ieee80211/Makefile
@@ -10,4 +10,3 @@ ieee80211-objs := \
10 ieee80211_wx.o \ 10 ieee80211_wx.o \
11 ieee80211_geo.o 11 ieee80211_geo.o
12 12
13obj-$(CONFIG_IEEE80211_SOFTMAC) += softmac/
diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig
deleted file mode 100644
index 2811651cb134..000000000000
--- a/net/ieee80211/softmac/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
1config IEEE80211_SOFTMAC
2 tristate "Software MAC add-on to the IEEE 802.11 networking stack"
3 depends on IEEE80211 && EXPERIMENTAL
4 select WIRELESS_EXT
5 select IEEE80211_CRYPT_WEP
6 ---help---
7 This option enables the hardware independent software MAC addon
8 for the IEEE 802.11 networking stack.
9
10config IEEE80211_SOFTMAC_DEBUG
11 bool "Enable full debugging output"
12 depends on IEEE80211_SOFTMAC
diff --git a/net/ieee80211/softmac/Makefile b/net/ieee80211/softmac/Makefile
deleted file mode 100644
index bfcb391bb2c7..000000000000
--- a/net/ieee80211/softmac/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
1obj-$(CONFIG_IEEE80211_SOFTMAC) += ieee80211softmac.o
2ieee80211softmac-objs := \
3 ieee80211softmac_io.o \
4 ieee80211softmac_auth.o \
5 ieee80211softmac_module.o \
6 ieee80211softmac_scan.o \
7 ieee80211softmac_wx.o \
8 ieee80211softmac_assoc.o \
9 ieee80211softmac_event.o
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
deleted file mode 100644
index c4d122ddd72c..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ /dev/null
@@ -1,489 +0,0 @@
1/*
2 * This file contains the softmac's association logic.
3 *
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>
9 *
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
27#include "ieee80211softmac_priv.h"
28
29/*
30 * Overview
31 *
32 * Before you can associate, you have to authenticate.
33 *
34 */
35
36/* Sends out an association request to the desired AP */
37static void
38ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
39{
40 unsigned long flags;
41
42 /* Switch to correct channel for this network */
43 mac->set_channel(mac->dev, net->channel);
44
45 /* Send association request */
46 ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0);
47
48 dprintk(KERN_INFO PFX "sent association request!\n");
49
50 spin_lock_irqsave(&mac->lock, flags);
51 mac->associnfo.associated = 0; /* just to make sure */
52
53 /* Set a timer for timeout */
54 /* FIXME: make timeout configurable */
55 if (likely(mac->running))
56 queue_delayed_work(mac->wq, &mac->associnfo.timeout, 5 * HZ);
57 spin_unlock_irqrestore(&mac->lock, flags);
58}
59
60void
61ieee80211softmac_assoc_timeout(struct work_struct *work)
62{
63 struct ieee80211softmac_device *mac =
64 container_of(work, struct ieee80211softmac_device,
65 associnfo.timeout.work);
66 struct ieee80211softmac_network *n;
67
68 mutex_lock(&mac->associnfo.mutex);
69 /* we might race against ieee80211softmac_handle_assoc_response,
70 * so make sure only one of us does something */
71 if (!mac->associnfo.associating)
72 goto out;
73 mac->associnfo.associating = 0;
74 mac->associnfo.bssvalid = 0;
75 mac->associnfo.associated = 0;
76
77 n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
78
79 dprintk(KERN_INFO PFX "assoc request timed out!\n");
80 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
81out:
82 mutex_unlock(&mac->associnfo.mutex);
83}
84
85void
86ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
87{
88 unsigned long flags;
89
90 spin_lock_irqsave(&mac->lock, flags);
91 if (mac->associnfo.associating)
92 cancel_delayed_work(&mac->associnfo.timeout);
93
94 netif_carrier_off(mac->dev);
95
96 mac->associnfo.associated = 0;
97 mac->associnfo.bssvalid = 0;
98 mac->associnfo.associating = 0;
99 ieee80211softmac_init_bss(mac);
100 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
101 spin_unlock_irqrestore(&mac->lock, flags);
102}
103
104/* Sends out a disassociation request to the desired AP */
105void
106ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason)
107{
108 struct ieee80211softmac_network *found;
109
110 if (mac->associnfo.bssvalid && mac->associnfo.associated) {
111 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
112 if (found)
113 ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
114 }
115
116 ieee80211softmac_disassoc(mac);
117}
118
119static inline int
120we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
121{
122 int idx;
123 u8 rate;
124
125 for (idx = 0; idx < (from_len); idx++) {
126 rate = (from)[idx];
127 if (!(rate & IEEE80211_BASIC_RATE_MASK))
128 continue;
129 rate &= ~IEEE80211_BASIC_RATE_MASK;
130 if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
131 return 0;
132 }
133 return 1;
134}
135
136static int
137network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
138{
139 /* we cannot associate to networks whose name we don't know */
140 if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
141 return 0;
142 /* do not associate to a network whose BSSBasicRateSet we cannot support */
143 if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
144 return 0;
145 /* do we really need to check the ex rates? */
146 if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
147 return 0;
148
149 /* assume that users know what they're doing ...
150 * (note we don't let them select a net we're incompatible with) */
151 if (mac->associnfo.bssfixed) {
152 return !memcmp(mac->associnfo.bssid, net->bssid, ETH_ALEN);
153 }
154
155 /* if 'ANY' network requested, take any that doesn't have privacy enabled */
156 if (mac->associnfo.req_essid.len == 0
157 && !(net->capability & WLAN_CAPABILITY_PRIVACY))
158 return 1;
159 if (net->ssid_len != mac->associnfo.req_essid.len)
160 return 0;
161 if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
162 return 1;
163 return 0;
164}
165
166static void
167ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context)
168{
169 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
170 ieee80211softmac_assoc_work(&mac->associnfo.work.work);
171}
172
173static void
174ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context)
175{
176 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
177
178 switch (event_type) {
179 case IEEE80211SOFTMAC_EVENT_AUTHENTICATED:
180 ieee80211softmac_assoc_work(&mac->associnfo.work.work);
181 break;
182 case IEEE80211SOFTMAC_EVENT_AUTH_FAILED:
183 case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT:
184 ieee80211softmac_disassoc(mac);
185 break;
186 }
187}
188
189/* This function is called to handle userspace requests (asynchronously) */
190void
191ieee80211softmac_assoc_work(struct work_struct *work)
192{
193 struct ieee80211softmac_device *mac =
194 container_of(work, struct ieee80211softmac_device,
195 associnfo.work.work);
196 struct ieee80211softmac_network *found = NULL;
197 struct ieee80211_network *net = NULL, *best = NULL;
198 int bssvalid;
199 unsigned long flags;
200
201 mutex_lock(&mac->associnfo.mutex);
202
203 if (!mac->associnfo.associating)
204 goto out;
205
206 /* ieee80211_disassoc might clear this */
207 bssvalid = mac->associnfo.bssvalid;
208
209 /* meh */
210 if (mac->associnfo.associated)
211 ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
212
213 /* try to find the requested network in our list, if we found one already */
214 if (bssvalid || mac->associnfo.bssfixed)
215 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
216
217 /* Search the ieee80211 networks for this network if we didn't find it by bssid,
218 * but only if we've scanned at least once (to get a better list of networks to
219 * select from). If we have not scanned before, the !found logic below will be
220 * invoked and will scan. */
221 if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT))
222 {
223 s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning
224 because it cannot follow the best pointer logic. */
225 spin_lock_irqsave(&mac->ieee->lock, flags);
226 list_for_each_entry(net, &mac->ieee->network_list, list) {
227 /* we're supposed to find the network with
228 * the best signal here, as we're asked to join
229 * any network with a specific ESSID, and many
230 * different ones could have that.
231 *
232 * I'll for now just go with the reported rssi.
233 *
234 * We also should take into account the rateset
235 * here to find the best BSSID to try.
236 */
237 if (network_matches_request(mac, net)) {
238 if (!best) {
239 best = net;
240 rssi = best->stats.rssi;
241 continue;
242 }
243 /* we already had a matching network, so
244 * compare their properties to get the
245 * better of the two ... (see above)
246 */
247 if (rssi < net->stats.rssi) {
248 best = net;
249 rssi = best->stats.rssi;
250 }
251 }
252 }
253 /* if we unlock here, we might get interrupted and the `best'
254 * pointer could go stale */
255 if (best) {
256 found = ieee80211softmac_create_network(mac, best);
257 /* if found is still NULL, then we got -ENOMEM somewhere */
258 if (found)
259 ieee80211softmac_add_network(mac, found);
260 }
261 spin_unlock_irqrestore(&mac->ieee->lock, flags);
262 }
263
264 if (!found) {
265 if (mac->associnfo.scan_retry > 0) {
266 mac->associnfo.scan_retry--;
267
268 /* We know of no such network. Let's scan.
269 * NB: this also happens if we had no memory to copy the network info...
270 * Maybe we can hope to have more memory after scanning finishes ;)
271 */
272 dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
273 ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
274 if (ieee80211softmac_start_scan(mac)) {
275 dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
276 }
277 goto out;
278 } else {
279 mac->associnfo.associating = 0;
280 mac->associnfo.associated = 0;
281
282 dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
283 /* reset the retry counter for the next user request since we
284 * break out and don't reschedule ourselves after this point. */
285 mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
286 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
287 goto out;
288 }
289 }
290
291 /* reset the retry counter for the next user request since we
292 * now found a net and will try to associate to it, but not
293 * schedule this function again. */
294 mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
295 mac->associnfo.bssvalid = 1;
296 memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
297 /* copy the ESSID for displaying it */
298 mac->associnfo.associate_essid.len = found->essid.len;
299 memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
300
301 /* we found a network! authenticate (if necessary) and associate to it. */
302 if (found->authenticating) {
303 dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
304 if(!mac->associnfo.assoc_wait) {
305 mac->associnfo.assoc_wait = 1;
306 ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
307 }
308 goto out;
309 }
310 if (!found->authenticated && !found->authenticating) {
311 /* This relies on the fact that _auth_req only queues the work,
312 * otherwise adding the notification would be racy. */
313 if (!ieee80211softmac_auth_req(mac, found)) {
314 if(!mac->associnfo.assoc_wait) {
315 dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
316 mac->associnfo.assoc_wait = 1;
317 ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
318 }
319 } else {
320 printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
321 mac->associnfo.assoc_wait = 0;
322 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
323 }
324 goto out;
325 }
326 /* finally! now we can start associating */
327 mac->associnfo.assoc_wait = 0;
328 ieee80211softmac_assoc(mac, found);
329
330out:
331 mutex_unlock(&mac->associnfo.mutex);
332}
333
334/* call this to do whatever is necessary when we're associated */
335static void
336ieee80211softmac_associated(struct ieee80211softmac_device *mac,
337 struct ieee80211_assoc_response * resp,
338 struct ieee80211softmac_network *net)
339{
340 u16 cap = le16_to_cpu(resp->capability);
341 u8 erp_value = net->erp_value;
342
343 mac->associnfo.associating = 0;
344 mac->bssinfo.supported_rates = net->supported_rates;
345 ieee80211softmac_recalc_txrates(mac);
346
347 mac->associnfo.associated = 1;
348
349 mac->associnfo.short_preamble_available =
350 (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
351 ieee80211softmac_process_erp(mac, erp_value);
352
353 if (mac->set_bssid_filter)
354 mac->set_bssid_filter(mac->dev, net->bssid);
355 memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
356 netif_carrier_on(mac->dev);
357
358 mac->association_id = le16_to_cpup(&resp->aid);
359}
360
361/* received frame handling functions */
362int
363ieee80211softmac_handle_assoc_response(struct net_device * dev,
364 struct ieee80211_assoc_response * resp,
365 struct ieee80211_network * _ieee80211_network)
366{
367 /* NOTE: the network parameter has to be mostly ignored by
368 * this code because it is the ieee80211's pointer
369 * to the struct, not ours (we made a copy)
370 */
371 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
372 u16 status = le16_to_cpup(&resp->status);
373 struct ieee80211softmac_network *network = NULL;
374 unsigned long flags;
375 DECLARE_MAC_BUF(mac2);
376
377 if (unlikely(!mac->running))
378 return -ENODEV;
379
380 spin_lock_irqsave(&mac->lock, flags);
381
382 if (!mac->associnfo.associating) {
383 /* we race against the timeout function, so make sure
384 * only one of us can do work */
385 spin_unlock_irqrestore(&mac->lock, flags);
386 return 0;
387 }
388 network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
389
390 /* someone sending us things without us knowing him? Ignore. */
391 if (!network) {
392 dprintk(KERN_INFO PFX "Received unrequested assocation response from %s\n",
393 print_mac(mac2, resp->header.addr3));
394 spin_unlock_irqrestore(&mac->lock, flags);
395 return 0;
396 }
397
398 /* now that we know it was for us, we can cancel the timeout */
399 cancel_delayed_work(&mac->associnfo.timeout);
400
401 /* if the association response included an ERP IE, update our saved
402 * copy */
403 if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
404 network->erp_value = _ieee80211_network->erp_value;
405
406 switch (status) {
407 case 0:
408 dprintk(KERN_INFO PFX "associated!\n");
409 ieee80211softmac_associated(mac, resp, network);
410 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
411 break;
412 case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
413 if (!network->auth_desynced_once) {
414 /* there seem to be a few rare cases where our view of
415 * the world is obscured, or buggy APs that don't DEAUTH
416 * us properly. So we handle that, but allow it only once.
417 */
418 printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
419 network->authenticated = 0;
420 /* we don't want to do this more than once ... */
421 network->auth_desynced_once = 1;
422 queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
423 break;
424 }
425 default:
426 dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
427 mac->associnfo.associating = 0;
428 mac->associnfo.bssvalid = 0;
429 mac->associnfo.associated = 0;
430 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
431 }
432
433 spin_unlock_irqrestore(&mac->lock, flags);
434 return 0;
435}
436
437void
438ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
439{
440 unsigned long flags;
441
442 spin_lock_irqsave(&mac->lock, flags);
443 mac->associnfo.associating = 1;
444 queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
445 spin_unlock_irqrestore(&mac->lock, flags);
446}
447
448int
449ieee80211softmac_handle_disassoc(struct net_device * dev,
450 struct ieee80211_disassoc *disassoc)
451{
452 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
453
454 if (unlikely(!mac->running))
455 return -ENODEV;
456
457 if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
458 return 0;
459
460 if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
461 return 0;
462
463 dprintk(KERN_INFO PFX "got disassoc frame\n");
464 ieee80211softmac_disassoc(mac);
465
466 ieee80211softmac_try_reassoc(mac);
467
468 return 0;
469}
470
471int
472ieee80211softmac_handle_reassoc_req(struct net_device * dev,
473 struct ieee80211_reassoc_request * resp)
474{
475 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
476 struct ieee80211softmac_network *network;
477
478 if (unlikely(!mac->running))
479 return -ENODEV;
480
481 network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
482 if (!network) {
483 dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
484 return 0;
485 }
486 queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
487
488 return 0;
489}
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
deleted file mode 100644
index 1a96c2572578..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ /dev/null
@@ -1,413 +0,0 @@
1/*
2 * This file contains the softmac's authentication logic.
3 *
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>
9 *
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
27#include "ieee80211softmac_priv.h"
28
29static void ieee80211softmac_auth_queue(struct work_struct *work);
30
31/* Queues an auth request to the desired AP */
32int
33ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
34 struct ieee80211softmac_network *net)
35{
36 struct ieee80211softmac_auth_queue_item *auth;
37 unsigned long flags;
38 DECLARE_MAC_BUF(mac2);
39
40 if (net->authenticating || net->authenticated)
41 return 0;
42 net->authenticating = 1;
43
44 /* Add the network if it's not already added */
45 ieee80211softmac_add_network(mac, net);
46
47 dprintk(KERN_NOTICE PFX "Queueing Authentication Request to %s\n", print_mac(mac2, net->bssid));
48 /* Queue the auth request */
49 auth = (struct ieee80211softmac_auth_queue_item *)
50 kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
51 if(auth == NULL)
52 return -ENOMEM;
53
54 auth->net = net;
55 auth->mac = mac;
56 auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
57 auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
58 INIT_DELAYED_WORK(&auth->work, ieee80211softmac_auth_queue);
59
60 /* Lock (for list) */
61 spin_lock_irqsave(&mac->lock, flags);
62
63 /* add to list */
64 list_add_tail(&auth->list, &mac->auth_queue);
65 queue_delayed_work(mac->wq, &auth->work, 0);
66 spin_unlock_irqrestore(&mac->lock, flags);
67
68 return 0;
69}
70
71
72/* Sends an auth request to the desired AP and handles timeouts */
73static void
74ieee80211softmac_auth_queue(struct work_struct *work)
75{
76 struct ieee80211softmac_device *mac;
77 struct ieee80211softmac_auth_queue_item *auth;
78 struct ieee80211softmac_network *net;
79 unsigned long flags;
80 DECLARE_MAC_BUF(mac2);
81
82 auth = container_of(work, struct ieee80211softmac_auth_queue_item,
83 work.work);
84 net = auth->net;
85 mac = auth->mac;
86
87 if(auth->retry > 0) {
88 /* Switch to correct channel for this network */
89 mac->set_channel(mac->dev, net->channel);
90
91 /* Lock and set flags */
92 spin_lock_irqsave(&mac->lock, flags);
93 if (unlikely(!mac->running)) {
94 /* Prevent reschedule on workqueue flush */
95 spin_unlock_irqrestore(&mac->lock, flags);
96 return;
97 }
98 net->authenticated = 0;
99 /* add a timeout call so we eventually give up waiting for an auth reply */
100 queue_delayed_work(mac->wq, &auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
101 auth->retry--;
102 spin_unlock_irqrestore(&mac->lock, flags);
103 if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
104 dprintk(KERN_NOTICE PFX "Sending Authentication Request to %s failed (this shouldn't happen, wait for the timeout).\n",
105 print_mac(mac2, net->bssid));
106 else
107 dprintk(KERN_NOTICE PFX "Sent Authentication Request to %s.\n", print_mac(mac2, net->bssid));
108 return;
109 }
110
111 printkl(KERN_WARNING PFX "Authentication timed out with %s\n", print_mac(mac2, net->bssid));
112 /* Remove this item from the queue */
113 spin_lock_irqsave(&mac->lock, flags);
114 net->authenticating = 0;
115 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
116 cancel_delayed_work(&auth->work); /* just to make sure... */
117 list_del(&auth->list);
118 spin_unlock_irqrestore(&mac->lock, flags);
119 /* Free it */
120 kfree(auth);
121}
122
123/* Sends a response to an auth challenge (for shared key auth). */
124static void
125ieee80211softmac_auth_challenge_response(struct work_struct *work)
126{
127 struct ieee80211softmac_auth_queue_item *aq =
128 container_of(work, struct ieee80211softmac_auth_queue_item,
129 work.work);
130
131 /* Send our response */
132 ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
133}
134
135/* Handle the auth response from the AP
136 * This should be registered with ieee80211 as handle_auth
137 */
138int
139ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
140{
141
142 struct list_head *list_ptr;
143 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
144 struct ieee80211softmac_auth_queue_item *aq = NULL;
145 struct ieee80211softmac_network *net = NULL;
146 unsigned long flags;
147 u8 * data;
148 DECLARE_MAC_BUF(mac2);
149
150 if (unlikely(!mac->running))
151 return -ENODEV;
152
153 /* Find correct auth queue item */
154 spin_lock_irqsave(&mac->lock, flags);
155 list_for_each(list_ptr, &mac->auth_queue) {
156 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
157 net = aq->net;
158 if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
159 break;
160 else
161 aq = NULL;
162 }
163 spin_unlock_irqrestore(&mac->lock, flags);
164
165 /* Make sure that we've got an auth queue item for this request */
166 if(aq == NULL)
167 {
168 dprintkl(KERN_DEBUG PFX "Authentication response received from %s but no queue item exists.\n", print_mac(mac2, auth->header.addr2));
169 /* Error #? */
170 return -1;
171 }
172
173 /* Check for out of order authentication */
174 if(!net->authenticating)
175 {
176 dprintkl(KERN_DEBUG PFX "Authentication response received from %s but did not request authentication.\n",print_mac(mac2, auth->header.addr2));
177 return -1;
178 }
179
180 /* Parse the auth packet */
181 switch(le16_to_cpu(auth->algorithm)) {
182 case WLAN_AUTH_OPEN:
183 /* Check the status code of the response */
184
185 switch(le16_to_cpu(auth->status)) {
186 case WLAN_STATUS_SUCCESS:
187 /* Update the status to Authenticated */
188 spin_lock_irqsave(&mac->lock, flags);
189 net->authenticating = 0;
190 net->authenticated = 1;
191 spin_unlock_irqrestore(&mac->lock, flags);
192
193 /* Send event */
194 printkl(KERN_NOTICE PFX "Open Authentication completed with %s\n", print_mac(mac2, net->bssid));
195 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
196 break;
197 default:
198 /* Lock and reset flags */
199 spin_lock_irqsave(&mac->lock, flags);
200 net->authenticated = 0;
201 net->authenticating = 0;
202 spin_unlock_irqrestore(&mac->lock, flags);
203
204 printkl(KERN_NOTICE PFX "Open Authentication with %s failed, error code: %i\n",
205 print_mac(mac2, net->bssid), le16_to_cpup(&auth->status));
206 /* Count the error? */
207 break;
208 }
209 goto free_aq;
210 break;
211 case WLAN_AUTH_SHARED_KEY:
212 /* Figure out where we are in the process */
213 switch(le16_to_cpu(auth->transaction)) {
214 case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
215 /* Check to make sure we have a challenge IE */
216 data = (u8 *)auth->info_element;
217 if (*data++ != MFIE_TYPE_CHALLENGE) {
218 printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
219 break;
220 }
221 /* Save the challenge */
222 spin_lock_irqsave(&mac->lock, flags);
223 net->challenge_len = *data++;
224 if (net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
225 net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
226 kfree(net->challenge);
227 net->challenge = kmemdup(data, net->challenge_len,
228 GFP_ATOMIC);
229 if (net->challenge == NULL) {
230 printkl(KERN_NOTICE PFX "Shared Key "
231 "Authentication failed due to "
232 "memory shortage.\n");
233 spin_unlock_irqrestore(&mac->lock, flags);
234 break;
235 }
236 aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
237
238 /* We reuse the work struct from the auth request here.
239 * It is safe to do so as each one is per-request, and
240 * at this point (dealing with authentication response)
241 * we have obviously already sent the initial auth
242 * request. */
243 cancel_delayed_work(&aq->work);
244 INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response);
245 queue_delayed_work(mac->wq, &aq->work, 0);
246 spin_unlock_irqrestore(&mac->lock, flags);
247 return 0;
248 case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
249 kfree(net->challenge);
250 net->challenge = NULL;
251 net->challenge_len = 0;
252 /* Check the status code of the response */
253 switch(auth->status) {
254 case WLAN_STATUS_SUCCESS:
255 /* Update the status to Authenticated */
256 spin_lock_irqsave(&mac->lock, flags);
257 net->authenticating = 0;
258 net->authenticated = 1;
259 spin_unlock_irqrestore(&mac->lock, flags);
260 printkl(KERN_NOTICE PFX "Shared Key Authentication completed with %s\n",
261 print_mac(mac2, net->bssid));
262 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
263 break;
264 default:
265 printkl(KERN_NOTICE PFX "Shared Key Authentication with %s failed, error code: %i\n",
266 print_mac(mac2, net->bssid), le16_to_cpup(&auth->status));
267 /* Lock and reset flags */
268 spin_lock_irqsave(&mac->lock, flags);
269 net->authenticating = 0;
270 net->authenticated = 0;
271 spin_unlock_irqrestore(&mac->lock, flags);
272 /* Count the error? */
273 break;
274 }
275 goto free_aq;
276 break;
277 default:
278 printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
279 break;
280 }
281 goto free_aq;
282 break;
283 default:
284 /* ERROR */
285 goto free_aq;
286 break;
287 }
288 return 0;
289free_aq:
290 /* Cancel the timeout */
291 spin_lock_irqsave(&mac->lock, flags);
292 cancel_delayed_work(&aq->work);
293 /* Remove this item from the queue */
294 list_del(&aq->list);
295 spin_unlock_irqrestore(&mac->lock, flags);
296
297 /* Free it */
298 kfree(aq);
299 return 0;
300}
301
302/*
303 * Handle deauthorization
304 */
305static void
306ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
307 struct ieee80211softmac_network *net)
308{
309 struct ieee80211softmac_auth_queue_item *aq = NULL;
310 struct list_head *list_ptr;
311 unsigned long flags;
312
313 /* deauthentication implies disassociation */
314 ieee80211softmac_disassoc(mac);
315
316 /* Lock and reset status flags */
317 spin_lock_irqsave(&mac->lock, flags);
318 net->authenticating = 0;
319 net->authenticated = 0;
320
321 /* Find correct auth queue item, if it exists */
322 list_for_each(list_ptr, &mac->auth_queue) {
323 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
324 if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
325 break;
326 else
327 aq = NULL;
328 }
329
330 /* Cancel pending work */
331 if(aq != NULL)
332 /* Not entirely safe? What about running work? */
333 cancel_delayed_work(&aq->work);
334
335 /* Free our network ref */
336 ieee80211softmac_del_network_locked(mac, net);
337 if(net->challenge != NULL)
338 kfree(net->challenge);
339 kfree(net);
340
341 /* can't transmit data right now... */
342 netif_carrier_off(mac->dev);
343 spin_unlock_irqrestore(&mac->lock, flags);
344
345 ieee80211softmac_try_reassoc(mac);
346}
347
348/*
349 * Sends a deauth request to the desired AP
350 */
351int
352ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
353 struct ieee80211softmac_network *net, int reason)
354{
355 int ret;
356
357 /* Make sure the network is authenticated */
358 if (!net->authenticated)
359 {
360 dprintkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
361 /* Error okay? */
362 return -EPERM;
363 }
364
365 /* Send the de-auth packet */
366 if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
367 return ret;
368
369 ieee80211softmac_deauth_from_net(mac, net);
370 return 0;
371}
372
373/*
374 * This should be registered with ieee80211 as handle_deauth
375 */
376int
377ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth)
378{
379
380 struct ieee80211softmac_network *net = NULL;
381 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
382 DECLARE_MAC_BUF(mac2);
383
384 if (unlikely(!mac->running))
385 return -ENODEV;
386
387 if (!deauth) {
388 dprintk("deauth without deauth packet. eek!\n");
389 return 0;
390 }
391
392 net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2);
393
394 if (net == NULL) {
395 dprintkl(KERN_DEBUG PFX "Received deauthentication packet from %s, but that network is unknown.\n",
396 print_mac(mac2, deauth->header.addr2));
397 return 0;
398 }
399
400 /* Make sure the network is authenticated */
401 if(!net->authenticated)
402 {
403 dprintkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
404 /* Error okay? */
405 return -EPERM;
406 }
407
408 ieee80211softmac_deauth_from_net(mac, net);
409
410 /* let's try to re-associate */
411 queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
412 return 0;
413}
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c
deleted file mode 100644
index 8cef05b60f16..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_event.c
+++ /dev/null
@@ -1,189 +0,0 @@
1/*
2 * Event system
3 * Also see comments in public header file and longer explanation below.
4 *
5 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
6 * Joseph Jezak <josejx@gentoo.org>
7 * Larry Finger <Larry.Finger@lwfinger.net>
8 * Danny van Dyk <kugelfang@gentoo.org>
9 * Michael Buesch <mbuesch@freenet.de>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 * The full GNU General Public License is included in this distribution in the
25 * file called COPYING.
26 */
27
28#include "ieee80211softmac_priv.h"
29
30/*
31 * Each event has associated to it
32 * - an event type (see constants in public header)
33 * - an event context (see below)
34 * - the function to be called
35 * - a context (extra parameter to call the function with)
36 * - and the softmac struct
37 *
38 * The event context is private and can only be used from
39 * within this module. Its meaning varies with the event
40 * type:
41 * SCAN_FINISHED,
42 * DISASSOCIATED: NULL
43 * ASSOCIATED,
44 * ASSOCIATE_FAILED,
45 * ASSOCIATE_TIMEOUT,
46 * AUTHENTICATED,
47 * AUTH_FAILED,
48 * AUTH_TIMEOUT: a pointer to the network struct
49 * ...
50 * Code within this module can use the event context to be only
51 * called when the event is true for that specific context
52 * as per above table.
53 * If the event context is NULL, then the notification is always called,
54 * regardless of the event context. The event context is not passed to
55 * the callback, it is assumed that the context suffices.
56 *
57 * You can also use the event context only by setting the event type
58 * to -1 (private use only), in which case you'll be notified
59 * whenever the event context matches.
60 */
61
62static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
63 NULL, /* scan finished */
64 NULL, /* associated */
65 "associating failed",
66 "associating timed out",
67 "authenticated",
68 "authenticating failed",
69 "authenticating timed out",
70 "associating failed because no suitable network was found",
71 NULL, /* disassociated */
72};
73
74
75static void
76ieee80211softmac_notify_callback(struct work_struct *work)
77{
78 struct ieee80211softmac_event *pevent =
79 container_of(work, struct ieee80211softmac_event, work.work);
80 struct ieee80211softmac_event event = *pevent;
81 kfree(pevent);
82
83 event.fun(event.mac->dev, event.event_type, event.context);
84}
85
86int
87ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
88 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
89{
90 struct ieee80211softmac_event *eventptr;
91 unsigned long flags;
92
93 if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
94 return -ENOSYS;
95
96 if (!fun)
97 return -EINVAL;
98
99 eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
100 if (!eventptr)
101 return -ENOMEM;
102
103 eventptr->event_type = event;
104 INIT_DELAYED_WORK(&eventptr->work, ieee80211softmac_notify_callback);
105 eventptr->fun = fun;
106 eventptr->context = context;
107 eventptr->mac = mac;
108 eventptr->event_context = event_context;
109
110 spin_lock_irqsave(&mac->lock, flags);
111 list_add(&eventptr->list, &mac->events);
112 spin_unlock_irqrestore(&mac->lock, flags);
113
114 return 0;
115}
116
117int
118ieee80211softmac_notify_gfp(struct net_device *dev,
119 int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
120{
121 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
122
123 if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
124 return -ENOSYS;
125
126 return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
127}
128EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
129
130/* private -- calling all callbacks that were specified */
131void
132ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
133{
134 struct ieee80211softmac_event *eventptr, *tmp;
135 struct ieee80211softmac_network *network;
136
137 if (event >= 0) {
138 union iwreq_data wrqu;
139 int we_event;
140 char *msg = NULL;
141
142 memset(&wrqu, '\0', sizeof (union iwreq_data));
143
144 switch(event) {
145 case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
146 network = (struct ieee80211softmac_network *)event_ctx;
147 memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN);
148 /* fall through */
149 case IEEE80211SOFTMAC_EVENT_DISASSOCIATED:
150 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
151 we_event = SIOCGIWAP;
152 break;
153 case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
154 we_event = SIOCGIWSCAN;
155 break;
156 default:
157 msg = event_descriptions[event];
158 if (!msg)
159 msg = "SOFTMAC EVENT BUG";
160 wrqu.data.length = strlen(msg);
161 we_event = IWEVCUSTOM;
162 break;
163 }
164 wireless_send_event(mac->dev, we_event, &wrqu, msg);
165 }
166
167 if (!list_empty(&mac->events))
168 list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
169 if ((eventptr->event_type == event || eventptr->event_type == -1)
170 && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
171 list_del(&eventptr->list);
172 /* User may have subscribed to ANY event, so
173 * we tell them which event triggered it. */
174 eventptr->event_type = event;
175 queue_delayed_work(mac->wq, &eventptr->work, 0);
176 }
177 }
178}
179
180void
181ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
182{
183 unsigned long flags;
184
185 spin_lock_irqsave(&mac->lock, flags);
186 ieee80211softmac_call_events_locked(mac, event, event_ctx);
187
188 spin_unlock_irqrestore(&mac->lock, flags);
189}
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
deleted file mode 100644
index 73b4b13fbd8f..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ /dev/null
@@ -1,488 +0,0 @@
1/*
2 * Some parts based on code from net80211
3 * Copyright (c) 2001 Atsushi Onoe
4 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35#include "ieee80211softmac_priv.h"
36
37/* Helper functions for inserting data into the frames */
38
39/*
40 * Adds an ESSID element to the frame
41 *
42 */
43static u8 *
44ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid)
45{
46 if (essid) {
47 *dst++ = MFIE_TYPE_SSID;
48 *dst++ = essid->len;
49 memcpy(dst, essid->data, essid->len);
50 return dst+essid->len;
51 } else {
52 *dst++ = MFIE_TYPE_SSID;
53 *dst++ = 0;
54 return dst;
55 }
56}
57
58/* Adds Supported Rates and if required Extended Rates Information Element
59 * to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */
60static u8 *
61ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r)
62{
63 int cck_len, ofdm_len;
64 *dst++ = MFIE_TYPE_RATES;
65
66 for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++);
67
68 if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN)
69 cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN;
70 *dst++ = cck_len;
71 memcpy(dst, r->rates, cck_len);
72 dst += cck_len;
73
74 if(cck_len < r->count){
75 for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++);
76 if (ofdm_len > 0) {
77 if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN)
78 ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN;
79 *dst++ = MFIE_TYPE_RATES_EX;
80 *dst++ = ofdm_len;
81 memcpy(dst, r->rates + cck_len, ofdm_len);
82 dst += ofdm_len;
83 }
84 }
85 return dst;
86}
87
88/* Allocate a management frame */
89static u8 *
90ieee80211softmac_alloc_mgt(u32 size)
91{
92 u8 * data;
93
94 /* Add the header and FCS to the size */
95 size = size + IEEE80211_3ADDR_LEN;
96 if(size > IEEE80211_DATA_LEN)
97 return NULL;
98 /* Allocate the frame */
99 data = kzalloc(size, GFP_ATOMIC);
100 return data;
101}
102
103/*
104 * Add a 2 Address Header
105 */
106static void
107ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac,
108 struct ieee80211_hdr_2addr *header, u32 type, u8 *dest)
109{
110 /* Fill in the frame control flags */
111 header->frame_ctl = cpu_to_le16(type);
112 /* Control packets always have WEP turned off */
113 if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL)
114 header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0;
115
116 /* Fill in the duration */
117 header->duration_id = 0;
118 /* FIXME: How do I find this?
119 * calculate. But most drivers just fill in 0 (except if it's a station id of course) */
120
121 /* Fill in the Destination Address */
122 if(dest == NULL)
123 memset(header->addr1, 0xFF, ETH_ALEN);
124 else
125 memcpy(header->addr1, dest, ETH_ALEN);
126 /* Fill in the Source Address */
127 memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN);
128
129}
130
131
132/* Add a 3 Address Header */
133static void
134ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
135 struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid)
136{
137 /* This is common with 2addr, so use that instead */
138 ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest);
139
140 /* Fill in the BSS ID */
141 if(bssid == NULL)
142 memset(header->addr3, 0xFF, ETH_ALEN);
143 else
144 memcpy(header->addr3, bssid, ETH_ALEN);
145
146 /* Fill in the sequence # */
147 /* FIXME: I need to add this to the softmac struct
148 * shouldn't the sequence number be in ieee80211? */
149}
150
151static __le16
152ieee80211softmac_capabilities(struct ieee80211softmac_device *mac,
153 struct ieee80211softmac_network *net)
154{
155 __le16 capability = 0;
156
157 /* ESS and IBSS bits are set according to the current mode */
158 switch (mac->ieee->iw_mode) {
159 case IW_MODE_INFRA:
160 capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
161 break;
162 case IW_MODE_ADHOC:
163 capability = cpu_to_le16(WLAN_CAPABILITY_IBSS);
164 break;
165 case IW_MODE_AUTO:
166 capability = cpu_to_le16(net->capabilities &
167 (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS));
168 break;
169 default:
170 /* bleh. we don't ever go to these modes */
171 printk(KERN_ERR PFX "invalid iw_mode!\n");
172 break;
173 }
174
175 /* CF Pollable / CF Poll Request */
176 /* Needs to be implemented, for now, the 0's == not supported */
177
178 /* Privacy Bit */
179 capability |= mac->ieee->sec.level ?
180 cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
181
182 /* Short Preamble */
183 /* Always supported: we probably won't ever be powering devices which
184 * dont support this... */
185 capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
186
187 /* PBCC */
188 /* Not widely used */
189
190 /* Channel Agility */
191 /* Not widely used */
192
193 /* Short Slot */
194 /* Will be implemented later */
195
196 /* DSSS-OFDM */
197 /* Not widely used */
198
199 return capability;
200}
201
202/*****************************************************************************
203 * Create Management packets
204 *****************************************************************************/
205
206/* Creates an association request packet */
207static u32
208ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
209 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
210{
211 u8 *data;
212 (*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt(
213 2 + /* Capability Info */
214 2 + /* Listen Interval */
215 /* SSID IE */
216 1 + 1 + IW_ESSID_MAX_SIZE +
217 /* Rates IE */
218 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
219 /* Extended Rates IE */
220 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN +
221 /* WPA IE if present */
222 mac->wpa.IElen
223 /* Other IE's? Optional?
224 * Yeah, probably need an extra IE parameter -- lots of vendors like to
225 * fill in their own IEs */
226 );
227 if (unlikely((*pkt) == NULL))
228 return 0;
229 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
230
231 /* Fill in the capabilities */
232 (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
233
234 /* Fill in Listen Interval (?) */
235 (*pkt)->listen_interval = cpu_to_le16(10);
236
237 data = (u8 *)(*pkt)->info_element;
238 /* Add SSID */
239 data = ieee80211softmac_add_essid(data, &net->essid);
240 /* Add Rates */
241 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
242 /* Add WPA IE */
243 if (mac->wpa.IElen && mac->wpa.IE) {
244 memcpy(data, mac->wpa.IE, mac->wpa.IElen);
245 data += mac->wpa.IElen;
246 }
247 /* Return the number of used bytes */
248 return (data - (u8*)(*pkt));
249}
250
251/* Create a reassociation request packet */
252static u32
253ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
254 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
255{
256 u8 *data;
257 (*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt(
258 2 + /* Capability Info */
259 2 + /* Listen Interval */
260 ETH_ALEN + /* AP MAC */
261 /* SSID IE */
262 1 + 1 + IW_ESSID_MAX_SIZE +
263 /* Rates IE */
264 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
265 /* Extended Rates IE */
266 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
267 /* Other IE's? */
268 );
269 if (unlikely((*pkt) == NULL))
270 return 0;
271 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
272
273 /* Fill in the capabilities */
274 (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
275
276 /* Fill in Listen Interval (?) */
277 (*pkt)->listen_interval = cpu_to_le16(10);
278 /* Fill in the current AP MAC */
279 memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN);
280
281 data = (u8 *)(*pkt)->info_element;
282 /* Add SSID */
283 data = ieee80211softmac_add_essid(data, &net->essid);
284 /* Add Rates */
285 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
286 /* Return packet size */
287 return (data - (u8 *)(*pkt));
288}
289
290/* Create an authentication packet */
291static u32
292ieee80211softmac_auth(struct ieee80211_auth **pkt,
293 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
294 u16 transaction, u16 status, int *encrypt_mpdu)
295{
296 u8 *data;
297 int auth_mode = mac->ieee->sec.auth_mode;
298 int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY
299 && transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE);
300
301 /* Allocate Packet */
302 (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
303 2 + /* Auth Algorithm */
304 2 + /* Auth Transaction Seq */
305 2 + /* Status Code */
306 /* Challenge Text IE */
307 (is_shared_response ? 1 + 1 + net->challenge_len : 0)
308 );
309 if (unlikely((*pkt) == NULL))
310 return 0;
311 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
312
313 /* Algorithm */
314 (*pkt)->algorithm = cpu_to_le16(auth_mode);
315 /* Transaction */
316 (*pkt)->transaction = cpu_to_le16(transaction);
317 /* Status */
318 (*pkt)->status = cpu_to_le16(status);
319
320 data = (u8 *)(*pkt)->info_element;
321 /* Challenge Text */
322 if (is_shared_response) {
323 *data = MFIE_TYPE_CHALLENGE;
324 data++;
325
326 /* Copy the challenge in */
327 *data = net->challenge_len;
328 data++;
329 memcpy(data, net->challenge, net->challenge_len);
330 data += net->challenge_len;
331
332 /* Make sure this frame gets encrypted with the shared key */
333 *encrypt_mpdu = 1;
334 } else
335 *encrypt_mpdu = 0;
336
337 /* Return the packet size */
338 return (data - (u8 *)(*pkt));
339}
340
341/* Create a disassocation or deauthentication packet */
342static u32
343ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt,
344 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
345 u16 type, u16 reason)
346{
347 /* Allocate Packet */
348 (*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2);
349 if (unlikely((*pkt) == NULL))
350 return 0;
351 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid);
352 /* Reason */
353 (*pkt)->reason = cpu_to_le16(reason);
354 /* Return the packet size */
355 return (2 + IEEE80211_3ADDR_LEN);
356}
357
358/* Create a probe request packet */
359static u32
360ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt,
361 struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid)
362{
363 u8 *data;
364 /* Allocate Packet */
365 (*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt(
366 /* SSID of requested network */
367 1 + 1 + IW_ESSID_MAX_SIZE +
368 /* Rates IE */
369 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
370 /* Extended Rates IE */
371 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
372 );
373 if (unlikely((*pkt) == NULL))
374 return 0;
375 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL);
376
377 data = (u8 *)(*pkt)->info_element;
378 /* Add ESSID (can be NULL) */
379 data = ieee80211softmac_add_essid(data, essid);
380 /* Add Rates */
381 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
382 /* Return packet size */
383 return (data - (u8 *)(*pkt));
384}
385
386/* Create a probe response packet */
387/* FIXME: Not complete */
388static u32
389ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt,
390 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
391{
392 u8 *data;
393 /* Allocate Packet */
394 (*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt(
395 8 + /* Timestamp */
396 2 + /* Beacon Interval */
397 2 + /* Capability Info */
398 /* SSID IE */
399 1 + 1 + IW_ESSID_MAX_SIZE +
400 7 + /* FH Parameter Set */
401 2 + /* DS Parameter Set */
402 8 + /* CF Parameter Set */
403 4 /* IBSS Parameter Set */
404 );
405 if (unlikely((*pkt) == NULL))
406 return 0;
407 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid);
408 data = (u8 *)(*pkt)->info_element;
409
410 /* Return the packet size */
411 return (data - (u8 *)(*pkt));
412}
413
414
415/* Sends a manangement packet
416 * FIXME: document the use of the arg parameter
417 * for _AUTH: (transaction #) | (status << 16)
418 */
419int
420ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
421 void *ptrarg, u32 type, u32 arg)
422{
423 void *pkt = NULL;
424 u32 pkt_size = 0;
425 int encrypt_mpdu = 0;
426
427 switch(type) {
428 case IEEE80211_STYPE_ASSOC_REQ:
429 pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
430 break;
431 case IEEE80211_STYPE_REASSOC_REQ:
432 pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
433 break;
434 case IEEE80211_STYPE_AUTH:
435 pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu);
436 break;
437 case IEEE80211_STYPE_DISASSOC:
438 case IEEE80211_STYPE_DEAUTH:
439 pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF));
440 break;
441 case IEEE80211_STYPE_PROBE_REQ:
442 pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg);
443 break;
444 case IEEE80211_STYPE_PROBE_RESP:
445 pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
446 break;
447 default:
448 printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type);
449 return -EINVAL;
450 };
451
452 if(pkt_size == 0 || pkt == NULL) {
453 printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n");
454 return -ENOMEM;
455 }
456
457 /* Send the packet to the ieee80211 layer for tx */
458 /* we defined softmac->mgmt_xmit for this. Should we keep it
459 * as it is (that means we'd need to wrap this into a txb),
460 * modify the prototype (so it matches this function),
461 * or get rid of it alltogether?
462 * Does this work for you now?
463 */
464 ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt,
465 IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu);
466
467 kfree(pkt);
468 return 0;
469}
470
471/* Beacon handling */
472int ieee80211softmac_handle_beacon(struct net_device *dev,
473 struct ieee80211_beacon *beacon,
474 struct ieee80211_network *network)
475{
476 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
477
478 /* This might race, but we don't really care and it's not worth
479 * adding heavyweight locking in this fastpath.
480 */
481 if (mac->associnfo.associated) {
482 if (memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
483 ieee80211softmac_process_erp(mac, network->erp_value);
484 }
485
486 return 0;
487}
488
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
deleted file mode 100644
index 07505ca859af..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ /dev/null
@@ -1,568 +0,0 @@
1/*
2 * Contains some basic softmac functions along with module registration code etc.
3 *
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>
9 *
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
27#include "ieee80211softmac_priv.h"
28#include <linux/sort.h>
29#include <linux/etherdevice.h>
30
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(*softmac) + sizeof_priv);
37 if (!dev)
38 return NULL;
39 softmac = ieee80211_priv(dev);
40 softmac->wq = create_freezeable_workqueue("softmac");
41 if (!softmac->wq) {
42 free_ieee80211(dev);
43 return NULL;
44 }
45
46 softmac->dev = dev;
47 softmac->ieee = netdev_priv(dev);
48 spin_lock_init(&softmac->lock);
49
50 softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
51 softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
52 softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
53 softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
54 softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
55 softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
56 softmac->scaninfo = NULL;
57
58 softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
59
60 /* TODO: initialise all the other callbacks in the ieee struct
61 * (once they're written)
62 */
63
64 INIT_LIST_HEAD(&softmac->auth_queue);
65 INIT_LIST_HEAD(&softmac->network_list);
66 INIT_LIST_HEAD(&softmac->events);
67
68 mutex_init(&softmac->associnfo.mutex);
69 INIT_DELAYED_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work);
70 INIT_DELAYED_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout);
71 softmac->start_scan = ieee80211softmac_start_scan_implementation;
72 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
73 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
74
75 /* to start with, we can't send anything ... */
76 netif_carrier_off(dev);
77
78 return dev;
79}
80EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
81
82/* Clears the pending work queue items, stops all scans, etc. */
83void
84ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
85{
86 unsigned long flags;
87 struct ieee80211softmac_event *eventptr, *eventtmp;
88 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
89 struct ieee80211softmac_network *netptr, *nettmp;
90
91 ieee80211softmac_stop_scan(sm);
92 ieee80211softmac_wait_for_scan(sm);
93
94 spin_lock_irqsave(&sm->lock, flags);
95 sm->running = 0;
96
97 /* Free all pending assoc work items */
98 cancel_delayed_work(&sm->associnfo.work);
99
100 /* Free all pending scan work items */
101 if(sm->scaninfo != NULL)
102 cancel_delayed_work(&sm->scaninfo->softmac_scan);
103
104 /* Free all pending auth work items */
105 list_for_each_entry(authptr, &sm->auth_queue, list)
106 cancel_delayed_work(&authptr->work);
107
108 /* delete all pending event calls and work items */
109 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
110 cancel_delayed_work(&eventptr->work);
111
112 spin_unlock_irqrestore(&sm->lock, flags);
113 flush_workqueue(sm->wq);
114
115 /* now we should be save and no longer need locking... */
116 spin_lock_irqsave(&sm->lock, flags);
117 /* Free all pending auth work items */
118 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
119 list_del(&authptr->list);
120 kfree(authptr);
121 }
122
123 /* delete all pending event calls and work items */
124 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
125 list_del(&eventptr->list);
126 kfree(eventptr);
127 }
128
129 /* Free all networks */
130 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
131 ieee80211softmac_del_network_locked(sm, netptr);
132 if(netptr->challenge != NULL)
133 kfree(netptr->challenge);
134 kfree(netptr);
135 }
136
137 spin_unlock_irqrestore(&sm->lock, flags);
138}
139EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
140
141void free_ieee80211softmac(struct net_device *dev)
142{
143 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
144 ieee80211softmac_clear_pending_work(sm);
145 kfree(sm->scaninfo);
146 kfree(sm->wpa.IE);
147 destroy_workqueue(sm->wq);
148 free_ieee80211(dev);
149}
150EXPORT_SYMBOL_GPL(free_ieee80211softmac);
151
152static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
153{
154 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
155 /* I took out the sorting check, we're seperating by modulation now. */
156 if (ri->count)
157 return;
158 /* otherwise assume we hav'em all! */
159 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
160 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
161 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
162 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
163 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
164 }
165 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
166 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
167 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
168 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
169 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
170 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
171 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
172 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
173 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
174 }
175}
176
177int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
178{
179 int search;
180 u8 search_rate;
181
182 for (search = 0; search < ri->count; search++) {
183 search_rate = ri->rates[search];
184 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
185 if (rate == search_rate)
186 return 1;
187 }
188
189 return 0;
190}
191
192u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
193 struct ieee80211softmac_ratesinfo *ri, int basic_only)
194{
195 u8 user_rate = mac->txrates.user_rate;
196 int i;
197
198 if (ri->count == 0)
199 return IEEE80211_CCK_RATE_1MB;
200
201 for (i = ri->count - 1; i >= 0; i--) {
202 u8 rate = ri->rates[i];
203 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
204 continue;
205 rate &= ~IEEE80211_BASIC_RATE_MASK;
206 if (rate > user_rate)
207 continue;
208 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
209 return rate;
210 }
211
212 /* If we haven't found a suitable rate by now, just trust the user */
213 return user_rate;
214}
215EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
216
217void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
218 u8 erp_value)
219{
220 int use_protection;
221 int short_preamble;
222 u32 changes = 0;
223
224 /* Barker preamble mode */
225 short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
226 && mac->associnfo.short_preamble_available) ? 1 : 0;
227
228 /* Protection needed? */
229 use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
230
231 if (mac->bssinfo.short_preamble != short_preamble) {
232 changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
233 mac->bssinfo.short_preamble = short_preamble;
234 }
235
236 if (mac->bssinfo.use_protection != use_protection) {
237 changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
238 mac->bssinfo.use_protection = use_protection;
239 }
240
241 if (mac->bssinfo_change && changes)
242 mac->bssinfo_change(mac->dev, changes);
243}
244
245void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
246{
247 struct ieee80211softmac_txrates *txrates = &mac->txrates;
248 u32 change = 0;
249
250 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
251 txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
252
253 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
254 txrates->default_fallback = lower_rate(mac, txrates->default_rate);
255
256 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
257 txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
258
259 if (mac->txrates_change)
260 mac->txrates_change(mac->dev, change);
261
262}
263
264void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
265{
266 struct ieee80211_device *ieee = mac->ieee;
267 u32 change = 0;
268 struct ieee80211softmac_txrates *txrates = &mac->txrates;
269 struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
270
271 /* TODO: We need some kind of state machine to lower the default rates
272 * if we loose too many packets.
273 */
274 /* Change the default txrate to the highest possible value.
275 * The txrate machine will lower it, if it is too high.
276 */
277 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
278 txrates->user_rate = IEEE80211_OFDM_RATE_24MB;
279 else
280 txrates->user_rate = IEEE80211_CCK_RATE_11MB;
281
282 txrates->default_rate = IEEE80211_CCK_RATE_1MB;
283 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
284
285 txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
286 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
287
288 txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
289 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
290
291 txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
292 change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
293
294 if (mac->txrates_change)
295 mac->txrates_change(mac->dev, change);
296
297 change = 0;
298
299 bssinfo->supported_rates.count = 0;
300 memset(bssinfo->supported_rates.rates, 0,
301 sizeof(bssinfo->supported_rates.rates));
302 change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
303
304 bssinfo->short_preamble = 0;
305 change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
306
307 bssinfo->use_protection = 0;
308 change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
309
310 if (mac->bssinfo_change)
311 mac->bssinfo_change(mac->dev, change);
312
313 mac->running = 1;
314}
315
316void ieee80211softmac_start(struct net_device *dev)
317{
318 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
319
320 ieee80211softmac_start_check_rates(mac);
321 ieee80211softmac_init_bss(mac);
322}
323EXPORT_SYMBOL_GPL(ieee80211softmac_start);
324
325void ieee80211softmac_stop(struct net_device *dev)
326{
327 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
328
329 ieee80211softmac_clear_pending_work(mac);
330}
331EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
332
333void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
334{
335 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
336 unsigned long flags;
337
338 spin_lock_irqsave(&mac->lock, flags);
339 memcpy(mac->ratesinfo.rates, rates, count);
340 mac->ratesinfo.count = count;
341 spin_unlock_irqrestore(&mac->lock, flags);
342}
343EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
344
345static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
346{
347 int i;
348 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
349
350 for (i=0; i<ri->count-1; i++) {
351 if (ri->rates[i] == rate)
352 return ri->rates[i+1];
353 }
354 /* I guess we can't go any higher... */
355 return ri->rates[ri->count];
356}
357
358u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
359{
360 int i;
361 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
362
363 for (i=delta; i<ri->count; i++) {
364 if (ri->rates[i] == rate)
365 return ri->rates[i-delta];
366 }
367 /* I guess we can't go any lower... */
368 return ri->rates[0];
369}
370
371static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
372 int amount)
373{
374 u8 default_rate = mac->txrates.default_rate;
375 u8 default_fallback = mac->txrates.default_fallback;
376 u32 changes = 0;
377
378 //TODO: This is highly experimental code.
379 // Maybe the dynamic rate selection does not work
380 // and it has to be removed again.
381
382printk("badness %d\n", mac->txrate_badness);
383 mac->txrate_badness += amount;
384 if (mac->txrate_badness <= -1000) {
385 /* Very small badness. Try a faster bitrate. */
386 default_rate = raise_rate(mac, default_rate);
387 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
388 default_fallback = get_fallback_rate(mac, default_rate);
389 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
390 mac->txrate_badness = 0;
391printk("Bitrate raised to %u\n", default_rate);
392 } else if (mac->txrate_badness >= 10000) {
393 /* Very high badness. Try a slower bitrate. */
394 default_rate = lower_rate(mac, default_rate);
395 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
396 default_fallback = get_fallback_rate(mac, default_rate);
397 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
398 mac->txrate_badness = 0;
399printk("Bitrate lowered to %u\n", default_rate);
400 }
401
402 mac->txrates.default_rate = default_rate;
403 mac->txrates.default_fallback = default_fallback;
404
405 if (changes && mac->txrates_change)
406 mac->txrates_change(mac->dev, changes);
407}
408
409void ieee80211softmac_fragment_lost(struct net_device *dev,
410 u16 wl_seq)
411{
412 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
413 unsigned long flags;
414
415 spin_lock_irqsave(&mac->lock, flags);
416 ieee80211softmac_add_txrates_badness(mac, 1000);
417 //TODO
418
419 spin_unlock_irqrestore(&mac->lock, flags);
420}
421EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
422
423static int rate_cmp(const void *a_, const void *b_) {
424 u8 *a, *b;
425 a = (u8*)a_;
426 b = (u8*)b_;
427 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
428}
429
430/* Allocate a softmac network struct and fill it from a network */
431struct ieee80211softmac_network *
432ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
433 struct ieee80211_network *net)
434{
435 struct ieee80211softmac_network *softnet;
436 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
437 if(softnet == NULL)
438 return NULL;
439 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
440 softnet->channel = net->channel;
441 softnet->essid.len = net->ssid_len;
442 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
443
444 /* copy rates over */
445 softnet->supported_rates.count = net->rates_len;
446 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
447 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
448 softnet->supported_rates.count += net->rates_ex_len;
449 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
450
451 /* we save the ERP value because it is needed at association time, and
452 * many AP's do not include an ERP IE in the association response. */
453 softnet->erp_value = net->erp_value;
454
455 softnet->capabilities = net->capability;
456 return softnet;
457}
458
459
460/* Add a network to the list, while locked */
461void
462ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
463 struct ieee80211softmac_network *add_net)
464{
465 struct ieee80211softmac_network *softmac_net;
466
467 list_for_each_entry(softmac_net, &mac->network_list, list) {
468 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
469 return;
470 }
471 list_add(&(add_net->list), &mac->network_list);
472}
473
474/* Add a network to the list, with locking */
475void
476ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
477 struct ieee80211softmac_network *add_net)
478{
479 unsigned long flags;
480 spin_lock_irqsave(&mac->lock, flags);
481 ieee80211softmac_add_network_locked(mac, add_net);
482 spin_unlock_irqrestore(&mac->lock, flags);
483}
484
485
486/* Delete a network from the list, while locked*/
487void
488ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
489 struct ieee80211softmac_network *del_net)
490{
491 list_del(&(del_net->list));
492}
493
494/* Delete a network from the list with locking */
495void
496ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
497 struct ieee80211softmac_network *del_net)
498{
499 unsigned long flags;
500 spin_lock_irqsave(&mac->lock, flags);
501 ieee80211softmac_del_network_locked(mac, del_net);
502 spin_unlock_irqrestore(&mac->lock, flags);
503}
504
505/* Get a network from the list by MAC while locked */
506struct ieee80211softmac_network *
507ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
508 u8 *bssid)
509{
510 struct ieee80211softmac_network *softmac_net;
511
512 list_for_each_entry(softmac_net, &mac->network_list, list) {
513 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
514 return softmac_net;
515 }
516 return NULL;
517}
518
519/* Get a network from the list by BSSID with locking */
520struct ieee80211softmac_network *
521ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
522 u8 *bssid)
523{
524 unsigned long flags;
525 struct ieee80211softmac_network *softmac_net;
526
527 spin_lock_irqsave(&mac->lock, flags);
528 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
529 spin_unlock_irqrestore(&mac->lock, flags);
530 return softmac_net;
531}
532
533/* Get a network from the list by ESSID while locked */
534struct ieee80211softmac_network *
535ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
536 struct ieee80211softmac_essid *essid)
537{
538 struct ieee80211softmac_network *softmac_net;
539
540 list_for_each_entry(softmac_net, &mac->network_list, list) {
541 if (softmac_net->essid.len == essid->len &&
542 !memcmp(softmac_net->essid.data, essid->data, essid->len))
543 return softmac_net;
544 }
545 return NULL;
546}
547
548/* Get a network from the list by ESSID with locking */
549struct ieee80211softmac_network *
550ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
551 struct ieee80211softmac_essid *essid)
552{
553 unsigned long flags;
554 struct ieee80211softmac_network *softmac_net = NULL;
555
556 spin_lock_irqsave(&mac->lock, flags);
557 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
558 spin_unlock_irqrestore(&mac->lock, flags);
559 return softmac_net;
560}
561
562MODULE_LICENSE("GPL");
563MODULE_AUTHOR("Johannes Berg");
564MODULE_AUTHOR("Joseph Jezak");
565MODULE_AUTHOR("Larry Finger");
566MODULE_AUTHOR("Danny van Dyk");
567MODULE_AUTHOR("Michael Buesch");
568MODULE_DESCRIPTION("802.11 software MAC");
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
deleted file mode 100644
index c43b189634df..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ /dev/null
@@ -1,244 +0,0 @@
1/*
2 * Internal softmac API definitions.
3 *
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>
9 *
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
27#ifndef IEEE80211SOFTMAC_PRIV_H_
28#define IEEE80211SOFTMAC_PRIV_H_
29
30#include <net/ieee80211softmac.h>
31#include <net/ieee80211softmac_wx.h>
32#include <linux/kernel.h>
33#include <linux/stringify.h>
34
35
36#define PFX "SoftMAC: "
37
38#ifdef assert
39# undef assert
40#endif
41#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
42#define assert(expr) \
43 do { \
44 if (unlikely(!(expr))) { \
45 printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \
46 __FILE__, __LINE__, __FUNCTION__); \
47 } \
48 } while (0)
49#else
50#define assert(expr) do {} while (0)
51#endif
52
53/* rate limited printk(). */
54#ifdef printkl
55# undef printkl
56#endif
57#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0)
58/* rate limited printk() for debugging */
59#ifdef dprintkl
60# undef dprintkl
61#endif
62#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
63# define dprintkl printkl
64#else
65# define dprintkl(f, x...) do { /* nothing */ } while (0)
66#endif
67
68/* debugging printk() */
69#ifdef dprintk
70# undef dprintk
71#endif
72#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
73# define dprintk(f, x...) do { printk(f ,##x); } while (0)
74#else
75# define dprintk(f, x...) do { /* nothing */ } while (0)
76#endif
77
78/* private definitions and prototypes */
79
80/*** prototypes from _scan.c */
81void ieee80211softmac_scan(struct work_struct *work);
82/* for internal use if scanning is needed */
83int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
84void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
85void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac);
86
87/* for use by _module.c to assign to the callbacks */
88int ieee80211softmac_start_scan_implementation(struct net_device *dev);
89void ieee80211softmac_stop_scan_implementation(struct net_device *dev);
90void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev);
91
92/*** Network prototypes from _module.c */
93struct ieee80211softmac_network * ieee80211softmac_create_network(
94 struct ieee80211softmac_device *mac, struct ieee80211_network *net);
95void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
96 struct ieee80211softmac_network *net);
97void ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
98 struct ieee80211softmac_network *net);
99void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
100 struct ieee80211softmac_network *net);
101void ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
102 struct ieee80211softmac_network *net);
103struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked(
104 struct ieee80211softmac_device *mac, u8 *ea);
105struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid(
106 struct ieee80211softmac_device *mac, u8 *ea);
107struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked(
108 struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
109struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid(
110 struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
111struct ieee80211softmac_network *
112ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
113 struct ieee80211softmac_essid *essid);
114struct ieee80211softmac_network *
115ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
116 struct ieee80211softmac_essid *essid);
117
118/* Rates related */
119void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
120 u8 erp_value);
121int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
122u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
123void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
124void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
125static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
126 return ieee80211softmac_lower_rate_delta(mac, rate, 1);
127}
128
129static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
130{
131 return ieee80211softmac_lower_rate_delta(mac, rate, 2);
132}
133
134
135/*** prototypes from _io.c */
136int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
137 void* ptrarg, u32 type, u32 arg);
138int ieee80211softmac_handle_beacon(struct net_device *dev,
139 struct ieee80211_beacon *beacon,
140 struct ieee80211_network *network);
141
142/*** prototypes from _auth.c */
143/* do these have to go into the public header? */
144int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
145int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
146
147/* for use by _module.c to assign to the callbacks */
148int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
149int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth);
150
151/*** prototypes from _assoc.c */
152void ieee80211softmac_assoc_work(struct work_struct *work);
153int ieee80211softmac_handle_assoc_response(struct net_device * dev,
154 struct ieee80211_assoc_response * resp,
155 struct ieee80211_network * network);
156int ieee80211softmac_handle_disassoc(struct net_device * dev,
157 struct ieee80211_disassoc * disassoc);
158int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
159 struct ieee80211_reassoc_request * reassoc);
160void ieee80211softmac_assoc_timeout(struct work_struct *work);
161void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason);
162void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac);
163
164/* some helper functions */
165static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
166{
167 return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
168 (sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
169 (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
170}
171
172static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
173{
174 return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
175 (sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
176 (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
177 ) || ieee80211softmac_scan_handlers_check_self(sm);
178}
179
180#define IEEE80211SOFTMAC_PROBE_DELAY HZ/50
181#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ)
182
183struct ieee80211softmac_network {
184 struct list_head list; /* List */
185 /* Network information copied from ieee80211_network */
186 u8 bssid[ETH_ALEN];
187 u8 channel;
188 struct ieee80211softmac_essid essid;
189
190 struct ieee80211softmac_ratesinfo supported_rates;
191
192 /* SoftMAC specific */
193 u16 authenticating:1, /* Status Flags */
194 authenticated:1,
195 auth_desynced_once:1;
196
197 u8 erp_value; /* Saved ERP value */
198 u16 capabilities; /* Capabilities bitfield */
199 u8 challenge_len; /* Auth Challenge length */
200 char *challenge; /* Challenge Text */
201};
202
203/* structure used to keep track of networks we're auth'ing to */
204struct ieee80211softmac_auth_queue_item {
205 struct list_head list; /* List head */
206 struct ieee80211softmac_network *net; /* Network to auth */
207 struct ieee80211softmac_device *mac; /* SoftMAC device */
208 u8 retry; /* Retry limit */
209 u8 state; /* Auth State */
210 struct delayed_work work; /* Work queue */
211};
212
213/* scanning information */
214struct ieee80211softmac_scaninfo {
215 u8 current_channel_idx,
216 number_channels;
217 struct ieee80211_channel *channels;
218 u8 started:1,
219 stop:1;
220 u8 skip_flags;
221 struct completion finished;
222 struct delayed_work softmac_scan;
223 struct ieee80211softmac_device *mac;
224};
225
226/* private event struct */
227struct ieee80211softmac_event {
228 struct list_head list;
229 int event_type;
230 void *event_context;
231 struct delayed_work work;
232 notify_function_ptr fun;
233 void *context;
234 struct ieee80211softmac_device *mac;
235};
236
237void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
238void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
239int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
240 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
241
242void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac);
243
244#endif /* IEEE80211SOFTMAC_PRIV_H_ */
diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c
deleted file mode 100644
index bfab8d7db88f..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_scan.c
+++ /dev/null
@@ -1,254 +0,0 @@
1/*
2 * Scanning routines.
3 *
4 * These are not exported because they're assigned to the function pointers.
5 *
6 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
7 * Joseph Jezak <josejx@gentoo.org>
8 * Larry Finger <Larry.Finger@lwfinger.net>
9 * Danny van Dyk <kugelfang@gentoo.org>
10 * Michael Buesch <mbuesch@freenet.de>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 * The full GNU General Public License is included in this distribution in the
26 * file called COPYING.
27 */
28
29#include <linux/completion.h>
30#include "ieee80211softmac_priv.h"
31
32/* internal, use to trigger scanning if needed.
33 * Returns -EBUSY if already scanning,
34 * result of start_scan otherwise */
35int
36ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
37{
38 unsigned long flags;
39 int ret;
40
41 spin_lock_irqsave(&sm->lock, flags);
42 if (sm->scanning)
43 {
44 spin_unlock_irqrestore(&sm->lock, flags);
45 return -EINPROGRESS;
46 }
47 sm->scanning = 1;
48 spin_unlock_irqrestore(&sm->lock, flags);
49
50 ret = sm->start_scan(sm->dev);
51 if (ret) {
52 spin_lock_irqsave(&sm->lock, flags);
53 sm->scanning = 0;
54 spin_unlock_irqrestore(&sm->lock, flags);
55 }
56 return ret;
57}
58
59void
60ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm)
61{
62 unsigned long flags;
63
64 spin_lock_irqsave(&sm->lock, flags);
65
66 if (!sm->scanning) {
67 spin_unlock_irqrestore(&sm->lock, flags);
68 return;
69 }
70
71 spin_unlock_irqrestore(&sm->lock, flags);
72 sm->stop_scan(sm->dev);
73}
74
75void
76ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm)
77{
78 unsigned long flags;
79
80 spin_lock_irqsave(&sm->lock, flags);
81
82 if (!sm->scanning) {
83 spin_unlock_irqrestore(&sm->lock, flags);
84 return;
85 }
86
87 spin_unlock_irqrestore(&sm->lock, flags);
88 sm->wait_for_scan(sm->dev);
89}
90
91
92/* internal scanning implementation follows */
93void ieee80211softmac_scan(struct work_struct *work)
94{
95 int invalid_channel;
96 u8 current_channel_idx;
97 struct ieee80211softmac_scaninfo *si =
98 container_of(work, struct ieee80211softmac_scaninfo,
99 softmac_scan.work);
100 struct ieee80211softmac_device *sm = si->mac;
101 unsigned long flags;
102
103 while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
104 current_channel_idx = si->current_channel_idx;
105 si->current_channel_idx++; /* go to the next channel */
106
107 invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
108
109 if (!invalid_channel) {
110 sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
111 // FIXME make this user configurable (active/passive)
112 if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
113 printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
114
115 /* also send directed management frame for the network we're looking for */
116 // TODO: is this if correct, or should we do this only if scanning from assoc request?
117 if (sm->associnfo.req_essid.len)
118 ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
119
120 spin_lock_irqsave(&sm->lock, flags);
121 if (unlikely(!sm->running)) {
122 /* Prevent reschedule on workqueue flush */
123 spin_unlock_irqrestore(&sm->lock, flags);
124 break;
125 }
126 queue_delayed_work(sm->wq, &si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
127 spin_unlock_irqrestore(&sm->lock, flags);
128 return;
129 } else {
130 dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
131 }
132 }
133
134 spin_lock_irqsave(&sm->lock, flags);
135 cancel_delayed_work(&si->softmac_scan);
136 si->started = 0;
137 spin_unlock_irqrestore(&sm->lock, flags);
138
139 dprintk(PFX "Scanning finished: scanned %d channels starting with channel %d\n",
140 sm->scaninfo->number_channels, sm->scaninfo->channels[0].channel);
141 ieee80211softmac_scan_finished(sm);
142 complete_all(&sm->scaninfo->finished);
143}
144
145static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
146{
147 /* ugh. can we call this without having the spinlock held? */
148 struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
149 if (unlikely(!info))
150 return NULL;
151 INIT_DELAYED_WORK(&info->softmac_scan, ieee80211softmac_scan);
152 info->mac = mac;
153 init_completion(&info->finished);
154 return info;
155}
156
157int ieee80211softmac_start_scan_implementation(struct net_device *dev)
158{
159 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
160 unsigned long flags;
161
162 if (!(dev->flags & IFF_UP))
163 return -ENODEV;
164
165 assert(ieee80211softmac_scan_handlers_check_self(sm));
166 if (!ieee80211softmac_scan_handlers_check_self(sm))
167 return -EINVAL;
168
169 spin_lock_irqsave(&sm->lock, flags);
170 /* it looks like we need to hold the lock here
171 * to make sure we don't allocate two of these... */
172 if (unlikely(!sm->scaninfo))
173 sm->scaninfo = allocate_scaninfo(sm);
174 if (unlikely(!sm->scaninfo)) {
175 spin_unlock_irqrestore(&sm->lock, flags);
176 return -ENOMEM;
177 }
178
179 sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
180 if (0 /* not scanning in IEEE802.11b */)//TODO
181 sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
182 if (0 /* IEEE802.11a */) {//TODO
183 sm->scaninfo->channels = sm->ieee->geo.a;
184 sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
185 } else {
186 sm->scaninfo->channels = sm->ieee->geo.bg;
187 sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
188 }
189 sm->scaninfo->current_channel_idx = 0;
190 sm->scaninfo->started = 1;
191 sm->scaninfo->stop = 0;
192 INIT_COMPLETION(sm->scaninfo->finished);
193 queue_delayed_work(sm->wq, &sm->scaninfo->softmac_scan, 0);
194 spin_unlock_irqrestore(&sm->lock, flags);
195 return 0;
196}
197
198void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
199{
200 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
201 unsigned long flags;
202
203 assert(ieee80211softmac_scan_handlers_check_self(sm));
204 if (!ieee80211softmac_scan_handlers_check_self(sm))
205 return;
206
207 spin_lock_irqsave(&sm->lock, flags);
208 assert(sm->scaninfo != NULL);
209 if (sm->scaninfo) {
210 if (sm->scaninfo->started)
211 sm->scaninfo->stop = 1;
212 else
213 complete_all(&sm->scaninfo->finished);
214 }
215 spin_unlock_irqrestore(&sm->lock, flags);
216}
217
218void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
219{
220 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
221 unsigned long flags;
222
223 assert(ieee80211softmac_scan_handlers_check_self(sm));
224 if (!ieee80211softmac_scan_handlers_check_self(sm))
225 return;
226
227 spin_lock_irqsave(&sm->lock, flags);
228 if (!sm->scaninfo->started) {
229 spin_unlock_irqrestore(&sm->lock, flags);
230 return;
231 }
232 spin_unlock_irqrestore(&sm->lock, flags);
233 wait_for_completion(&sm->scaninfo->finished);
234}
235
236/* this is what drivers (that do scanning) call when they're done */
237void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
238{
239 unsigned long flags;
240
241 spin_lock_irqsave(&sm->lock, flags);
242 sm->scanning = 0;
243 spin_unlock_irqrestore(&sm->lock, flags);
244
245 if (sm->associnfo.bssvalid) {
246 struct ieee80211softmac_network *net;
247
248 net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
249 if (net)
250 sm->set_channel(sm->dev, net->channel);
251 }
252 ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
253}
254EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
deleted file mode 100644
index e01b59aedc54..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ /dev/null
@@ -1,508 +0,0 @@
1/*
2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
3 *
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>
9 *
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
27#include "ieee80211softmac_priv.h"
28
29#include <net/iw_handler.h>
30/* for is_broadcast_ether_addr and is_zero_ether_addr */
31#include <linux/etherdevice.h>
32
33int
34ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
35 struct iw_request_info *info,
36 union iwreq_data *data,
37 char *extra)
38{
39 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
40 return ieee80211softmac_start_scan(sm);
41}
42EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
43
44
45/* if we're still scanning, return -EAGAIN so that userspace tools
46 * can get the complete scan results, otherwise return 0. */
47int
48ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
49 struct iw_request_info *info,
50 union iwreq_data *data,
51 char *extra)
52{
53 unsigned long flags;
54 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
55
56 spin_lock_irqsave(&sm->lock, flags);
57 if (sm->scanning) {
58 spin_unlock_irqrestore(&sm->lock, flags);
59 return -EAGAIN;
60 }
61 spin_unlock_irqrestore(&sm->lock, flags);
62 return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
63}
64EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
65
66int
67ieee80211softmac_wx_set_essid(struct net_device *net_dev,
68 struct iw_request_info *info,
69 union iwreq_data *data,
70 char *extra)
71{
72 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
73 struct ieee80211softmac_auth_queue_item *authptr;
74 int length = 0;
75 DECLARE_MAC_BUF(mac);
76
77check_assoc_again:
78 mutex_lock(&sm->associnfo.mutex);
79 if((sm->associnfo.associating || sm->associnfo.associated) &&
80 (data->essid.flags && data->essid.length)) {
81 dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
82 /* Cancel assoc work */
83 cancel_delayed_work(&sm->associnfo.work);
84 /* We don't have to do this, but it's a little cleaner */
85 list_for_each_entry(authptr, &sm->auth_queue, list)
86 cancel_delayed_work(&authptr->work);
87 sm->associnfo.bssvalid = 0;
88 sm->associnfo.bssfixed = 0;
89 sm->associnfo.associating = 0;
90 sm->associnfo.associated = 0;
91 /* We must unlock to avoid deadlocks with the assoc workqueue
92 * on the associnfo.mutex */
93 mutex_unlock(&sm->associnfo.mutex);
94 flush_workqueue(sm->wq);
95 /* Avoid race! Check assoc status again. Maybe someone started an
96 * association while we flushed. */
97 goto check_assoc_again;
98 }
99
100 sm->associnfo.static_essid = 0;
101 sm->associnfo.assoc_wait = 0;
102
103 if (data->essid.flags && data->essid.length) {
104 length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
105 if (length) {
106 memcpy(sm->associnfo.req_essid.data, extra, length);
107 sm->associnfo.static_essid = 1;
108 }
109 }
110
111 /* set our requested ESSID length.
112 * If applicable, we have already copied the data in */
113 sm->associnfo.req_essid.len = length;
114
115 sm->associnfo.associating = 1;
116 /* queue lower level code to do work (if necessary) */
117 queue_delayed_work(sm->wq, &sm->associnfo.work, 0);
118
119 mutex_unlock(&sm->associnfo.mutex);
120
121 return 0;
122}
123EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
124
125int
126ieee80211softmac_wx_get_essid(struct net_device *net_dev,
127 struct iw_request_info *info,
128 union iwreq_data *data,
129 char *extra)
130{
131 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
132
133 mutex_lock(&sm->associnfo.mutex);
134 /* If all fails, return ANY (empty) */
135 data->essid.length = 0;
136 data->essid.flags = 0; /* active */
137
138 /* If we have a statically configured ESSID then return it */
139 if (sm->associnfo.static_essid) {
140 data->essid.length = sm->associnfo.req_essid.len;
141 data->essid.flags = 1; /* active */
142 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
143 dprintk(KERN_INFO PFX "Getting essid from req_essid\n");
144 } else if (sm->associnfo.associated || sm->associnfo.associating) {
145 /* If we're associating/associated, return that */
146 data->essid.length = sm->associnfo.associate_essid.len;
147 data->essid.flags = 1; /* active */
148 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
149 dprintk(KERN_INFO PFX "Getting essid from associate_essid\n");
150 }
151 mutex_unlock(&sm->associnfo.mutex);
152
153 return 0;
154}
155EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
156
157int
158ieee80211softmac_wx_set_rate(struct net_device *net_dev,
159 struct iw_request_info *info,
160 union iwreq_data *data,
161 char *extra)
162{
163 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
164 struct ieee80211_device *ieee = mac->ieee;
165 unsigned long flags;
166 s32 in_rate = data->bitrate.value;
167 u8 rate;
168 int is_ofdm = 0;
169 int err = -EINVAL;
170
171 if (in_rate == -1) {
172 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
173 in_rate = 24000000;
174 else
175 in_rate = 11000000;
176 }
177
178 switch (in_rate) {
179 case 1000000:
180 rate = IEEE80211_CCK_RATE_1MB;
181 break;
182 case 2000000:
183 rate = IEEE80211_CCK_RATE_2MB;
184 break;
185 case 5500000:
186 rate = IEEE80211_CCK_RATE_5MB;
187 break;
188 case 11000000:
189 rate = IEEE80211_CCK_RATE_11MB;
190 break;
191 case 6000000:
192 rate = IEEE80211_OFDM_RATE_6MB;
193 is_ofdm = 1;
194 break;
195 case 9000000:
196 rate = IEEE80211_OFDM_RATE_9MB;
197 is_ofdm = 1;
198 break;
199 case 12000000:
200 rate = IEEE80211_OFDM_RATE_12MB;
201 is_ofdm = 1;
202 break;
203 case 18000000:
204 rate = IEEE80211_OFDM_RATE_18MB;
205 is_ofdm = 1;
206 break;
207 case 24000000:
208 rate = IEEE80211_OFDM_RATE_24MB;
209 is_ofdm = 1;
210 break;
211 case 36000000:
212 rate = IEEE80211_OFDM_RATE_36MB;
213 is_ofdm = 1;
214 break;
215 case 48000000:
216 rate = IEEE80211_OFDM_RATE_48MB;
217 is_ofdm = 1;
218 break;
219 case 54000000:
220 rate = IEEE80211_OFDM_RATE_54MB;
221 is_ofdm = 1;
222 break;
223 default:
224 goto out;
225 }
226
227 spin_lock_irqsave(&mac->lock, flags);
228
229 /* Check if correct modulation for this PHY. */
230 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
231 goto out_unlock;
232
233 mac->txrates.user_rate = rate;
234 ieee80211softmac_recalc_txrates(mac);
235 err = 0;
236
237out_unlock:
238 spin_unlock_irqrestore(&mac->lock, flags);
239out:
240 return err;
241}
242EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
243
244int
245ieee80211softmac_wx_get_rate(struct net_device *net_dev,
246 struct iw_request_info *info,
247 union iwreq_data *data,
248 char *extra)
249{
250 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
251 unsigned long flags;
252 int err = -EINVAL;
253
254 spin_lock_irqsave(&mac->lock, flags);
255
256 if (unlikely(!mac->running)) {
257 err = -ENODEV;
258 goto out_unlock;
259 }
260
261 switch (mac->txrates.default_rate) {
262 case IEEE80211_CCK_RATE_1MB:
263 data->bitrate.value = 1000000;
264 break;
265 case IEEE80211_CCK_RATE_2MB:
266 data->bitrate.value = 2000000;
267 break;
268 case IEEE80211_CCK_RATE_5MB:
269 data->bitrate.value = 5500000;
270 break;
271 case IEEE80211_CCK_RATE_11MB:
272 data->bitrate.value = 11000000;
273 break;
274 case IEEE80211_OFDM_RATE_6MB:
275 data->bitrate.value = 6000000;
276 break;
277 case IEEE80211_OFDM_RATE_9MB:
278 data->bitrate.value = 9000000;
279 break;
280 case IEEE80211_OFDM_RATE_12MB:
281 data->bitrate.value = 12000000;
282 break;
283 case IEEE80211_OFDM_RATE_18MB:
284 data->bitrate.value = 18000000;
285 break;
286 case IEEE80211_OFDM_RATE_24MB:
287 data->bitrate.value = 24000000;
288 break;
289 case IEEE80211_OFDM_RATE_36MB:
290 data->bitrate.value = 36000000;
291 break;
292 case IEEE80211_OFDM_RATE_48MB:
293 data->bitrate.value = 48000000;
294 break;
295 case IEEE80211_OFDM_RATE_54MB:
296 data->bitrate.value = 54000000;
297 break;
298 default:
299 assert(0);
300 goto out_unlock;
301 }
302 err = 0;
303out_unlock:
304 spin_unlock_irqrestore(&mac->lock, flags);
305
306 return err;
307}
308EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
309
310int
311ieee80211softmac_wx_get_wap(struct net_device *net_dev,
312 struct iw_request_info *info,
313 union iwreq_data *data,
314 char *extra)
315{
316 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
317 int err = 0;
318
319 mutex_lock(&mac->associnfo.mutex);
320 if (mac->associnfo.bssvalid)
321 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
322 else
323 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
324 data->ap_addr.sa_family = ARPHRD_ETHER;
325 mutex_unlock(&mac->associnfo.mutex);
326
327 return err;
328}
329EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
330
331int
332ieee80211softmac_wx_set_wap(struct net_device *net_dev,
333 struct iw_request_info *info,
334 union iwreq_data *data,
335 char *extra)
336{
337 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
338
339 /* sanity check */
340 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
341 return -EINVAL;
342 }
343
344 mutex_lock(&mac->associnfo.mutex);
345 if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
346 /* the bssid we have is not to be fixed any longer,
347 * and we should reassociate to the best AP. */
348 mac->associnfo.bssfixed = 0;
349 /* force reassociation */
350 mac->associnfo.bssvalid = 0;
351 if (mac->associnfo.associated)
352 queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
353 } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
354 /* the bssid we have is no longer fixed */
355 mac->associnfo.bssfixed = 0;
356 } else {
357 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
358 if (mac->associnfo.associating || mac->associnfo.associated) {
359 /* bssid unchanged and associated or associating - just return */
360 goto out;
361 }
362 } else {
363 /* copy new value in data->ap_addr.sa_data to bssid */
364 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
365 }
366 /* tell the other code that this bssid should be used no matter what */
367 mac->associnfo.bssfixed = 1;
368 /* queue associate if new bssid or (old one again and not associated) */
369 queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
370 }
371
372 out:
373 mutex_unlock(&mac->associnfo.mutex);
374
375 return 0;
376}
377EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
378
379int
380ieee80211softmac_wx_set_genie(struct net_device *dev,
381 struct iw_request_info *info,
382 union iwreq_data *wrqu,
383 char *extra)
384{
385 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
386 unsigned long flags;
387 int err = 0;
388 char *buf;
389 int i;
390
391 mutex_lock(&mac->associnfo.mutex);
392 spin_lock_irqsave(&mac->lock, flags);
393 /* bleh. shouldn't be locked for that kmalloc... */
394
395 if (wrqu->data.length) {
396 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
397 /* this is an IE, so the length must be
398 * correct. Is it possible though that
399 * more than one IE is passed in?
400 */
401 err = -EINVAL;
402 goto out;
403 }
404 if (mac->wpa.IEbuflen <= wrqu->data.length) {
405 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
406 if (!buf) {
407 err = -ENOMEM;
408 goto out;
409 }
410 kfree(mac->wpa.IE);
411 mac->wpa.IE = buf;
412 mac->wpa.IEbuflen = wrqu->data.length;
413 }
414 memcpy(mac->wpa.IE, extra, wrqu->data.length);
415 dprintk(KERN_INFO PFX "generic IE set to ");
416 for (i=0;i<wrqu->data.length;i++)
417 dprintk("%.2x", (u8)mac->wpa.IE[i]);
418 dprintk("\n");
419 mac->wpa.IElen = wrqu->data.length;
420 } else {
421 kfree(mac->wpa.IE);
422 mac->wpa.IE = NULL;
423 mac->wpa.IElen = 0;
424 mac->wpa.IEbuflen = 0;
425 }
426
427 out:
428 spin_unlock_irqrestore(&mac->lock, flags);
429 mutex_unlock(&mac->associnfo.mutex);
430
431 return err;
432}
433EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
434
435int
436ieee80211softmac_wx_get_genie(struct net_device *dev,
437 struct iw_request_info *info,
438 union iwreq_data *wrqu,
439 char *extra)
440{
441 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
442 unsigned long flags;
443 int err = 0;
444 int space = wrqu->data.length;
445
446 mutex_lock(&mac->associnfo.mutex);
447 spin_lock_irqsave(&mac->lock, flags);
448
449 wrqu->data.length = 0;
450
451 if (mac->wpa.IE && mac->wpa.IElen) {
452 wrqu->data.length = mac->wpa.IElen;
453 if (mac->wpa.IElen <= space)
454 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
455 else
456 err = -E2BIG;
457 }
458 spin_unlock_irqrestore(&mac->lock, flags);
459 mutex_unlock(&mac->associnfo.mutex);
460
461 return err;
462}
463EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
464
465int
466ieee80211softmac_wx_set_mlme(struct net_device *dev,
467 struct iw_request_info *info,
468 union iwreq_data *wrqu,
469 char *extra)
470{
471 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
472 struct iw_mlme *mlme = (struct iw_mlme *)extra;
473 u16 reason = mlme->reason_code;
474 struct ieee80211softmac_network *net;
475 int err = -EINVAL;
476
477 mutex_lock(&mac->associnfo.mutex);
478
479 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
480 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
481 goto out;
482 }
483
484 switch (mlme->cmd) {
485 case IW_MLME_DEAUTH:
486 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
487 if (!net) {
488 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
489 goto out;
490 }
491 err = ieee80211softmac_deauth_req(mac, net, reason);
492 goto out;
493 case IW_MLME_DISASSOC:
494 ieee80211softmac_send_disassoc_req(mac, reason);
495 mac->associnfo.associated = 0;
496 mac->associnfo.associating = 0;
497 err = 0;
498 goto out;
499 default:
500 err = -EOPNOTSUPP;
501 }
502
503out:
504 mutex_unlock(&mac->associnfo.mutex);
505
506 return err;
507}
508EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);