aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2006-03-22 22:55:57 -0500
committerJeff Garzik <jeff@garzik.org>2006-03-22 22:55:57 -0500
commitfa4fa40a990f8f4eff65476bef32007c154bbac0 (patch)
treec6e15822d1da2811ed004d3f8a4c72864adb5250 /net
parentb7ad6d75028d021362221d9b2db19fcff995c3f8 (diff)
parentfe0b06b123762ab620b5bee3dab1576ddddd0a7f (diff)
Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
Diffstat (limited to 'net')
-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.c403
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c376
-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.h239
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_scan.c237
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c412
13 files changed, 2852 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..c788377f5648
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -0,0 +1,403 @@
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 function_enter();
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 function_enter();
68
69 spin_lock_irqsave(&mac->lock, flags);
70 /* we might race against ieee80211softmac_handle_assoc_response,
71 * so make sure only one of us does something */
72 if (!mac->associnfo.associating) {
73 spin_unlock_irqrestore(&mac->lock, flags);
74 return;
75 }
76 mac->associnfo.associating = 0;
77 mac->associnfo.bssvalid = 0;
78 mac->associated = 0;
79 spin_unlock_irqrestore(&mac->lock, flags);
80
81 dprintk(KERN_INFO PFX "assoc request timed out!\n");
82 /* FIXME: we need to know the network here. that requires a bit of restructuring */
83 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
84}
85
86/* Sends out a disassociation request to the desired AP */
87static void
88ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
89{
90 unsigned long flags;
91 struct ieee80211softmac_network *found;
92 function_enter();
93
94 if (mac->associnfo.bssvalid && mac->associated) {
95 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
96 if (found)
97 ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
98 } else if (mac->associnfo.associating) {
99 cancel_delayed_work(&mac->associnfo.timeout);
100 }
101
102 /* Change our state */
103 spin_lock_irqsave(&mac->lock, flags);
104 /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */
105 mac->associated = 0;
106 mac->associnfo.associating = 0;
107 spin_unlock_irqrestore(&mac->lock, flags);
108}
109
110static inline int
111we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
112{
113 int idx, search, found;
114 u8 rate, search_rate;
115
116 for (idx = 0; idx < (from_len); idx++) {
117 rate = (from)[idx];
118 if (!(rate & IEEE80211_BASIC_RATE_MASK))
119 continue;
120 found = 0;
121 rate &= ~IEEE80211_BASIC_RATE_MASK;
122 for (search = 0; search < mac->ratesinfo.count; search++) {
123 search_rate = mac->ratesinfo.rates[search];
124 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
125 if (rate == search_rate) {
126 found = 1;
127 break;
128 }
129 }
130 if (!found)
131 return 0;
132 }
133 return 1;
134}
135
136static int
137network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
138{
139 /* we cannot associate to networks whose name we don't know */
140 if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
141 return 0;
142 /* do not associate to a network whose BSSBasicRateSet we cannot support */
143 if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
144 return 0;
145 /* do we really need to check the ex rates? */
146 if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
147 return 0;
148
149 /* if 'ANY' network requested, take any that doesn't have privacy enabled */
150 if (mac->associnfo.req_essid.len == 0
151 && !(net->capability & WLAN_CAPABILITY_PRIVACY))
152 return 1;
153 if (net->ssid_len != mac->associnfo.req_essid.len)
154 return 0;
155 if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
156 return 1;
157 return 0;
158}
159
160static void
161ieee80211softmac_assoc_notify(struct net_device *dev, void *context)
162{
163 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
164 ieee80211softmac_assoc_work((void*)mac);
165}
166
167/* This function is called to handle userspace requests (asynchronously) */
168void
169ieee80211softmac_assoc_work(void *d)
170{
171 struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
172 struct ieee80211softmac_network *found = NULL;
173 struct ieee80211_network *net = NULL, *best = NULL;
174 unsigned long flags;
175
176 function_enter();
177
178 /* meh */
179 if (mac->associated)
180 ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
181
182 /* try to find the requested network in our list, if we found one already */
183 if (mac->associnfo.bssvalid)
184 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
185
186 /* Search the ieee80211 networks for this network if we didn't find it by bssid,
187 * but only if we've scanned at least once (to get a better list of networks to
188 * select from). If we have not scanned before, the !found logic below will be
189 * invoked and will scan. */
190 if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT))
191 {
192 s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning
193 because it cannot follow the best pointer logic. */
194 spin_lock_irqsave(&mac->ieee->lock, flags);
195 list_for_each_entry(net, &mac->ieee->network_list, list) {
196 /* we're supposed to find the network with
197 * the best signal here, as we're asked to join
198 * any network with a specific ESSID, and many
199 * different ones could have that.
200 *
201 * I'll for now just go with the reported rssi.
202 *
203 * We also should take into account the rateset
204 * here to find the best BSSID to try.
205 */
206 if (network_matches_request(mac, net)) {
207 if (!best) {
208 best = net;
209 rssi = best->stats.rssi;
210 continue;
211 }
212 /* we already had a matching network, so
213 * compare their properties to get the
214 * better of the two ... (see above)
215 */
216 if (rssi < net->stats.rssi) {
217 best = net;
218 rssi = best->stats.rssi;
219 }
220 }
221 }
222 /* if we unlock here, we might get interrupted and the `best'
223 * pointer could go stale */
224 if (best) {
225 found = ieee80211softmac_create_network(mac, best);
226 /* if found is still NULL, then we got -ENOMEM somewhere */
227 if (found)
228 ieee80211softmac_add_network(mac, found);
229 }
230 spin_unlock_irqrestore(&mac->ieee->lock, flags);
231 }
232
233 if (!found) {
234 if (mac->associnfo.scan_retry > 0) {
235 spin_lock_irqsave(&mac->lock, flags);
236 mac->associnfo.scan_retry--;
237 spin_unlock_irqrestore(&mac->lock, flags);
238
239 /* We know of no such network. Let's scan.
240 * NB: this also happens if we had no memory to copy the network info...
241 * Maybe we can hope to have more memory after scanning finishes ;)
242 */
243 dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
244 ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL);
245 if (ieee80211softmac_start_scan(mac))
246 dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
247 return;
248 }
249 else {
250 spin_lock_irqsave(&mac->lock, flags);
251 mac->associnfo.associating = 0;
252 mac->associated = 0;
253 spin_unlock_irqrestore(&mac->lock, flags);
254
255 dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
256 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
257 return;
258 }
259 }
260
261 mac->associnfo.bssvalid = 1;
262 memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
263 /* copy the ESSID for displaying it */
264 mac->associnfo.associate_essid.len = found->essid.len;
265 memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
266
267 /* we found a network! authenticate (if necessary) and associate to it. */
268 if (!found->authenticated) {
269 /* This relies on the fact that _auth_req only queues the work,
270 * otherwise adding the notification would be racy. */
271 if (!ieee80211softmac_auth_req(mac, found)) {
272 dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
273 ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL);
274 } else {
275 printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
276 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
277 }
278 return;
279 }
280 /* finally! now we can start associating */
281 ieee80211softmac_assoc(mac, found);
282}
283
284/* call this to do whatever is necessary when we're associated */
285static void
286ieee80211softmac_associated(struct ieee80211softmac_device *mac,
287 struct ieee80211_assoc_response * resp,
288 struct ieee80211softmac_network *net)
289{
290 mac->associnfo.associating = 0;
291 mac->associated = 1;
292 if (mac->set_bssid_filter)
293 mac->set_bssid_filter(mac->dev, net->bssid);
294 memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
295 netif_carrier_on(mac->dev);
296
297 mac->association_id = le16_to_cpup(&resp->aid);
298}
299
300/* received frame handling functions */
301int
302ieee80211softmac_handle_assoc_response(struct net_device * dev,
303 struct ieee80211_assoc_response * resp,
304 struct ieee80211_network * _ieee80211_network_do_not_use)
305{
306 /* NOTE: the network parameter has to be ignored by
307 * this code because it is the ieee80211's pointer
308 * to the struct, not ours (we made a copy)
309 */
310 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
311 u16 status = le16_to_cpup(&resp->status);
312 struct ieee80211softmac_network *network = NULL;
313 unsigned long flags;
314
315 spin_lock_irqsave(&mac->lock, flags);
316
317 if (!mac->associnfo.associating) {
318 /* we race against the timeout function, so make sure
319 * only one of us can do work */
320 spin_unlock_irqrestore(&mac->lock, flags);
321 return 0;
322 }
323 network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
324
325 /* someone sending us things without us knowing him? Ignore. */
326 if (!network) {
327 dprintk(KERN_INFO PFX "Received unrequested assocation response from " MAC_FMT "\n", MAC_ARG(resp->header.addr3));
328 spin_unlock_irqrestore(&mac->lock, flags);
329 return 0;
330 }
331
332 /* now that we know it was for us, we can cancel the timeout */
333 cancel_delayed_work(&mac->associnfo.timeout);
334
335 switch (status) {
336 case 0:
337 dprintk(KERN_INFO PFX "associated!\n");
338 ieee80211softmac_associated(mac, resp, network);
339 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
340 break;
341 case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
342 if (!network->auth_desynced_once) {
343 /* there seem to be a few rare cases where our view of
344 * the world is obscured, or buggy APs that don't DEAUTH
345 * us properly. So we handle that, but allow it only once.
346 */
347 printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
348 network->authenticated = 0;
349 /* we don't want to do this more than once ... */
350 network->auth_desynced_once = 1;
351 schedule_work(&mac->associnfo.work);
352 break;
353 }
354 default:
355 dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
356 mac->associnfo.associating = 0;
357 mac->associnfo.bssvalid = 0;
358 mac->associated = 0;
359 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
360 }
361
362 spin_unlock_irqrestore(&mac->lock, flags);
363 return 0;
364}
365
366int
367ieee80211softmac_handle_disassoc(struct net_device * dev,
368 struct ieee80211_disassoc *disassoc)
369{
370 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
371 unsigned long flags;
372 if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
373 return 0;
374 if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
375 return 0;
376 dprintk(KERN_INFO PFX "got disassoc frame\n");
377 netif_carrier_off(dev);
378 spin_lock_irqsave(&mac->lock, flags);
379 mac->associnfo.bssvalid = 0;
380 mac->associated = 0;
381 schedule_work(&mac->associnfo.work);
382 spin_unlock_irqrestore(&mac->lock, flags);
383
384 return 0;
385}
386
387int
388ieee80211softmac_handle_reassoc_req(struct net_device * dev,
389 struct ieee80211_reassoc_request * resp)
390{
391 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
392 struct ieee80211softmac_network *network;
393
394 function_enter();
395
396 network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
397 if (!network) {
398 dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
399 return 0;
400 }
401 ieee80211softmac_assoc(mac, network);
402 return 0;
403}
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
new file mode 100644
index 000000000000..ac09e0c836ee
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -0,0 +1,376 @@
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 function_enter();
40
41 if (net->authenticating)
42 return 0;
43
44 /* Add the network if it's not already added */
45 ieee80211softmac_add_network(mac, net);
46
47 dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid));
48 /* Queue the auth request */
49 auth = (struct ieee80211softmac_auth_queue_item *)
50 kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
51 if(auth == NULL)
52 return -ENOMEM;
53
54 auth->net = net;
55 auth->mac = mac;
56 auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
57 auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
58 INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth);
59
60 /* Lock (for list) */
61 spin_lock_irqsave(&mac->lock, flags);
62
63 /* add to list */
64 list_add_tail(&auth->list, &mac->auth_queue);
65 schedule_work(&auth->work);
66 spin_unlock_irqrestore(&mac->lock, flags);
67
68 return 0;
69}
70
71
72/* Sends an auth request to the desired AP and handles timeouts */
73static void
74ieee80211softmac_auth_queue(void *data)
75{
76 struct ieee80211softmac_device *mac;
77 struct ieee80211softmac_auth_queue_item *auth;
78 struct ieee80211softmac_network *net;
79 unsigned long flags;
80
81 function_enter();
82
83 auth = (struct ieee80211softmac_auth_queue_item *)data;
84 net = auth->net;
85 mac = auth->mac;
86
87 if(auth->retry > 0) {
88 /* Switch to correct channel for this network */
89 mac->set_channel(mac->dev, net->channel);
90
91 /* Lock and set flags */
92 spin_lock_irqsave(&mac->lock, flags);
93 net->authenticated = 0;
94 net->authenticating = 1;
95 /* add a timeout call so we eventually give up waiting for an auth reply */
96 schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
97 auth->retry--;
98 spin_unlock_irqrestore(&mac->lock, flags);
99 if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
100 dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid));
101 else
102 dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid));
103 return;
104 }
105
106 printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid));
107 /* Remove this item from the queue */
108 spin_lock_irqsave(&mac->lock, flags);
109 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
110 cancel_delayed_work(&auth->work); /* just to make sure... */
111 list_del(&auth->list);
112 spin_unlock_irqrestore(&mac->lock, flags);
113 /* Free it */
114 kfree(auth);
115}
116
117/* Handle the auth response from the AP
118 * This should be registered with ieee80211 as handle_auth
119 */
120int
121ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
122{
123
124 struct list_head *list_ptr;
125 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
126 struct ieee80211softmac_auth_queue_item *aq = NULL;
127 struct ieee80211softmac_network *net = NULL;
128 unsigned long flags;
129 u8 * data;
130
131 function_enter();
132
133 /* Find correct auth queue item */
134 spin_lock_irqsave(&mac->lock, flags);
135 list_for_each(list_ptr, &mac->auth_queue) {
136 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
137 net = aq->net;
138 if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
139 break;
140 else
141 aq = NULL;
142 }
143 spin_unlock_irqrestore(&mac->lock, flags);
144
145 /* Make sure that we've got an auth queue item for this request */
146 if(aq == NULL)
147 {
148 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2));
149 /* Error #? */
150 return -1;
151 }
152
153 /* Check for out of order authentication */
154 if(!net->authenticating)
155 {
156 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2));
157 return -1;
158 }
159
160 /* Parse the auth packet */
161 switch(auth->algorithm) {
162 case WLAN_AUTH_OPEN:
163 /* Check the status code of the response */
164
165 switch(auth->status) {
166 case WLAN_STATUS_SUCCESS:
167 /* Update the status to Authenticated */
168 spin_lock_irqsave(&mac->lock, flags);
169 net->authenticating = 0;
170 net->authenticated = 1;
171 spin_unlock_irqrestore(&mac->lock, flags);
172
173 /* Send event */
174 printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid));
175 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
176 break;
177 default:
178 /* Lock and reset flags */
179 spin_lock_irqsave(&mac->lock, flags);
180 net->authenticated = 0;
181 net->authenticating = 0;
182 spin_unlock_irqrestore(&mac->lock, flags);
183
184 printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n",
185 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
186 /* Count the error? */
187 break;
188 }
189 goto free_aq;
190 break;
191 case WLAN_AUTH_SHARED_KEY:
192 /* Figure out where we are in the process */
193 switch(auth->transaction) {
194 case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
195 /* Check to make sure we have a challenge IE */
196 data = (u8 *)auth->info_element;
197 if(*data++ != MFIE_TYPE_CHALLENGE){
198 printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
199 break;
200 }
201 /* Save the challenge */
202 spin_lock_irqsave(&mac->lock, flags);
203 net->challenge_len = *data++;
204 if(net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
205 net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
206 if(net->challenge != NULL)
207 kfree(net->challenge);
208 net->challenge = kmalloc(net->challenge_len, GFP_ATOMIC);
209 memcpy(net->challenge, data, net->challenge_len);
210 aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
211 spin_unlock_irqrestore(&mac->lock, flags);
212
213 /* Switch to correct channel for this network */
214 mac->set_channel(mac->dev, net->channel);
215
216 /* Send our response (How to encrypt?) */
217 ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
218 break;
219 case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
220 /* Check the status code of the response */
221 switch(auth->status) {
222 case WLAN_STATUS_SUCCESS:
223 /* Update the status to Authenticated */
224 spin_lock_irqsave(&mac->lock, flags);
225 net->authenticating = 0;
226 net->authenticated = 1;
227 spin_unlock_irqrestore(&mac->lock, flags);
228 printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n",
229 MAC_ARG(net->bssid));
230 break;
231 default:
232 printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n",
233 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
234 /* Lock and reset flags */
235 spin_lock_irqsave(&mac->lock, flags);
236 net->authenticating = 0;
237 net->authenticated = 0;
238 spin_unlock_irqrestore(&mac->lock, flags);
239 /* Count the error? */
240 break;
241 }
242 goto free_aq;
243 break;
244 default:
245 printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
246 break;
247 }
248 goto free_aq;
249 break;
250 default:
251 /* ERROR */
252 goto free_aq;
253 break;
254 }
255 return 0;
256free_aq:
257 /* Cancel the timeout */
258 spin_lock_irqsave(&mac->lock, flags);
259 cancel_delayed_work(&aq->work);
260 /* Remove this item from the queue */
261 list_del(&aq->list);
262 spin_unlock_irqrestore(&mac->lock, flags);
263
264 /* Free it */
265 kfree(aq);
266 return 0;
267}
268
269/*
270 * Handle deauthorization
271 */
272static void
273ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
274 struct ieee80211softmac_network *net)
275{
276 struct ieee80211softmac_auth_queue_item *aq = NULL;
277 struct list_head *list_ptr;
278 unsigned long flags;
279
280 function_enter();
281
282 /* Lock and reset status flags */
283 spin_lock_irqsave(&mac->lock, flags);
284 net->authenticating = 0;
285 net->authenticated = 0;
286
287 /* Find correct auth queue item, if it exists */
288 list_for_each(list_ptr, &mac->auth_queue) {
289 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
290 if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
291 break;
292 else
293 aq = NULL;
294 }
295
296 /* Cancel pending work */
297 if(aq != NULL)
298 /* Not entirely safe? What about running work? */
299 cancel_delayed_work(&aq->work);
300
301 /* Free our network ref */
302 ieee80211softmac_del_network_locked(mac, net);
303 if(net->challenge != NULL)
304 kfree(net->challenge);
305 kfree(net);
306
307 /* can't transmit data right now... */
308 netif_carrier_off(mac->dev);
309 /* let's try to re-associate */
310 schedule_work(&mac->associnfo.work);
311 spin_unlock_irqrestore(&mac->lock, flags);
312}
313
314/*
315 * Sends a deauth request to the desired AP
316 */
317int
318ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
319 struct ieee80211softmac_network *net, int reason)
320{
321 int ret;
322
323 function_enter();
324
325 /* Make sure the network is authenticated */
326 if (!net->authenticated)
327 {
328 printkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
329 /* Error okay? */
330 return -EPERM;
331 }
332
333 /* Send the de-auth packet */
334 if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
335 return ret;
336
337 ieee80211softmac_deauth_from_net(mac, net);
338 return 0;
339}
340
341/*
342 * This should be registered with ieee80211 as handle_deauth
343 */
344int
345ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth)
346{
347
348 struct ieee80211softmac_network *net = NULL;
349 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
350
351 function_enter();
352
353 if (!deauth) {
354 dprintk("deauth without deauth packet. eek!\n");
355 return 0;
356 }
357
358 net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2);
359
360 if (net == NULL) {
361 printkl(KERN_DEBUG PFX "Received deauthentication packet from "MAC_FMT", but that network is unknown.\n",
362 MAC_ARG(deauth->header.addr2));
363 return 0;
364 }
365
366 /* Make sure the network is authenticated */
367 if(!net->authenticated)
368 {
369 printkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
370 /* Error okay? */
371 return -EPERM;
372 }
373
374 ieee80211softmac_deauth_from_net(mac, net);
375 return 0;
376}
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..258da14937be
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -0,0 +1,239 @@
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#ifdef function_enter
79# undef function_enter
80#endif
81#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
82# define function_enter() do { printk(KERN_DEBUG PFX "%s:%d:%s()\n", __FILE__, __LINE__, __FUNCTION__); } while (0)
83#else
84# define function_enter() do { /* nothing */ } while (0)
85#endif
86
87/* private definitions and prototypes */
88
89/*** prototypes from _scan.c */
90void ieee80211softmac_scan(void *sm);
91/* for internal use if scanning is needed */
92int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
93void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
94void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac);
95
96/* for use by _module.c to assign to the callbacks */
97int ieee80211softmac_start_scan_implementation(struct net_device *dev);
98void ieee80211softmac_stop_scan_implementation(struct net_device *dev);
99void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev);
100
101/*** Network prototypes from _module.c */
102struct ieee80211softmac_network * ieee80211softmac_create_network(
103 struct ieee80211softmac_device *mac, struct ieee80211_network *net);
104void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
105 struct ieee80211softmac_network *net);
106void ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
107 struct ieee80211softmac_network *net);
108void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
109 struct ieee80211softmac_network *net);
110void ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
111 struct ieee80211softmac_network *net);
112struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked(
113 struct ieee80211softmac_device *mac, u8 *ea);
114struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid(
115 struct ieee80211softmac_device *mac, u8 *ea);
116struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked(
117 struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
118struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid(
119 struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
120struct ieee80211softmac_network *
121ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
122 struct ieee80211softmac_essid *essid);
123struct ieee80211softmac_network *
124ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
125 struct ieee80211softmac_essid *essid);
126
127/* Rates related */
128u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
129static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
130 return ieee80211softmac_lower_rate_delta(mac, rate, 1);
131}
132
133static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
134{
135 return ieee80211softmac_lower_rate_delta(mac, rate, 2);
136}
137
138
139/*** prototypes from _io.c */
140int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
141 void* ptrarg, u32 type, u32 arg);
142
143/*** prototypes from _auth.c */
144/* do these have to go into the public header? */
145int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
146int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
147
148/* for use by _module.c to assign to the callbacks */
149int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
150int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth);
151
152/*** prototypes from _assoc.c */
153void ieee80211softmac_assoc_work(void *d);
154int ieee80211softmac_handle_assoc_response(struct net_device * dev,
155 struct ieee80211_assoc_response * resp,
156 struct ieee80211_network * network);
157int ieee80211softmac_handle_disassoc(struct net_device * dev,
158 struct ieee80211_disassoc * disassoc);
159int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
160 struct ieee80211_reassoc_request * reassoc);
161void ieee80211softmac_assoc_timeout(void *d);
162
163/* some helper functions */
164static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
165{
166 return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
167 (sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
168 (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
169}
170
171static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
172{
173 return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
174 (sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
175 (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
176 ) || ieee80211softmac_scan_handlers_check_self(sm);
177}
178
179#define IEEE80211SOFTMAC_PROBE_DELAY HZ/2
180#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ)
181
182struct ieee80211softmac_network {
183 struct list_head list; /* List */
184 /* Network information copied from ieee80211_network */
185 u8 bssid[ETH_ALEN];
186 u8 channel;
187 struct ieee80211softmac_essid essid;
188
189 struct ieee80211softmac_ratesinfo supported_rates;
190
191 /* SoftMAC specific */
192 u16 authenticating:1, /* Status Flags */
193 authenticated:1,
194 auth_desynced_once:1;
195
196 u16 capabilities; /* Capabilities bitfield */
197 u8 challenge_len; /* Auth Challenge length */
198 char *challenge; /* Challenge Text */
199};
200
201/* structure used to keep track of networks we're auth'ing to */
202struct ieee80211softmac_auth_queue_item {
203 struct list_head list; /* List head */
204 struct ieee80211softmac_network *net; /* Network to auth */
205 struct ieee80211softmac_device *mac; /* SoftMAC device */
206 u8 retry; /* Retry limit */
207 u8 state; /* Auth State */
208 struct work_struct work; /* Work queue */
209};
210
211/* scanning information */
212struct ieee80211softmac_scaninfo {
213 u8 current_channel_idx,
214 number_channels;
215 struct ieee80211_channel *channels;
216 u8 started:1,
217 stop:1;
218 u8 skip_flags;
219 struct completion finished;
220 struct work_struct softmac_scan;
221};
222
223/* private event struct */
224struct ieee80211softmac_event {
225 struct list_head list;
226 int event_type;
227 void *event_context;
228 struct work_struct work;
229 notify_function_ptr fun;
230 void *context;
231 struct ieee80211softmac_device *mac;
232};
233
234void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
235void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
236int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
237 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
238
239#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..290ddb0951d6
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_scan.c
@@ -0,0 +1,237 @@
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 ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
236}
237EXPORT_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