aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee80211
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-23 23:44:19 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-23 23:44:19 -0500
commit1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch)
treef5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /net/ieee80211
parentac58c9059da8886b5e8cde012a80266b18ca146e (diff)
parent674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff)
Merge branch 'linus'
Diffstat (limited to 'net/ieee80211')
-rw-r--r--net/ieee80211/Kconfig1
-rw-r--r--net/ieee80211/Makefile1
-rw-r--r--net/ieee80211/ieee80211_rx.c74
-rw-r--r--net/ieee80211/softmac/Kconfig10
-rw-r--r--net/ieee80211/softmac/Makefile9
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c396
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c364
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_event.c159
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_io.c474
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c457
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_priv.h230
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_scan.c244
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c412
13 files changed, 2831 insertions, 0 deletions
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
index d18ccba3ea9e..dbb08528ddf5 100644
--- a/net/ieee80211/Kconfig
+++ b/net/ieee80211/Kconfig
@@ -66,3 +66,4 @@ config IEEE80211_CRYPT_TKIP
66 This can be compiled as a modules and it will be called 66 This can be compiled as a modules and it will be called
67 "ieee80211_crypt_tkip". 67 "ieee80211_crypt_tkip".
68 68
69source "net/ieee80211/softmac/Kconfig"
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile
index f988417121da..796a7c76ee48 100644
--- a/net/ieee80211/Makefile
+++ b/net/ieee80211/Makefile
@@ -10,3 +10,4 @@ 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/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index a7f2a642a512..604b7b0097bc 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -780,6 +780,80 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
780 return 0; 780 return 0;
781} 781}
782 782
783/* Filter out unrelated packets, call ieee80211_rx[_mgt] */
784int ieee80211_rx_any(struct ieee80211_device *ieee,
785 struct sk_buff *skb, struct ieee80211_rx_stats *stats)
786{
787 struct ieee80211_hdr_4addr *hdr;
788 int is_packet_for_us;
789 u16 fc;
790
791 if (ieee->iw_mode == IW_MODE_MONITOR)
792 return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL;
793
794 hdr = (struct ieee80211_hdr_4addr *)skb->data;
795 fc = le16_to_cpu(hdr->frame_ctl);
796
797 if ((fc & IEEE80211_FCTL_VERS) != 0)
798 return -EINVAL;
799
800 switch (fc & IEEE80211_FCTL_FTYPE) {
801 case IEEE80211_FTYPE_MGMT:
802 ieee80211_rx_mgt(ieee, hdr, stats);
803 return 0;
804 case IEEE80211_FTYPE_DATA:
805 break;
806 case IEEE80211_FTYPE_CTL:
807 return 0;
808 default:
809 return -EINVAL;
810 }
811
812 is_packet_for_us = 0;
813 switch (ieee->iw_mode) {
814 case IW_MODE_ADHOC:
815 /* our BSS and not from/to DS */
816 if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0)
817 if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
818 /* promisc: get all */
819 if (ieee->dev->flags & IFF_PROMISC)
820 is_packet_for_us = 1;
821 /* to us */
822 else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
823 is_packet_for_us = 1;
824 /* mcast */
825 else if (is_multicast_ether_addr(hdr->addr1))
826 is_packet_for_us = 1;
827 }
828 break;
829 case IW_MODE_INFRA:
830 /* our BSS (== from our AP) and from DS */
831 if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0)
832 if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
833 /* promisc: get all */
834 if (ieee->dev->flags & IFF_PROMISC)
835 is_packet_for_us = 1;
836 /* to us */
837 else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
838 is_packet_for_us = 1;
839 /* mcast */
840 else if (is_multicast_ether_addr(hdr->addr1)) {
841 /* not our own packet bcasted from AP */
842 if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN))
843 is_packet_for_us = 1;
844 }
845 }
846 break;
847 default:
848 /* ? */
849 break;
850 }
851
852 if (is_packet_for_us)
853 return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL);
854 return 0;
855}
856
783#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 857#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
784 858
785static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; 859static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig
new file mode 100644
index 000000000000..6cd9f3427be6
--- /dev/null
+++ b/net/ieee80211/softmac/Kconfig
@@ -0,0 +1,10 @@
1config IEEE80211_SOFTMAC
2 tristate "Software MAC add-on to the IEEE 802.11 networking stack"
3 depends on IEEE80211 && EXPERIMENTAL
4 ---help---
5 This option enables the hardware independent software MAC addon
6 for the IEEE 802.11 networking stack.
7
8config IEEE80211_SOFTMAC_DEBUG
9 bool "Enable full debugging output"
10 depends on IEEE80211_SOFTMAC
diff --git a/net/ieee80211/softmac/Makefile b/net/ieee80211/softmac/Makefile
new file mode 100644
index 000000000000..bfcb391bb2c7
--- /dev/null
+++ b/net/ieee80211/softmac/Makefile
@@ -0,0 +1,9 @@
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
new file mode 100644
index 000000000000..be61de78dfa4
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -0,0 +1,396 @@
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 /* Change the state to associating */
51 spin_lock_irqsave(&mac->lock, flags);
52 mac->associnfo.associating = 1;
53 mac->associated = 0; /* just to make sure */
54 spin_unlock_irqrestore(&mac->lock, flags);
55
56 /* Set a timer for timeout */
57 /* FIXME: make timeout configurable */
58 schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ);
59}
60
61void
62ieee80211softmac_assoc_timeout(void *d)
63{
64 struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
65 unsigned long flags;
66
67 spin_lock_irqsave(&mac->lock, flags);
68 /* we might race against ieee80211softmac_handle_assoc_response,
69 * so make sure only one of us does something */
70 if (!mac->associnfo.associating) {
71 spin_unlock_irqrestore(&mac->lock, flags);
72 return;
73 }
74 mac->associnfo.associating = 0;
75 mac->associnfo.bssvalid = 0;
76 mac->associated = 0;
77 spin_unlock_irqrestore(&mac->lock, flags);
78
79 dprintk(KERN_INFO PFX "assoc request timed out!\n");
80 /* FIXME: we need to know the network here. that requires a bit of restructuring */
81 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
82}
83
84/* Sends out a disassociation request to the desired AP */
85static void
86ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
87{
88 unsigned long flags;
89 struct ieee80211softmac_network *found;
90
91 if (mac->associnfo.bssvalid && mac->associated) {
92 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
93 if (found)
94 ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
95 } else if (mac->associnfo.associating) {
96 cancel_delayed_work(&mac->associnfo.timeout);
97 }
98
99 /* Change our state */
100 spin_lock_irqsave(&mac->lock, flags);
101 /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */
102 mac->associated = 0;
103 mac->associnfo.associating = 0;
104 spin_unlock_irqrestore(&mac->lock, flags);
105}
106
107static inline int
108we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
109{
110 int idx, search, found;
111 u8 rate, search_rate;
112
113 for (idx = 0; idx < (from_len); idx++) {
114 rate = (from)[idx];
115 if (!(rate & IEEE80211_BASIC_RATE_MASK))
116 continue;
117 found = 0;
118 rate &= ~IEEE80211_BASIC_RATE_MASK;
119 for (search = 0; search < mac->ratesinfo.count; search++) {
120 search_rate = mac->ratesinfo.rates[search];
121 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
122 if (rate == search_rate) {
123 found = 1;
124 break;
125 }
126 }
127 if (!found)
128 return 0;
129 }
130 return 1;
131}
132
133static int
134network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
135{
136 /* we cannot associate to networks whose name we don't know */
137 if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
138 return 0;
139 /* do not associate to a network whose BSSBasicRateSet we cannot support */
140 if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
141 return 0;
142 /* do we really need to check the ex rates? */
143 if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
144 return 0;
145
146 /* if 'ANY' network requested, take any that doesn't have privacy enabled */
147 if (mac->associnfo.req_essid.len == 0
148 && !(net->capability & WLAN_CAPABILITY_PRIVACY))
149 return 1;
150 if (net->ssid_len != mac->associnfo.req_essid.len)
151 return 0;
152 if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
153 return 1;
154 return 0;
155}
156
157static void
158ieee80211softmac_assoc_notify(struct net_device *dev, void *context)
159{
160 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
161 ieee80211softmac_assoc_work((void*)mac);
162}
163
164/* This function is called to handle userspace requests (asynchronously) */
165void
166ieee80211softmac_assoc_work(void *d)
167{
168 struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
169 struct ieee80211softmac_network *found = NULL;
170 struct ieee80211_network *net = NULL, *best = NULL;
171 unsigned long flags;
172
173 /* meh */
174 if (mac->associated)
175 ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
176
177 /* try to find the requested network in our list, if we found one already */
178 if (mac->associnfo.bssvalid)
179 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
180
181 /* Search the ieee80211 networks for this network if we didn't find it by bssid,
182 * but only if we've scanned at least once (to get a better list of networks to
183 * select from). If we have not scanned before, the !found logic below will be
184 * invoked and will scan. */
185 if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT))
186 {
187 s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning
188 because it cannot follow the best pointer logic. */
189 spin_lock_irqsave(&mac->ieee->lock, flags);
190 list_for_each_entry(net, &mac->ieee->network_list, list) {
191 /* we're supposed to find the network with
192 * the best signal here, as we're asked to join
193 * any network with a specific ESSID, and many
194 * different ones could have that.
195 *
196 * I'll for now just go with the reported rssi.
197 *
198 * We also should take into account the rateset
199 * here to find the best BSSID to try.
200 */
201 if (network_matches_request(mac, net)) {
202 if (!best) {
203 best = net;
204 rssi = best->stats.rssi;
205 continue;
206 }
207 /* we already had a matching network, so
208 * compare their properties to get the
209 * better of the two ... (see above)
210 */
211 if (rssi < net->stats.rssi) {
212 best = net;
213 rssi = best->stats.rssi;
214 }
215 }
216 }
217 /* if we unlock here, we might get interrupted and the `best'
218 * pointer could go stale */
219 if (best) {
220 found = ieee80211softmac_create_network(mac, best);
221 /* if found is still NULL, then we got -ENOMEM somewhere */
222 if (found)
223 ieee80211softmac_add_network(mac, found);
224 }
225 spin_unlock_irqrestore(&mac->ieee->lock, flags);
226 }
227
228 if (!found) {
229 if (mac->associnfo.scan_retry > 0) {
230 spin_lock_irqsave(&mac->lock, flags);
231 mac->associnfo.scan_retry--;
232 spin_unlock_irqrestore(&mac->lock, flags);
233
234 /* We know of no such network. Let's scan.
235 * NB: this also happens if we had no memory to copy the network info...
236 * Maybe we can hope to have more memory after scanning finishes ;)
237 */
238 dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
239 ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL);
240 if (ieee80211softmac_start_scan(mac))
241 dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
242 return;
243 }
244 else {
245 spin_lock_irqsave(&mac->lock, flags);
246 mac->associnfo.associating = 0;
247 mac->associated = 0;
248 spin_unlock_irqrestore(&mac->lock, flags);
249
250 dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
251 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
252 return;
253 }
254 }
255
256 mac->associnfo.bssvalid = 1;
257 memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
258 /* copy the ESSID for displaying it */
259 mac->associnfo.associate_essid.len = found->essid.len;
260 memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
261
262 /* we found a network! authenticate (if necessary) and associate to it. */
263 if (!found->authenticated) {
264 /* This relies on the fact that _auth_req only queues the work,
265 * otherwise adding the notification would be racy. */
266 if (!ieee80211softmac_auth_req(mac, found)) {
267 dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
268 ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL);
269 } else {
270 printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
271 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
272 }
273 return;
274 }
275 /* finally! now we can start associating */
276 ieee80211softmac_assoc(mac, found);
277}
278
279/* call this to do whatever is necessary when we're associated */
280static void
281ieee80211softmac_associated(struct ieee80211softmac_device *mac,
282 struct ieee80211_assoc_response * resp,
283 struct ieee80211softmac_network *net)
284{
285 mac->associnfo.associating = 0;
286 mac->associated = 1;
287 if (mac->set_bssid_filter)
288 mac->set_bssid_filter(mac->dev, net->bssid);
289 memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
290 netif_carrier_on(mac->dev);
291
292 mac->association_id = le16_to_cpup(&resp->aid);
293}
294
295/* received frame handling functions */
296int
297ieee80211softmac_handle_assoc_response(struct net_device * dev,
298 struct ieee80211_assoc_response * resp,
299 struct ieee80211_network * _ieee80211_network_do_not_use)
300{
301 /* NOTE: the network parameter has to be ignored by
302 * this code because it is the ieee80211's pointer
303 * to the struct, not ours (we made a copy)
304 */
305 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
306 u16 status = le16_to_cpup(&resp->status);
307 struct ieee80211softmac_network *network = NULL;
308 unsigned long flags;
309
310 spin_lock_irqsave(&mac->lock, flags);
311
312 if (!mac->associnfo.associating) {
313 /* we race against the timeout function, so make sure
314 * only one of us can do work */
315 spin_unlock_irqrestore(&mac->lock, flags);
316 return 0;
317 }
318 network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
319
320 /* someone sending us things without us knowing him? Ignore. */
321 if (!network) {
322 dprintk(KERN_INFO PFX "Received unrequested assocation response from " MAC_FMT "\n", MAC_ARG(resp->header.addr3));
323 spin_unlock_irqrestore(&mac->lock, flags);
324 return 0;
325 }
326
327 /* now that we know it was for us, we can cancel the timeout */
328 cancel_delayed_work(&mac->associnfo.timeout);
329
330 switch (status) {
331 case 0:
332 dprintk(KERN_INFO PFX "associated!\n");
333 ieee80211softmac_associated(mac, resp, network);
334 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
335 break;
336 case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
337 if (!network->auth_desynced_once) {
338 /* there seem to be a few rare cases where our view of
339 * the world is obscured, or buggy APs that don't DEAUTH
340 * us properly. So we handle that, but allow it only once.
341 */
342 printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
343 network->authenticated = 0;
344 /* we don't want to do this more than once ... */
345 network->auth_desynced_once = 1;
346 schedule_work(&mac->associnfo.work);
347 break;
348 }
349 default:
350 dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
351 mac->associnfo.associating = 0;
352 mac->associnfo.bssvalid = 0;
353 mac->associated = 0;
354 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
355 }
356
357 spin_unlock_irqrestore(&mac->lock, flags);
358 return 0;
359}
360
361int
362ieee80211softmac_handle_disassoc(struct net_device * dev,
363 struct ieee80211_disassoc *disassoc)
364{
365 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
366 unsigned long flags;
367 if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
368 return 0;
369 if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
370 return 0;
371 dprintk(KERN_INFO PFX "got disassoc frame\n");
372 netif_carrier_off(dev);
373 spin_lock_irqsave(&mac->lock, flags);
374 mac->associnfo.bssvalid = 0;
375 mac->associated = 0;
376 schedule_work(&mac->associnfo.work);
377 spin_unlock_irqrestore(&mac->lock, flags);
378
379 return 0;
380}
381
382int
383ieee80211softmac_handle_reassoc_req(struct net_device * dev,
384 struct ieee80211_reassoc_request * resp)
385{
386 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
387 struct ieee80211softmac_network *network;
388
389 network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
390 if (!network) {
391 dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
392 return 0;
393 }
394 ieee80211softmac_assoc(mac, network);
395 return 0;
396}
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
new file mode 100644
index 000000000000..9a0eac6c61eb
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -0,0 +1,364 @@
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(void *data);
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
39 if (net->authenticating)
40 return 0;
41
42 /* Add the network if it's not already added */
43 ieee80211softmac_add_network(mac, net);
44
45 dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid));
46 /* Queue the auth request */
47 auth = (struct ieee80211softmac_auth_queue_item *)
48 kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
49 if(auth == NULL)
50 return -ENOMEM;
51
52 auth->net = net;
53 auth->mac = mac;
54 auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
55 auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
56 INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth);
57
58 /* Lock (for list) */
59 spin_lock_irqsave(&mac->lock, flags);
60
61 /* add to list */
62 list_add_tail(&auth->list, &mac->auth_queue);
63 schedule_work(&auth->work);
64 spin_unlock_irqrestore(&mac->lock, flags);
65
66 return 0;
67}
68
69
70/* Sends an auth request to the desired AP and handles timeouts */
71static void
72ieee80211softmac_auth_queue(void *data)
73{
74 struct ieee80211softmac_device *mac;
75 struct ieee80211softmac_auth_queue_item *auth;
76 struct ieee80211softmac_network *net;
77 unsigned long flags;
78
79 auth = (struct ieee80211softmac_auth_queue_item *)data;
80 net = auth->net;
81 mac = auth->mac;
82
83 if(auth->retry > 0) {
84 /* Switch to correct channel for this network */
85 mac->set_channel(mac->dev, net->channel);
86
87 /* Lock and set flags */
88 spin_lock_irqsave(&mac->lock, flags);
89 net->authenticated = 0;
90 net->authenticating = 1;
91 /* add a timeout call so we eventually give up waiting for an auth reply */
92 schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
93 auth->retry--;
94 spin_unlock_irqrestore(&mac->lock, flags);
95 if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
96 dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid));
97 else
98 dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid));
99 return;
100 }
101
102 printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid));
103 /* Remove this item from the queue */
104 spin_lock_irqsave(&mac->lock, flags);
105 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
106 cancel_delayed_work(&auth->work); /* just to make sure... */
107 list_del(&auth->list);
108 spin_unlock_irqrestore(&mac->lock, flags);
109 /* Free it */
110 kfree(auth);
111}
112
113/* Handle the auth response from the AP
114 * This should be registered with ieee80211 as handle_auth
115 */
116int
117ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
118{
119
120 struct list_head *list_ptr;
121 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
122 struct ieee80211softmac_auth_queue_item *aq = NULL;
123 struct ieee80211softmac_network *net = NULL;
124 unsigned long flags;
125 u8 * data;
126
127 /* Find correct auth queue item */
128 spin_lock_irqsave(&mac->lock, flags);
129 list_for_each(list_ptr, &mac->auth_queue) {
130 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
131 net = aq->net;
132 if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
133 break;
134 else
135 aq = NULL;
136 }
137 spin_unlock_irqrestore(&mac->lock, flags);
138
139 /* Make sure that we've got an auth queue item for this request */
140 if(aq == NULL)
141 {
142 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2));
143 /* Error #? */
144 return -1;
145 }
146
147 /* Check for out of order authentication */
148 if(!net->authenticating)
149 {
150 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2));
151 return -1;
152 }
153
154 /* Parse the auth packet */
155 switch(auth->algorithm) {
156 case WLAN_AUTH_OPEN:
157 /* Check the status code of the response */
158
159 switch(auth->status) {
160 case WLAN_STATUS_SUCCESS:
161 /* Update the status to Authenticated */
162 spin_lock_irqsave(&mac->lock, flags);
163 net->authenticating = 0;
164 net->authenticated = 1;
165 spin_unlock_irqrestore(&mac->lock, flags);
166
167 /* Send event */
168 printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid));
169 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
170 break;
171 default:
172 /* Lock and reset flags */
173 spin_lock_irqsave(&mac->lock, flags);
174 net->authenticated = 0;
175 net->authenticating = 0;
176 spin_unlock_irqrestore(&mac->lock, flags);
177
178 printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n",
179 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
180 /* Count the error? */
181 break;
182 }
183 goto free_aq;
184 break;
185 case WLAN_AUTH_SHARED_KEY:
186 /* Figure out where we are in the process */
187 switch(auth->transaction) {
188 case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
189 /* Check to make sure we have a challenge IE */
190 data = (u8 *)auth->info_element;
191 if(*data++ != MFIE_TYPE_CHALLENGE){
192 printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
193 break;
194 }
195 /* Save the challenge */
196 spin_lock_irqsave(&mac->lock, flags);
197 net->challenge_len = *data++;
198 if(net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
199 net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
200 if(net->challenge != NULL)
201 kfree(net->challenge);
202 net->challenge = kmalloc(net->challenge_len, GFP_ATOMIC);
203 memcpy(net->challenge, data, net->challenge_len);
204 aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
205 spin_unlock_irqrestore(&mac->lock, flags);
206
207 /* Switch to correct channel for this network */
208 mac->set_channel(mac->dev, net->channel);
209
210 /* Send our response (How to encrypt?) */
211 ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
212 break;
213 case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
214 /* Check the status code of the response */
215 switch(auth->status) {
216 case WLAN_STATUS_SUCCESS:
217 /* Update the status to Authenticated */
218 spin_lock_irqsave(&mac->lock, flags);
219 net->authenticating = 0;
220 net->authenticated = 1;
221 spin_unlock_irqrestore(&mac->lock, flags);
222 printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n",
223 MAC_ARG(net->bssid));
224 break;
225 default:
226 printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n",
227 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
228 /* Lock and reset flags */
229 spin_lock_irqsave(&mac->lock, flags);
230 net->authenticating = 0;
231 net->authenticated = 0;
232 spin_unlock_irqrestore(&mac->lock, flags);
233 /* Count the error? */
234 break;
235 }
236 goto free_aq;
237 break;
238 default:
239 printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
240 break;
241 }
242 goto free_aq;
243 break;
244 default:
245 /* ERROR */
246 goto free_aq;
247 break;
248 }
249 return 0;
250free_aq:
251 /* Cancel the timeout */
252 spin_lock_irqsave(&mac->lock, flags);
253 cancel_delayed_work(&aq->work);
254 /* Remove this item from the queue */
255 list_del(&aq->list);
256 spin_unlock_irqrestore(&mac->lock, flags);
257
258 /* Free it */
259 kfree(aq);
260 return 0;
261}
262
263/*
264 * Handle deauthorization
265 */
266static void
267ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
268 struct ieee80211softmac_network *net)
269{
270 struct ieee80211softmac_auth_queue_item *aq = NULL;
271 struct list_head *list_ptr;
272 unsigned long flags;
273
274 /* Lock and reset status flags */
275 spin_lock_irqsave(&mac->lock, flags);
276 net->authenticating = 0;
277 net->authenticated = 0;
278
279 /* Find correct auth queue item, if it exists */
280 list_for_each(list_ptr, &mac->auth_queue) {
281 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
282 if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
283 break;
284 else
285 aq = NULL;
286 }
287
288 /* Cancel pending work */
289 if(aq != NULL)
290 /* Not entirely safe? What about running work? */
291 cancel_delayed_work(&aq->work);
292
293 /* Free our network ref */
294 ieee80211softmac_del_network_locked(mac, net);
295 if(net->challenge != NULL)
296 kfree(net->challenge);
297 kfree(net);
298
299 /* can't transmit data right now... */
300 netif_carrier_off(mac->dev);
301 /* let's try to re-associate */
302 schedule_work(&mac->associnfo.work);
303 spin_unlock_irqrestore(&mac->lock, flags);
304}
305
306/*
307 * Sends a deauth request to the desired AP
308 */
309int
310ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
311 struct ieee80211softmac_network *net, int reason)
312{
313 int ret;
314
315 /* Make sure the network is authenticated */
316 if (!net->authenticated)
317 {
318 printkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
319 /* Error okay? */
320 return -EPERM;
321 }
322
323 /* Send the de-auth packet */
324 if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
325 return ret;
326
327 ieee80211softmac_deauth_from_net(mac, net);
328 return 0;
329}
330
331/*
332 * This should be registered with ieee80211 as handle_deauth
333 */
334int
335ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth)
336{
337
338 struct ieee80211softmac_network *net = NULL;
339 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
340
341 if (!deauth) {
342 dprintk("deauth without deauth packet. eek!\n");
343 return 0;
344 }
345
346 net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2);
347
348 if (net == NULL) {
349 printkl(KERN_DEBUG PFX "Received deauthentication packet from "MAC_FMT", but that network is unknown.\n",
350 MAC_ARG(deauth->header.addr2));
351 return 0;
352 }
353
354 /* Make sure the network is authenticated */
355 if(!net->authenticated)
356 {
357 printkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
358 /* Error okay? */
359 return -EPERM;
360 }
361
362 ieee80211softmac_deauth_from_net(mac, net);
363 return 0;
364}
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c
new file mode 100644
index 000000000000..0a52bbda1e4c
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_event.c
@@ -0,0 +1,159 @@
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: no special meaning
42 * ASSOCIATED,
43 * ASSOCIATE_FAILED,
44 * ASSOCIATE_TIMEOUT,
45 * AUTHENTICATED,
46 * AUTH_FAILED,
47 * AUTH_TIMEOUT: a pointer to the network struct
48 * ...
49 * Code within this module can use the event context to be only
50 * called when the event is true for that specific context
51 * as per above table.
52 * If the event context is NULL, then the notification is always called,
53 * regardless of the event context. The event context is not passed to
54 * the callback, it is assumed that the context suffices.
55 *
56 * You can also use the event context only by setting the event type
57 * to -1 (private use only), in which case you'll be notified
58 * whenever the event context matches.
59 */
60
61static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
62 "scan finished",
63 "associated",
64 "associating failed",
65 "associating timed out",
66 "authenticated",
67 "authenticating failed",
68 "authenticating timed out",
69 "associating failed because no suitable network was found",
70};
71
72
73static void
74ieee80211softmac_notify_callback(void *d)
75{
76 struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d;
77 kfree(d);
78
79 event.fun(event.mac->dev, event.context);
80}
81
82int
83ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
84 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
85{
86 struct ieee80211softmac_event *eventptr;
87 unsigned long flags;
88
89 if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
90 return -ENOSYS;
91
92 if (!fun)
93 return -EINVAL;
94
95 eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
96 if (!eventptr)
97 return -ENOMEM;
98
99 eventptr->event_type = event;
100 INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr);
101 eventptr->fun = fun;
102 eventptr->context = context;
103 eventptr->mac = mac;
104 eventptr->event_context = event_context;
105
106 spin_lock_irqsave(&mac->lock, flags);
107 list_add(&eventptr->list, &mac->events);
108 spin_unlock_irqrestore(&mac->lock, flags);
109
110 return 0;
111}
112
113int
114ieee80211softmac_notify_gfp(struct net_device *dev,
115 int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
116{
117 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
118
119 if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
120 return -ENOSYS;
121
122 return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
123}
124EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
125
126/* private -- calling all callbacks that were specified */
127void
128ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
129{
130 struct ieee80211softmac_event *eventptr, *tmp;
131 union iwreq_data wrqu;
132 char *msg;
133
134 if (event >= 0) {
135 msg = event_descriptions[event];
136 wrqu.data.length = strlen(msg);
137 wireless_send_event(mac->dev, IWEVCUSTOM, &wrqu, msg);
138 }
139
140 if (!list_empty(&mac->events))
141 list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
142 if ((eventptr->event_type == event || eventptr->event_type == -1)
143 && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
144 list_del(&eventptr->list);
145 schedule_work(&eventptr->work);
146 }
147 }
148}
149
150void
151ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
152{
153 unsigned long flags;
154
155 spin_lock_irqsave(&mac->lock, flags);
156 ieee80211softmac_call_events_locked(mac, event, event_ctx);
157
158 spin_unlock_irqrestore(&mac->lock, flags);
159}
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
new file mode 100644
index 000000000000..febc51dbb412
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -0,0 +1,474 @@
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 = kmalloc(size, GFP_ATOMIC);
100 memset(data, 0, size);
101 return data;
102}
103
104/*
105 * Add a 2 Address Header
106 */
107static void
108ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac,
109 struct ieee80211_hdr_2addr *header, u32 type, u8 *dest)
110{
111 /* Fill in the frame control flags */
112 header->frame_ctl = cpu_to_le16(type);
113 /* Control packets always have WEP turned off */
114 if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL)
115 header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0;
116
117 /* Fill in the duration */
118 header->duration_id = 0;
119 /* FIXME: How do I find this?
120 * calculate. But most drivers just fill in 0 (except if it's a station id of course) */
121
122 /* Fill in the Destination Address */
123 if(dest == NULL)
124 memset(header->addr1, 0xFF, ETH_ALEN);
125 else
126 memcpy(header->addr1, dest, ETH_ALEN);
127 /* Fill in the Source Address */
128 memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN);
129
130}
131
132
133/* Add a 3 Address Header */
134static void
135ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
136 struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid)
137{
138 /* This is common with 2addr, so use that instead */
139 ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest);
140
141 /* Fill in the BSS ID */
142 if(bssid == NULL)
143 memset(header->addr3, 0xFF, ETH_ALEN);
144 else
145 memcpy(header->addr3, bssid, ETH_ALEN);
146
147 /* Fill in the sequence # */
148 /* FIXME: I need to add this to the softmac struct
149 * shouldn't the sequence number be in ieee80211? */
150}
151
152
153/*****************************************************************************
154 * Create Management packets
155 *****************************************************************************/
156
157/* Creates an association request packet */
158static u32
159ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
160 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
161{
162 u8 *data;
163 (*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt(
164 2 + /* Capability Info */
165 2 + /* Listen Interval */
166 /* SSID IE */
167 1 + 1 + IW_ESSID_MAX_SIZE +
168 /* Rates IE */
169 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
170 /* Extended Rates IE */
171 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN +
172 /* WPA IE if present */
173 mac->wpa.IElen
174 /* Other IE's? Optional?
175 * Yeah, probably need an extra IE parameter -- lots of vendors like to
176 * fill in their own IEs */
177 );
178 if (unlikely((*pkt) == NULL))
179 return 0;
180 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
181
182 /* Fill in capability Info */
183 (*pkt)->capability = (mac->ieee->iw_mode == IW_MODE_MASTER) || (mac->ieee->iw_mode == IW_MODE_INFRA) ?
184 cpu_to_le16(WLAN_CAPABILITY_ESS) :
185 cpu_to_le16(WLAN_CAPABILITY_IBSS);
186 /* Need to add this
187 (*pkt)->capability |= mac->ieee->short_slot ?
188 cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
189 */
190 (*pkt)->capability |= mac->ieee->sec.level ? cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
191 /* Fill in Listen Interval (?) */
192 (*pkt)->listen_interval = cpu_to_le16(10);
193
194 data = (u8 *)(*pkt)->info_element;
195 /* Add SSID */
196 data = ieee80211softmac_add_essid(data, &net->essid);
197 /* Add Rates */
198 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
199 /* Add WPA IE */
200 if (mac->wpa.IElen && mac->wpa.IE) {
201 memcpy(data, mac->wpa.IE, mac->wpa.IElen);
202 data += mac->wpa.IElen;
203 }
204 /* Return the number of used bytes */
205 return (data - (u8*)(*pkt));
206}
207
208/* Create a reassociation request packet */
209static u32
210ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
211 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
212{
213 u8 *data;
214 (*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt(
215 2 + /* Capability Info */
216 2 + /* Listen Interval */
217 ETH_ALEN + /* AP MAC */
218 /* SSID IE */
219 1 + 1 + IW_ESSID_MAX_SIZE +
220 /* Rates IE */
221 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
222 /* Extended Rates IE */
223 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
224 /* Other IE's? */
225 );
226 if (unlikely((*pkt) == NULL))
227 return 0;
228 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
229
230 /* Fill in capability Info */
231 (*pkt)->capability = mac->ieee->iw_mode == IW_MODE_MASTER ?
232 cpu_to_le16(WLAN_CAPABILITY_ESS) :
233 cpu_to_le16(WLAN_CAPABILITY_IBSS);
234 /*
235 (*pkt)->capability |= mac->ieee->short_slot ?
236 cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
237 */
238 (*pkt)->capability |= mac->ieee->sec.level ?
239 cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
240
241 /* Fill in Listen Interval (?) */
242 (*pkt)->listen_interval = cpu_to_le16(10);
243 /* Fill in the current AP MAC */
244 memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN);
245
246 data = (u8 *)(*pkt)->info_element;
247 /* Add SSID */
248 data = ieee80211softmac_add_essid(data, &net->essid);
249 /* Add Rates */
250 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
251 /* Return packet size */
252 return (data - (u8 *)(*pkt));
253}
254
255/* Create an authentication packet */
256static u32
257ieee80211softmac_auth(struct ieee80211_auth **pkt,
258 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
259 u16 transaction, u16 status)
260{
261 u8 *data;
262 /* Allocate Packet */
263 (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
264 2 + /* Auth Algorithm */
265 2 + /* Auth Transaction Seq */
266 2 + /* Status Code */
267 /* Challenge Text IE */
268 mac->ieee->open_wep ? 0 :
269 1 + 1 + WLAN_AUTH_CHALLENGE_LEN
270 );
271 if (unlikely((*pkt) == NULL))
272 return 0;
273 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
274
275 /* Algorithm */
276 (*pkt)->algorithm = mac->ieee->open_wep ?
277 cpu_to_le16(WLAN_AUTH_OPEN) :
278 cpu_to_le16(WLAN_AUTH_SHARED_KEY);
279 /* Transaction */
280 (*pkt)->transaction = cpu_to_le16(transaction);
281 /* Status */
282 (*pkt)->status = cpu_to_le16(status);
283
284 data = (u8 *)(*pkt)->info_element;
285 /* Challenge Text */
286 if(!mac->ieee->open_wep){
287 *data = MFIE_TYPE_CHALLENGE;
288 data++;
289
290 /* Copy the challenge in */
291 // *data = challenge length
292 // data += sizeof(u16);
293 // memcpy(data, challenge, challenge length);
294 // data += challenge length;
295
296 /* Add the full size to the packet length */
297 }
298
299 /* Return the packet size */
300 return (data - (u8 *)(*pkt));
301}
302
303/* Create a disassocation or deauthentication packet */
304static u32
305ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt,
306 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
307 u16 type, u16 reason)
308{
309 /* Allocate Packet */
310 (*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2);
311 if (unlikely((*pkt) == NULL))
312 return 0;
313 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid);
314 /* Reason */
315 (*pkt)->reason = cpu_to_le16(reason);
316 /* Return the packet size */
317 return (2 + IEEE80211_3ADDR_LEN);
318}
319
320/* Create a probe request packet */
321static u32
322ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt,
323 struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid)
324{
325 u8 *data;
326 /* Allocate Packet */
327 (*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt(
328 /* SSID of requested network */
329 1 + 1 + IW_ESSID_MAX_SIZE +
330 /* Rates IE */
331 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
332 /* Extended Rates IE */
333 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
334 );
335 if (unlikely((*pkt) == NULL))
336 return 0;
337 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL);
338
339 data = (u8 *)(*pkt)->info_element;
340 /* Add ESSID (can be NULL) */
341 data = ieee80211softmac_add_essid(data, essid);
342 /* Add Rates */
343 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
344 /* Return packet size */
345 return (data - (u8 *)(*pkt));
346}
347
348/* Create a probe response packet */
349/* FIXME: Not complete */
350static u32
351ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt,
352 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
353{
354 u8 *data;
355 /* Allocate Packet */
356 (*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt(
357 8 + /* Timestamp */
358 2 + /* Beacon Interval */
359 2 + /* Capability Info */
360 /* SSID IE */
361 1 + 1 + IW_ESSID_MAX_SIZE +
362 7 + /* FH Parameter Set */
363 2 + /* DS Parameter Set */
364 8 + /* CF Parameter Set */
365 4 /* IBSS Parameter Set */
366 );
367 if (unlikely((*pkt) == NULL))
368 return 0;
369 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid);
370 data = (u8 *)(*pkt)->info_element;
371
372 /* Return the packet size */
373 return (data - (u8 *)(*pkt));
374}
375
376
377/* Sends a manangement packet
378 * FIXME: document the use of the arg parameter
379 * for _AUTH: (transaction #) | (status << 16)
380 */
381int
382ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
383 void *ptrarg, u32 type, u32 arg)
384{
385 void *pkt = NULL;
386 u32 pkt_size = 0;
387
388 switch(type) {
389 case IEEE80211_STYPE_ASSOC_REQ:
390 pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
391 break;
392 case IEEE80211_STYPE_REASSOC_REQ:
393 pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
394 break;
395 case IEEE80211_STYPE_AUTH:
396 pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16));
397 break;
398 case IEEE80211_STYPE_DISASSOC:
399 case IEEE80211_STYPE_DEAUTH:
400 pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF));
401 break;
402 case IEEE80211_STYPE_PROBE_REQ:
403 pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg);
404 break;
405 case IEEE80211_STYPE_PROBE_RESP:
406 pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
407 break;
408 default:
409 printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type);
410 return -EINVAL;
411 };
412
413 if(pkt_size == 0 || pkt == NULL) {
414 printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n");
415 return -ENOMEM;
416 }
417
418 /* Send the packet to the ieee80211 layer for tx */
419 /* we defined softmac->mgmt_xmit for this. Should we keep it
420 * as it is (that means we'd need to wrap this into a txb),
421 * modify the prototype (so it matches this function),
422 * or get rid of it alltogether?
423 * Does this work for you now?
424 */
425 ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, pkt_size);
426
427 kfree(pkt);
428 return 0;
429}
430
431
432/* Create an rts/cts frame */
433static u32
434ieee80211softmac_rts_cts(struct ieee80211_hdr_2addr **pkt,
435 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
436 u32 type)
437{
438 /* Allocate Packet */
439 (*pkt) = kmalloc(IEEE80211_2ADDR_LEN, GFP_ATOMIC);
440 memset(*pkt, 0, IEEE80211_2ADDR_LEN);
441 if((*pkt) == NULL)
442 return 0;
443 ieee80211softmac_hdr_2addr(mac, (*pkt), type, net->bssid);
444 return IEEE80211_2ADDR_LEN;
445}
446
447
448/* Sends a control packet */
449static int
450ieee80211softmac_send_ctl_frame(struct ieee80211softmac_device *mac,
451 struct ieee80211softmac_network *net, u32 type, u32 arg)
452{
453 void *pkt = NULL;
454 u32 pkt_size = 0;
455
456 switch(type) {
457 case IEEE80211_STYPE_RTS:
458 case IEEE80211_STYPE_CTS:
459 pkt_size = ieee80211softmac_rts_cts((struct ieee80211_hdr_2addr **)(&pkt), mac, net, type);
460 break;
461 default:
462 printkl(KERN_DEBUG PFX "Unsupported Control Frame type: %i\n", type);
463 return -EINVAL;
464 }
465
466 if(pkt_size == 0)
467 return -ENOMEM;
468
469 /* Send the packet to the ieee80211 layer for tx */
470 ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *) pkt, pkt_size);
471
472 kfree(pkt);
473 return 0;
474}
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
new file mode 100644
index 000000000000..6f99f781bff8
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -0,0 +1,457 @@
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
30struct net_device *alloc_ieee80211softmac(int sizeof_priv)
31{
32 struct ieee80211softmac_device *softmac;
33 struct net_device *dev;
34
35 dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
36 softmac = ieee80211_priv(dev);
37 softmac->dev = dev;
38 softmac->ieee = netdev_priv(dev);
39 spin_lock_init(&softmac->lock);
40
41 softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
42 softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
43 softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
44 softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
45 softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
46 softmac->scaninfo = NULL;
47
48 /* TODO: initialise all the other callbacks in the ieee struct
49 * (once they're written)
50 */
51
52 INIT_LIST_HEAD(&softmac->auth_queue);
53 INIT_LIST_HEAD(&softmac->network_list);
54 INIT_LIST_HEAD(&softmac->events);
55
56 INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
57 INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
58 softmac->start_scan = ieee80211softmac_start_scan_implementation;
59 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
60 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
61
62 //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
63 // It has to be set to the highest rate all stations in the current network can handle.
64 softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
65 softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
66 /* This is reassigned in ieee80211softmac_start to sane values. */
67 softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
68 softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
69
70 /* to start with, we can't send anything ... */
71 netif_carrier_off(dev);
72
73 return dev;
74}
75EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
76
77/* Clears the pending work queue items, stops all scans, etc. */
78void
79ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
80{
81 unsigned long flags;
82 struct ieee80211softmac_event *eventptr, *eventtmp;
83 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
84 struct ieee80211softmac_network *netptr, *nettmp;
85
86 ieee80211softmac_stop_scan(sm);
87 ieee80211softmac_wait_for_scan(sm);
88
89 spin_lock_irqsave(&sm->lock, flags);
90 /* Free all pending assoc work items */
91 cancel_delayed_work(&sm->associnfo.work);
92
93 /* Free all pending scan work items */
94 if(sm->scaninfo != NULL)
95 cancel_delayed_work(&sm->scaninfo->softmac_scan);
96
97 /* Free all pending auth work items */
98 list_for_each_entry(authptr, &sm->auth_queue, list)
99 cancel_delayed_work(&authptr->work);
100
101 /* delete all pending event calls and work items */
102 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
103 cancel_delayed_work(&eventptr->work);
104
105 spin_unlock_irqrestore(&sm->lock, flags);
106 flush_scheduled_work();
107
108 /* now we should be save and no longer need locking... */
109 spin_lock_irqsave(&sm->lock, flags);
110 /* Free all pending auth work items */
111 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
112 list_del(&authptr->list);
113 kfree(authptr);
114 }
115
116 /* delete all pending event calls and work items */
117 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
118 list_del(&eventptr->list);
119 kfree(eventptr);
120 }
121
122 /* Free all networks */
123 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
124 ieee80211softmac_del_network_locked(sm, netptr);
125 if(netptr->challenge != NULL)
126 kfree(netptr->challenge);
127 kfree(netptr);
128 }
129
130 spin_unlock_irqrestore(&sm->lock, flags);
131}
132EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
133
134void free_ieee80211softmac(struct net_device *dev)
135{
136 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
137 ieee80211softmac_clear_pending_work(sm);
138 kfree(sm->scaninfo);
139 kfree(sm->wpa.IE);
140 free_ieee80211(dev);
141}
142EXPORT_SYMBOL_GPL(free_ieee80211softmac);
143
144static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
145{
146 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
147 /* I took out the sorting check, we're seperating by modulation now. */
148 if (ri->count)
149 return;
150 /* otherwise assume we hav'em all! */
151 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
152 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
153 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
154 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
155 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
156 }
157 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
158 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
159 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
160 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
161 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
162 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
163 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
164 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
165 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
166 }
167}
168
169void ieee80211softmac_start(struct net_device *dev)
170{
171 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
172 struct ieee80211_device *ieee = mac->ieee;
173 u32 change = 0;
174 struct ieee80211softmac_txrates oldrates;
175
176 ieee80211softmac_start_check_rates(mac);
177
178 /* TODO: We need some kind of state machine to lower the default rates
179 * if we loose too many packets.
180 */
181 /* Change the default txrate to the highest possible value.
182 * The txrate machine will lower it, if it is too high.
183 */
184 if (mac->txrates_change)
185 oldrates = mac->txrates;
186 if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
187 mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
188 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
189 mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
190 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
191 } else if (ieee->modulation & IEEE80211_CCK_MODULATION) {
192 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
193 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
194 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
195 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
196 } else
197 assert(0);
198 if (mac->txrates_change)
199 mac->txrates_change(dev, change, &oldrates);
200}
201EXPORT_SYMBOL_GPL(ieee80211softmac_start);
202
203void ieee80211softmac_stop(struct net_device *dev)
204{
205 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
206
207 ieee80211softmac_clear_pending_work(mac);
208}
209EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
210
211void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
212{
213 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
214 unsigned long flags;
215
216 spin_lock_irqsave(&mac->lock, flags);
217 memcpy(mac->ratesinfo.rates, rates, count);
218 mac->ratesinfo.count = count;
219 spin_unlock_irqrestore(&mac->lock, flags);
220}
221EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
222
223static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
224{
225 int i;
226 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
227
228 for (i=0; i<ri->count-1; i++) {
229 if (ri->rates[i] == rate)
230 return ri->rates[i+1];
231 }
232 /* I guess we can't go any higher... */
233 return ri->rates[ri->count];
234}
235
236u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
237{
238 int i;
239 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
240
241 for (i=delta; i<ri->count; i++) {
242 if (ri->rates[i] == rate)
243 return ri->rates[i-delta];
244 }
245 /* I guess we can't go any lower... */
246 return ri->rates[0];
247}
248
249static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
250 int amount)
251{
252 struct ieee80211softmac_txrates oldrates;
253 u8 default_rate = mac->txrates.default_rate;
254 u8 default_fallback = mac->txrates.default_fallback;
255 u32 changes = 0;
256
257 //TODO: This is highly experimental code.
258 // Maybe the dynamic rate selection does not work
259 // and it has to be removed again.
260
261printk("badness %d\n", mac->txrate_badness);
262 mac->txrate_badness += amount;
263 if (mac->txrate_badness <= -1000) {
264 /* Very small badness. Try a faster bitrate. */
265 if (mac->txrates_change)
266 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
267 default_rate = raise_rate(mac, default_rate);
268 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
269 default_fallback = get_fallback_rate(mac, default_rate);
270 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
271 mac->txrate_badness = 0;
272printk("Bitrate raised to %u\n", default_rate);
273 } else if (mac->txrate_badness >= 10000) {
274 /* Very high badness. Try a slower bitrate. */
275 if (mac->txrates_change)
276 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
277 default_rate = lower_rate(mac, default_rate);
278 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
279 default_fallback = get_fallback_rate(mac, default_rate);
280 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
281 mac->txrate_badness = 0;
282printk("Bitrate lowered to %u\n", default_rate);
283 }
284
285 mac->txrates.default_rate = default_rate;
286 mac->txrates.default_fallback = default_fallback;
287
288 if (changes && mac->txrates_change)
289 mac->txrates_change(mac->dev, changes, &oldrates);
290}
291
292void ieee80211softmac_fragment_lost(struct net_device *dev,
293 u16 wl_seq)
294{
295 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
296 unsigned long flags;
297
298 spin_lock_irqsave(&mac->lock, flags);
299 ieee80211softmac_add_txrates_badness(mac, 1000);
300 //TODO
301
302 spin_unlock_irqrestore(&mac->lock, flags);
303}
304EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
305
306static int rate_cmp(const void *a_, const void *b_) {
307 u8 *a, *b;
308 a = (u8*)a_;
309 b = (u8*)b_;
310 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
311}
312
313/* Allocate a softmac network struct and fill it from a network */
314struct ieee80211softmac_network *
315ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
316 struct ieee80211_network *net)
317{
318 struct ieee80211softmac_network *softnet;
319 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
320 if(softnet == NULL)
321 return NULL;
322 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
323 softnet->channel = net->channel;
324 softnet->essid.len = net->ssid_len;
325 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
326
327 /* copy rates over */
328 softnet->supported_rates.count = net->rates_len;
329 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
330 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
331 softnet->supported_rates.count += net->rates_ex_len;
332 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
333
334 softnet->capabilities = net->capability;
335 return softnet;
336}
337
338
339/* Add a network to the list, while locked */
340void
341ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
342 struct ieee80211softmac_network *add_net)
343{
344 struct list_head *list_ptr;
345 struct ieee80211softmac_network *softmac_net = NULL;
346
347 list_for_each(list_ptr, &mac->network_list) {
348 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
349 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
350 break;
351 else
352 softmac_net = NULL;
353 }
354 if(softmac_net == NULL)
355 list_add(&(add_net->list), &mac->network_list);
356}
357
358/* Add a network to the list, with locking */
359void
360ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
361 struct ieee80211softmac_network *add_net)
362{
363 unsigned long flags;
364 spin_lock_irqsave(&mac->lock, flags);
365 ieee80211softmac_add_network_locked(mac, add_net);
366 spin_unlock_irqrestore(&mac->lock, flags);
367}
368
369
370/* Delete a network from the list, while locked*/
371void
372ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
373 struct ieee80211softmac_network *del_net)
374{
375 list_del(&(del_net->list));
376}
377
378/* Delete a network from the list with locking */
379void
380ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
381 struct ieee80211softmac_network *del_net)
382{
383 unsigned long flags;
384 spin_lock_irqsave(&mac->lock, flags);
385 ieee80211softmac_del_network_locked(mac, del_net);
386 spin_unlock_irqrestore(&mac->lock, flags);
387}
388
389/* Get a network from the list by MAC while locked */
390struct ieee80211softmac_network *
391ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
392 u8 *bssid)
393{
394 struct list_head *list_ptr;
395 struct ieee80211softmac_network *softmac_net = NULL;
396 list_for_each(list_ptr, &mac->network_list) {
397 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
398 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
399 break;
400 else
401 softmac_net = NULL;
402 }
403 return softmac_net;
404}
405
406/* Get a network from the list by BSSID with locking */
407struct ieee80211softmac_network *
408ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
409 u8 *bssid)
410{
411 unsigned long flags;
412 struct ieee80211softmac_network *softmac_net;
413
414 spin_lock_irqsave(&mac->lock, flags);
415 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
416 spin_unlock_irqrestore(&mac->lock, flags);
417 return softmac_net;
418}
419
420/* Get a network from the list by ESSID while locked */
421struct ieee80211softmac_network *
422ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
423 struct ieee80211softmac_essid *essid)
424{
425 struct list_head *list_ptr;
426 struct ieee80211softmac_network *softmac_net = NULL;
427
428 list_for_each(list_ptr, &mac->network_list) {
429 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
430 if (softmac_net->essid.len == essid->len &&
431 !memcmp(softmac_net->essid.data, essid->data, essid->len))
432 return softmac_net;
433 }
434 return NULL;
435}
436
437/* Get a network from the list by ESSID with locking */
438struct ieee80211softmac_network *
439ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
440 struct ieee80211softmac_essid *essid)
441{
442 unsigned long flags;
443 struct ieee80211softmac_network *softmac_net = NULL;
444
445 spin_lock_irqsave(&mac->lock, flags);
446 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
447 spin_unlock_irqrestore(&mac->lock, flags);
448 return softmac_net;
449}
450
451MODULE_LICENSE("GPL");
452MODULE_AUTHOR("Johannes Berg");
453MODULE_AUTHOR("Joseph Jezak");
454MODULE_AUTHOR("Larry Finger");
455MODULE_AUTHOR("Danny van Dyk");
456MODULE_AUTHOR("Michael Buesch");
457MODULE_DESCRIPTION("802.11 software MAC");
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
new file mode 100644
index 000000000000..9ba7dbd161eb
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -0,0 +1,230 @@
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(void *sm);
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 */
119u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
120static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
121 return ieee80211softmac_lower_rate_delta(mac, rate, 1);
122}
123
124static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
125{
126 return ieee80211softmac_lower_rate_delta(mac, rate, 2);
127}
128
129
130/*** prototypes from _io.c */
131int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
132 void* ptrarg, u32 type, u32 arg);
133
134/*** prototypes from _auth.c */
135/* do these have to go into the public header? */
136int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
137int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
138
139/* for use by _module.c to assign to the callbacks */
140int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
141int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth);
142
143/*** prototypes from _assoc.c */
144void ieee80211softmac_assoc_work(void *d);
145int ieee80211softmac_handle_assoc_response(struct net_device * dev,
146 struct ieee80211_assoc_response * resp,
147 struct ieee80211_network * network);
148int ieee80211softmac_handle_disassoc(struct net_device * dev,
149 struct ieee80211_disassoc * disassoc);
150int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
151 struct ieee80211_reassoc_request * reassoc);
152void ieee80211softmac_assoc_timeout(void *d);
153
154/* some helper functions */
155static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
156{
157 return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
158 (sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
159 (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
160}
161
162static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
163{
164 return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
165 (sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
166 (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
167 ) || ieee80211softmac_scan_handlers_check_self(sm);
168}
169
170#define IEEE80211SOFTMAC_PROBE_DELAY HZ/2
171#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ)
172
173struct ieee80211softmac_network {
174 struct list_head list; /* List */
175 /* Network information copied from ieee80211_network */
176 u8 bssid[ETH_ALEN];
177 u8 channel;
178 struct ieee80211softmac_essid essid;
179
180 struct ieee80211softmac_ratesinfo supported_rates;
181
182 /* SoftMAC specific */
183 u16 authenticating:1, /* Status Flags */
184 authenticated:1,
185 auth_desynced_once:1;
186
187 u16 capabilities; /* Capabilities bitfield */
188 u8 challenge_len; /* Auth Challenge length */
189 char *challenge; /* Challenge Text */
190};
191
192/* structure used to keep track of networks we're auth'ing to */
193struct ieee80211softmac_auth_queue_item {
194 struct list_head list; /* List head */
195 struct ieee80211softmac_network *net; /* Network to auth */
196 struct ieee80211softmac_device *mac; /* SoftMAC device */
197 u8 retry; /* Retry limit */
198 u8 state; /* Auth State */
199 struct work_struct work; /* Work queue */
200};
201
202/* scanning information */
203struct ieee80211softmac_scaninfo {
204 u8 current_channel_idx,
205 number_channels;
206 struct ieee80211_channel *channels;
207 u8 started:1,
208 stop:1;
209 u8 skip_flags;
210 struct completion finished;
211 struct work_struct softmac_scan;
212};
213
214/* private event struct */
215struct ieee80211softmac_event {
216 struct list_head list;
217 int event_type;
218 void *event_context;
219 struct work_struct work;
220 notify_function_ptr fun;
221 void *context;
222 struct ieee80211softmac_device *mac;
223};
224
225void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
226void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
227int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
228 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
229
230#endif /* IEEE80211SOFTMAC_PRIV_H_ */
diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c
new file mode 100644
index 000000000000..bb9ab8b45d09
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_scan.c
@@ -0,0 +1,244 @@
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(void *d)
94{
95 int invalid_channel;
96 u8 current_channel_idx;
97 struct ieee80211softmac_device *sm = (struct ieee80211softmac_device *)d;
98 struct ieee80211softmac_scaninfo *si = sm->scaninfo;
99 unsigned long flags;
100
101 while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
102 current_channel_idx = si->current_channel_idx;
103 si->current_channel_idx++; /* go to the next channel */
104
105 invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
106
107 if (!invalid_channel) {
108 sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
109 // FIXME make this user configurable (active/passive)
110 if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
111 printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
112
113 /* also send directed management frame for the network we're looking for */
114 // TODO: is this if correct, or should we do this only if scanning from assoc request?
115 if (sm->associnfo.req_essid.len)
116 ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
117 schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
118 return;
119 } else {
120 dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
121 }
122 }
123
124 spin_lock_irqsave(&sm->lock, flags);
125 cancel_delayed_work(&si->softmac_scan);
126 si->started = 0;
127 spin_unlock_irqrestore(&sm->lock, flags);
128
129 dprintk(PFX "Scanning finished\n");
130 ieee80211softmac_scan_finished(sm);
131 complete_all(&sm->scaninfo->finished);
132}
133
134static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
135{
136 /* ugh. can we call this without having the spinlock held? */
137 struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
138 if (unlikely(!info))
139 return NULL;
140 INIT_WORK(&info->softmac_scan, ieee80211softmac_scan, mac);
141 init_completion(&info->finished);
142 return info;
143}
144
145int ieee80211softmac_start_scan_implementation(struct net_device *dev)
146{
147 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
148 unsigned long flags;
149
150 if (!(dev->flags & IFF_UP))
151 return -ENODEV;
152
153 assert(ieee80211softmac_scan_handlers_check_self(sm));
154 if (!ieee80211softmac_scan_handlers_check_self(sm))
155 return -EINVAL;
156
157 spin_lock_irqsave(&sm->lock, flags);
158 /* it looks like we need to hold the lock here
159 * to make sure we don't allocate two of these... */
160 if (unlikely(!sm->scaninfo))
161 sm->scaninfo = allocate_scaninfo(sm);
162 if (unlikely(!sm->scaninfo)) {
163 spin_unlock_irqrestore(&sm->lock, flags);
164 return -ENOMEM;
165 }
166
167 sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
168 if (0 /* not scanning in IEEE802.11b */)//TODO
169 sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
170 if (0 /* IEEE802.11a */) {//TODO
171 sm->scaninfo->channels = sm->ieee->geo.a;
172 sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
173 } else {
174 sm->scaninfo->channels = sm->ieee->geo.bg;
175 sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
176 }
177 dprintk(PFX "Start scanning with channel: %d\n", sm->scaninfo->channels[0].channel);
178 dprintk(PFX "Scanning %d channels\n", sm->scaninfo->number_channels);
179 sm->scaninfo->current_channel_idx = 0;
180 sm->scaninfo->started = 1;
181 sm->scaninfo->stop = 0;
182 INIT_COMPLETION(sm->scaninfo->finished);
183 schedule_work(&sm->scaninfo->softmac_scan);
184 spin_unlock_irqrestore(&sm->lock, flags);
185 return 0;
186}
187
188void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
189{
190 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
191 unsigned long flags;
192
193 assert(ieee80211softmac_scan_handlers_check_self(sm));
194 if (!ieee80211softmac_scan_handlers_check_self(sm))
195 return;
196
197 spin_lock_irqsave(&sm->lock, flags);
198 assert(sm->scaninfo != NULL);
199 if (sm->scaninfo) {
200 if (sm->scaninfo->started)
201 sm->scaninfo->stop = 1;
202 else
203 complete_all(&sm->scaninfo->finished);
204 }
205 spin_unlock_irqrestore(&sm->lock, flags);
206}
207
208void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
209{
210 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
211 unsigned long flags;
212
213 assert(ieee80211softmac_scan_handlers_check_self(sm));
214 if (!ieee80211softmac_scan_handlers_check_self(sm))
215 return;
216
217 spin_lock_irqsave(&sm->lock, flags);
218 if (!sm->scaninfo->started) {
219 spin_unlock_irqrestore(&sm->lock, flags);
220 return;
221 }
222 spin_unlock_irqrestore(&sm->lock, flags);
223 wait_for_completion(&sm->scaninfo->finished);
224}
225
226/* this is what drivers (that do scanning) call when they're done */
227void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
228{
229 unsigned long flags;
230
231 spin_lock_irqsave(&sm->lock, flags);
232 sm->scanning = 0;
233 spin_unlock_irqrestore(&sm->lock, flags);
234
235 if (sm->associnfo.bssvalid) {
236 struct ieee80211softmac_network *net;
237
238 net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
239 if (net)
240 sm->set_channel(sm->dev, net->channel);
241 }
242 ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
243}
244EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
new file mode 100644
index 000000000000..e1a9bc6d36ff
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -0,0 +1,412 @@
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
31
32int
33ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
34 struct iw_request_info *info,
35 union iwreq_data *data,
36 char *extra)
37{
38 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
39 return ieee80211softmac_start_scan(sm);
40}
41EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
42
43
44int
45ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
46 struct iw_request_info *info,
47 union iwreq_data *data,
48 char *extra)
49{
50 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
51 return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
52}
53EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
54
55int
56ieee80211softmac_wx_set_essid(struct net_device *net_dev,
57 struct iw_request_info *info,
58 union iwreq_data *data,
59 char *extra)
60{
61 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
62 int length = 0;
63 unsigned long flags;
64
65 spin_lock_irqsave(&sm->lock, flags);
66
67 sm->associnfo.static_essid = 0;
68
69 if (data->essid.flags && data->essid.length && extra /*required?*/) {
70 length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
71 if (length) {
72 memcpy(sm->associnfo.req_essid.data, extra, length);
73 sm->associnfo.static_essid = 1;
74 }
75 }
76 sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
77
78 /* set our requested ESSID length.
79 * If applicable, we have already copied the data in */
80 sm->associnfo.req_essid.len = length;
81
82 /* queue lower level code to do work (if necessary) */
83 schedule_work(&sm->associnfo.work);
84
85 spin_unlock_irqrestore(&sm->lock, flags);
86 return 0;
87}
88EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
89
90int
91ieee80211softmac_wx_get_essid(struct net_device *net_dev,
92 struct iw_request_info *info,
93 union iwreq_data *data,
94 char *extra)
95{
96 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
97 unsigned long flags;
98
99 /* avoid getting inconsistent information */
100 spin_lock_irqsave(&sm->lock, flags);
101 /* If all fails, return ANY (empty) */
102 data->essid.length = 0;
103 data->essid.flags = 0; /* active */
104
105 /* If we have a statically configured ESSID then return it */
106 if (sm->associnfo.static_essid) {
107 data->essid.length = sm->associnfo.req_essid.len;
108 data->essid.flags = 1; /* active */
109 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
110 }
111
112 /* If we're associating/associated, return that */
113 if (sm->associated || sm->associnfo.associating) {
114 data->essid.length = sm->associnfo.associate_essid.len;
115 data->essid.flags = 1; /* active */
116 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
117 }
118 spin_unlock_irqrestore(&sm->lock, flags);
119 return 0;
120}
121EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
122
123int
124ieee80211softmac_wx_set_rate(struct net_device *net_dev,
125 struct iw_request_info *info,
126 union iwreq_data *data,
127 char *extra)
128{
129 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
130 struct ieee80211_device *ieee = mac->ieee;
131 unsigned long flags;
132 s32 in_rate = data->bitrate.value;
133 u8 rate;
134 int is_ofdm = 0;
135 int err = -EINVAL;
136
137 if (in_rate == -1) {
138 /* automatic detect */
139 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
140 in_rate = 54000000;
141 else
142 in_rate = 11000000;
143 }
144
145 switch (in_rate) {
146 case 1000000:
147 rate = IEEE80211_CCK_RATE_1MB;
148 break;
149 case 2000000:
150 rate = IEEE80211_CCK_RATE_2MB;
151 break;
152 case 5500000:
153 rate = IEEE80211_CCK_RATE_5MB;
154 break;
155 case 11000000:
156 rate = IEEE80211_CCK_RATE_11MB;
157 break;
158 case 6000000:
159 rate = IEEE80211_OFDM_RATE_6MB;
160 is_ofdm = 1;
161 break;
162 case 9000000:
163 rate = IEEE80211_OFDM_RATE_9MB;
164 is_ofdm = 1;
165 break;
166 case 12000000:
167 rate = IEEE80211_OFDM_RATE_12MB;
168 is_ofdm = 1;
169 break;
170 case 18000000:
171 rate = IEEE80211_OFDM_RATE_18MB;
172 is_ofdm = 1;
173 break;
174 case 24000000:
175 rate = IEEE80211_OFDM_RATE_24MB;
176 is_ofdm = 1;
177 break;
178 case 36000000:
179 rate = IEEE80211_OFDM_RATE_36MB;
180 is_ofdm = 1;
181 break;
182 case 48000000:
183 rate = IEEE80211_OFDM_RATE_48MB;
184 is_ofdm = 1;
185 break;
186 case 54000000:
187 rate = IEEE80211_OFDM_RATE_54MB;
188 is_ofdm = 1;
189 break;
190 default:
191 goto out;
192 }
193
194 spin_lock_irqsave(&mac->lock, flags);
195
196 /* Check if correct modulation for this PHY. */
197 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
198 goto out_unlock;
199
200 mac->txrates.default_rate = rate;
201 mac->txrates.default_fallback = lower_rate(mac, rate);
202 err = 0;
203
204out_unlock:
205 spin_unlock_irqrestore(&mac->lock, flags);
206out:
207 return err;
208}
209EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
210
211int
212ieee80211softmac_wx_get_rate(struct net_device *net_dev,
213 struct iw_request_info *info,
214 union iwreq_data *data,
215 char *extra)
216{
217 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
218 unsigned long flags;
219 int err = -EINVAL;
220
221 spin_lock_irqsave(&mac->lock, flags);
222 switch (mac->txrates.default_rate) {
223 case IEEE80211_CCK_RATE_1MB:
224 data->bitrate.value = 1000000;
225 break;
226 case IEEE80211_CCK_RATE_2MB:
227 data->bitrate.value = 2000000;
228 break;
229 case IEEE80211_CCK_RATE_5MB:
230 data->bitrate.value = 5500000;
231 break;
232 case IEEE80211_CCK_RATE_11MB:
233 data->bitrate.value = 11000000;
234 break;
235 case IEEE80211_OFDM_RATE_6MB:
236 data->bitrate.value = 6000000;
237 break;
238 case IEEE80211_OFDM_RATE_9MB:
239 data->bitrate.value = 9000000;
240 break;
241 case IEEE80211_OFDM_RATE_12MB:
242 data->bitrate.value = 12000000;
243 break;
244 case IEEE80211_OFDM_RATE_18MB:
245 data->bitrate.value = 18000000;
246 break;
247 case IEEE80211_OFDM_RATE_24MB:
248 data->bitrate.value = 24000000;
249 break;
250 case IEEE80211_OFDM_RATE_36MB:
251 data->bitrate.value = 36000000;
252 break;
253 case IEEE80211_OFDM_RATE_48MB:
254 data->bitrate.value = 48000000;
255 break;
256 case IEEE80211_OFDM_RATE_54MB:
257 data->bitrate.value = 54000000;
258 break;
259 default:
260 assert(0);
261 goto out_unlock;
262 }
263 err = 0;
264out_unlock:
265 spin_unlock_irqrestore(&mac->lock, flags);
266
267 return err;
268}
269EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
270
271int
272ieee80211softmac_wx_get_wap(struct net_device *net_dev,
273 struct iw_request_info *info,
274 union iwreq_data *data,
275 char *extra)
276{
277 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
278 int err = 0;
279 unsigned long flags;
280
281 spin_lock_irqsave(&mac->lock, flags);
282 if (mac->associnfo.bssvalid)
283 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
284 else
285 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
286 data->ap_addr.sa_family = ARPHRD_ETHER;
287 spin_unlock_irqrestore(&mac->lock, flags);
288 return err;
289}
290EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
291
292int
293ieee80211softmac_wx_set_wap(struct net_device *net_dev,
294 struct iw_request_info *info,
295 union iwreq_data *data,
296 char *extra)
297{
298 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
299 static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
300 static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
301 unsigned long flags;
302
303 /* sanity check */
304 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
305 return -EINVAL;
306 }
307
308 spin_lock_irqsave(&mac->lock, flags);
309 if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
310 !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
311 schedule_work(&mac->associnfo.work);
312 goto out;
313 } else {
314 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
315 if (mac->associnfo.associating || mac->associated) {
316 /* bssid unchanged and associated or associating - just return */
317 goto out;
318 }
319 } else {
320 /* copy new value in data->ap_addr.sa_data to bssid */
321 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
322 }
323 /* queue associate if new bssid or (old one again and not associated) */
324 schedule_work(&mac->associnfo.work);
325 }
326
327out:
328 spin_unlock_irqrestore(&mac->lock, flags);
329 return 0;
330}
331EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
332
333int
334ieee80211softmac_wx_set_genie(struct net_device *dev,
335 struct iw_request_info *info,
336 union iwreq_data *wrqu,
337 char *extra)
338{
339 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
340 unsigned long flags;
341 int err = 0;
342 char *buf;
343 int i;
344
345 spin_lock_irqsave(&mac->lock, flags);
346 /* bleh. shouldn't be locked for that kmalloc... */
347
348 if (wrqu->data.length) {
349 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
350 /* this is an IE, so the length must be
351 * correct. Is it possible though that
352 * more than one IE is passed in?
353 */
354 err = -EINVAL;
355 goto out;
356 }
357 if (mac->wpa.IEbuflen <= wrqu->data.length) {
358 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
359 if (!buf) {
360 err = -ENOMEM;
361 goto out;
362 }
363 kfree(mac->wpa.IE);
364 mac->wpa.IE = buf;
365 mac->wpa.IEbuflen = wrqu->data.length;
366 }
367 memcpy(mac->wpa.IE, extra, wrqu->data.length);
368 dprintk(KERN_INFO PFX "generic IE set to ");
369 for (i=0;i<wrqu->data.length;i++)
370 dprintk("%.2x", mac->wpa.IE[i]);
371 dprintk("\n");
372 mac->wpa.IElen = wrqu->data.length;
373 } else {
374 kfree(mac->wpa.IE);
375 mac->wpa.IE = NULL;
376 mac->wpa.IElen = 0;
377 mac->wpa.IEbuflen = 0;
378 }
379
380 out:
381 spin_unlock_irqrestore(&mac->lock, flags);
382 return err;
383}
384EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
385
386int
387ieee80211softmac_wx_get_genie(struct net_device *dev,
388 struct iw_request_info *info,
389 union iwreq_data *wrqu,
390 char *extra)
391{
392 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
393 unsigned long flags;
394 int err = 0;
395 int space = wrqu->data.length;
396
397 spin_lock_irqsave(&mac->lock, flags);
398
399 wrqu->data.length = 0;
400
401 if (mac->wpa.IE && mac->wpa.IElen) {
402 wrqu->data.length = mac->wpa.IElen;
403 if (mac->wpa.IElen <= space)
404 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
405 else
406 err = -E2BIG;
407 }
408 spin_unlock_irqrestore(&mac->lock, flags);
409 return err;
410}
411EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
412