aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2006-01-04 10:32:16 -0500
committerJohn W. Linville <linville@tuxdriver.com>2006-03-22 22:16:50 -0500
commit370121e5190a86a2d8a717ecd6f33028c7dc6fd4 (patch)
tree2bd809d8dea7a831f9c47d06572e98194bfc0ccc
parent1c2e02750b992703a8a18634e08b04353face243 (diff)
[PATCH] wireless: Add softmac layer to the kernel
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/net/ieee80211softmac.h269
-rw-r--r--include/net/ieee80211softmac_wx.h66
-rw-r--r--net/ieee80211/Kconfig1
-rw-r--r--net/ieee80211/softmac/Kconfig9
-rw-r--r--net/ieee80211/softmac/Makefile9
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c356
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c348
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_event.c135
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_io.c474
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c441
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_priv.h206
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_scan.c216
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c390
13 files changed, 2920 insertions, 0 deletions
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
new file mode 100644
index 000000000000..0b5f2df29f02
--- /dev/null
+++ b/include/net/ieee80211softmac.h
@@ -0,0 +1,269 @@
1#ifndef IEEE80211SOFTMAC_H_
2#define IEEE80211SOFTMAC_H_
3
4#include <linux/kernel.h>
5#include <linux/spinlock.h>
6#include <linux/workqueue.h>
7#include <linux/list.h>
8#include <net/ieee80211.h>
9
10/* Once the API is considered more or less stable,
11 * this should be incremented on API incompatible changes.
12 */
13#define IEEE80211SOFTMAC_API 0
14
15#define IEEE80211SOFTMAC_MAX_RATES_LEN 8
16#define IEEE80211SOFTMAC_MAX_EX_RATES_LEN 255
17
18struct ieee80211softmac_ratesinfo {
19 u8 count;
20 u8 rates[IEEE80211SOFTMAC_MAX_RATES_LEN + IEEE80211SOFTMAC_MAX_EX_RATES_LEN];
21};
22
23/* internal structures */
24struct ieee80211softmac_network;
25struct ieee80211softmac_scaninfo;
26
27struct ieee80211softmac_essid {
28 u8 len;
29 char data[IW_ESSID_MAX_SIZE+1];
30};
31
32struct ieee80211softmac_wpa {
33 char *IE;
34 int IElen;
35 int IEbuflen;
36};
37
38/*
39 * Information about association
40 *
41 * Do we need a lock for this?
42 * We only ever use this structure inlined
43 * into our global struct. I've used its lock,
44 * but maybe we need a local one here?
45 */
46struct ieee80211softmac_assoc_info {
47 /*
48 * This is the requested ESSID. It is written
49 * only by the WX handlers.
50 *
51 */
52 struct ieee80211softmac_essid req_essid;
53 /*
54 * the ESSID of the network we're currently
55 * associated (or trying) to. This is
56 * updated to the network's actual ESSID
57 * even if the requested ESSID was 'ANY'
58 */
59 struct ieee80211softmac_essid associate_essid;
60
61 /* BSSID we're trying to associate to */
62 char bssid[ETH_ALEN];
63
64 /* some flags.
65 * static_essid is valid if the essid is constant,
66 * this is for use by the wx handlers only.
67 *
68 * associating is true, if the network has been
69 * auth'ed on and we are in the process of associating.
70 *
71 * bssvalid is true if we found a matching network
72 * and saved it's BSSID into the bssid above.
73 */
74 u8 static_essid:1,
75 associating:1,
76 bssvalid:1;
77
78 /* Scan retries remaining */
79 int scan_retry;
80
81 struct work_struct work;
82 struct work_struct timeout;
83};
84
85enum {
86 IEEE80211SOFTMAC_AUTH_OPEN_REQUEST = 1,
87 IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE = 2,
88};
89
90enum {
91 IEEE80211SOFTMAC_AUTH_SHARED_REQUEST = 1,
92 IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE = 2,
93 IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE = 3,
94 IEEE80211SOFTMAC_AUTH_SHARED_PASS = 4,
95};
96
97/* We should make these tunable
98 * AUTH_TIMEOUT seems really long, but that's what it is in BSD */
99#define IEEE80211SOFTMAC_AUTH_TIMEOUT (12 * HZ)
100#define IEEE80211SOFTMAC_AUTH_RETRY_LIMIT 5
101#define IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT 3
102
103struct ieee80211softmac_txrates {
104 /* The Bit-Rate to be used for multicast frames. */
105 u8 mcast_rate;
106 /* The Bit-Rate to be used for multicast fallback
107 * (If the device supports fallback and hardware-retry)
108 */
109 u8 mcast_fallback;
110 /* The Bit-Rate to be used for any other (normal) data packet. */
111 u8 default_rate;
112 /* The Bit-Rate to be used for default fallback
113 * (If the device supports fallback and hardware-retry)
114 */
115 u8 default_fallback;
116};
117
118/* Bits for txrates_change callback. */
119#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT (1 << 0) /* default_rate */
120#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK (1 << 1) /* default_fallback */
121#define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */
122#define IEEE80211SOFTMAC_TXRATECHG_MCAST_FBACK (1 << 3) /* mcast_fallback */
123
124struct ieee80211softmac_device {
125 /* 802.11 structure for data stuff */
126 struct ieee80211_device *ieee;
127 struct net_device *dev;
128
129 /* only valid if associated, then holds the Association ID */
130 u16 association_id;
131
132 /* the following methods are callbacks that the driver
133 * using this framework has to assign
134 */
135
136 /* always assign these */
137 void (*set_bssid_filter)(struct net_device *dev, const u8 *bssid);
138 void (*set_channel)(struct net_device *dev, u8 channel);
139
140 /* assign if you need it, informational only */
141 void (*link_change)(struct net_device *dev);
142
143 /* If the hardware can do scanning, assign _all_ three of these callbacks.
144 * When the scan finishes, call ieee80211softmac_scan_finished().
145 */
146
147 /* when called, start_scan is guaranteed to not be called again
148 * until you call ieee80211softmac_scan_finished.
149 * Return 0 if scanning could start, error otherwise.
150 * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_start_scan */
151 int (*start_scan)(struct net_device *dev);
152 /* this should block until after ieee80211softmac_scan_finished was called
153 * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_wait_for_scan */
154 void (*wait_for_scan)(struct net_device *dev);
155 /* stop_scan aborts a scan, but is asynchronous.
156 * if you want to wait for it too, use wait_for_scan
157 * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_stop_scan */
158 void (*stop_scan)(struct net_device *dev);
159
160 /* we'll need something about beacons here too, for AP or ad-hoc modes */
161
162 /* Transmission rates to be used by the driver.
163 * The SoftMAC figures out the best possible rates.
164 * The driver just needs to read them.
165 */
166 struct ieee80211softmac_txrates txrates;
167 /* If the driver needs to do stuff on TX rate changes, assign this callback. */
168 void (*txrates_change)(struct net_device *dev,
169 u32 changes, /* see IEEE80211SOFTMAC_TXRATECHG flags */
170 const struct ieee80211softmac_txrates *rates_before_change);
171
172 /* private stuff follows */
173 /* this lock protects this structure */
174 spinlock_t lock;
175
176 /* couple of flags */
177 u8 scanning:1, /* protects scanning from being done multiple times at once */
178 associated:1;
179
180 /* workquere for scannning, ... */
181 struct workqueue_struct *workqueue;
182
183 struct ieee80211softmac_scaninfo *scaninfo;
184 struct ieee80211softmac_assoc_info associnfo;
185
186 struct list_head auth_queue;
187 struct list_head events;
188
189 struct ieee80211softmac_ratesinfo ratesinfo;
190 int txrate_badness;
191
192 /* WPA stuff */
193 struct ieee80211softmac_wpa wpa;
194
195 /* we need to keep a list of network structs we copied */
196 struct list_head network_list;
197
198 /* This must be the last item so that it points to the data
199 * allocated beyond this structure by alloc_ieee80211 */
200 u8 priv[0];
201};
202
203extern void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm);
204
205static inline void * ieee80211softmac_priv(struct net_device *dev)
206{
207 return ((struct ieee80211softmac_device *)ieee80211_priv(dev))->priv;
208}
209
210extern struct net_device * alloc_ieee80211softmac(int sizeof_priv);
211extern void free_ieee80211softmac(struct net_device *dev);
212
213/* Call this function if you detect a lost TX fragment.
214 * (If the device indicates failure of ACK RX, for example.)
215 * It is wise to call this function if you are able to detect lost packets,
216 * because it contributes to the TX Rates auto adjustment.
217 */
218extern void ieee80211softmac_fragment_lost(struct net_device *dev,
219 u16 wireless_sequence_number);
220/* Call this function before _start to tell the softmac what rates
221 * the hw supports. The rates parameter is copied, so you can
222 * free it right after calling this function.
223 * Note that the rates need to be sorted. */
224extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
225
226/* Start the SoftMAC. Call this after you initialized the device
227 * and it is ready to run.
228 */
229extern void ieee80211softmac_start(struct net_device *dev);
230/* Stop the SoftMAC. Call this before you shutdown the device. */
231extern void ieee80211softmac_stop(struct net_device *dev);
232
233/*
234 * Event system
235 */
236
237/* valid event types */
238#define IEEE80211SOFTMAC_EVENT_ANY -1 /*private use only*/
239#define IEEE80211SOFTMAC_EVENT_SCAN_FINISHED 0
240#define IEEE80211SOFTMAC_EVENT_ASSOCIATED 1
241#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED 2
242#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT 3
243#define IEEE80211SOFTMAC_EVENT_AUTHENTICATED 4
244#define IEEE80211SOFTMAC_EVENT_AUTH_FAILED 5
245#define IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT 6
246#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND 7
247/* keep this updated! */
248#define IEEE80211SOFTMAC_EVENT_LAST 7
249/*
250 * If you want to be notified of certain events, you can call
251 * ieee80211softmac_notify[_atomic] with
252 * - event set to one of the constants below
253 * - fun set to a function pointer of the appropriate type
254 * - context set to the context data you want passed
255 * The return value is 0, or an error.
256 */
257typedef void (*notify_function_ptr)(struct net_device *dev, void *context);
258
259#define ieee80211softmac_notify(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_KERNEL);
260#define ieee80211softmac_notify_atomic(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_ATOMIC);
261
262extern int ieee80211softmac_notify_gfp(struct net_device *dev,
263 int event, notify_function_ptr fun, void *context, gfp_t gfp_mask);
264
265/* To clear pending work (for ifconfig down, etc.) */
266extern void
267ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm);
268
269#endif /* IEEE80211SOFTMAC_H_ */
diff --git a/include/net/ieee80211softmac_wx.h b/include/net/ieee80211softmac_wx.h
new file mode 100644
index 000000000000..165ea4c78ee0
--- /dev/null
+++ b/include/net/ieee80211softmac_wx.h
@@ -0,0 +1,66 @@
1#ifndef _IEEE80211SOFTMAC_WX_H
2#define _IEEE80211SOFTMAC_WX_H
3
4#include <net/ieee80211softmac.h>
5#include <net/iw_handler.h>
6
7extern int
8ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
9 struct iw_request_info *info,
10 union iwreq_data *data,
11 char *extra);
12
13extern int
14ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
15 struct iw_request_info *info,
16 union iwreq_data *data,
17 char *extra);
18
19extern int
20ieee80211softmac_wx_set_essid(struct net_device *net_dev,
21 struct iw_request_info *info,
22 union iwreq_data *data,
23 char *extra);
24
25extern int
26ieee80211softmac_wx_get_essid(struct net_device *net_dev,
27 struct iw_request_info *info,
28 union iwreq_data *data,
29 char *extra);
30
31extern int
32ieee80211softmac_wx_set_rate(struct net_device *net_dev,
33 struct iw_request_info *info,
34 union iwreq_data *data,
35 char *extra);
36
37extern int
38ieee80211softmac_wx_get_rate(struct net_device *net_dev,
39 struct iw_request_info *info,
40 union iwreq_data *data,
41 char *extra);
42
43extern int
44ieee80211softmac_wx_get_wap(struct net_device *net_dev,
45 struct iw_request_info *info,
46 union iwreq_data *data,
47 char *extra);
48
49extern int
50ieee80211softmac_wx_set_wap(struct net_device *net_dev,
51 struct iw_request_info *info,
52 union iwreq_data *data,
53 char *extra);
54
55extern int
56ieee80211softmac_wx_set_genie(struct net_device *dev,
57 struct iw_request_info *info,
58 union iwreq_data *wrqu,
59 char *extra);
60
61extern int
62ieee80211softmac_wx_get_genie(struct net_device *dev,
63 struct iw_request_info *info,
64 union iwreq_data *wrqu,
65 char *extra);
66#endif /* _IEEE80211SOFTMAC_WX */
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/softmac/Kconfig b/net/ieee80211/softmac/Kconfig
new file mode 100644
index 000000000000..8d4250425911
--- /dev/null
+++ b/net/ieee80211/softmac/Kconfig
@@ -0,0 +1,9 @@
1config IEEE80211_SOFTMAC
2 tristate "Software MAC add-on to the IEEE 802.11 networking stack"
3 ---help---
4 This option enables the hardware independent software MAC addon
5 for the IEEE 802.11 networking stack.
6
7config IEEE80211_SOFTMAC_DEBUG
8 bool "Enable full debugging output"
9 depends on IEEE80211_SOFTMAC
diff --git a/net/ieee80211/softmac/Makefile b/net/ieee80211/softmac/Makefile
new file mode 100644
index 000000000000..d8c416bdddd7
--- /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..d491005d6cfd
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -0,0 +1,356 @@
1#include "ieee80211softmac_priv.h"
2
3/*
4 * Overview
5 *
6 * Before you can associate, you have to authenticate.
7 *
8 */
9
10/* Sends out an association request to the desired AP */
11static void
12ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
13{
14 unsigned long flags;
15 function_enter();
16 /* Switch to correct channel for this network */
17 mac->set_channel(mac->dev, net->channel);
18
19 /* Send association request */
20 ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0);
21
22 dprintk(KERN_INFO PFX "sent association request!\n");
23
24 /* Change the state to associating */
25 spin_lock_irqsave(&mac->lock, flags);
26 mac->associnfo.associating = 1;
27 mac->associated = 0; /* just to make sure */
28 spin_unlock_irqrestore(&mac->lock, flags);
29
30 /* Set a timer for timeout */
31 /* FIXME: make timeout configurable */
32 queue_delayed_work(mac->workqueue, &mac->associnfo.timeout, 5 * HZ);
33}
34
35void
36ieee80211softmac_assoc_timeout(void *d)
37{
38 struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
39 unsigned long flags;
40
41 function_enter();
42
43 spin_lock_irqsave(&mac->lock, flags);
44 /* we might race against ieee80211softmac_handle_assoc_response,
45 * so make sure only one of us does something */
46 if (!mac->associnfo.associating) {
47 spin_unlock_irqrestore(&mac->lock, flags);
48 return;
49 }
50 mac->associnfo.associating = 0;
51 mac->associnfo.bssvalid = 0;
52 mac->associated = 0;
53 spin_unlock_irqrestore(&mac->lock, flags);
54
55 dprintk(KERN_INFO PFX "assoc request timed out!\n");
56 /* FIXME: we need to know the network here. that requires a bit of restructuring */
57 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
58}
59
60static void
61ieee80211softmac_reassoc(struct ieee80211softmac_device *mac)
62{
63 function_enter();
64}
65
66
67/* Sends out a disassociation request to the desired AP */
68static void
69ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
70{
71 unsigned long flags;
72 struct ieee80211softmac_network *found;
73 function_enter();
74
75 if (mac->associnfo.bssvalid && mac->associated) {
76 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
77 if (found)
78 ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
79 } else if (mac->associnfo.associating) {
80 cancel_delayed_work(&mac->associnfo.timeout);
81 }
82
83 /* Change our state */
84 spin_lock_irqsave(&mac->lock, flags);
85 /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */
86 mac->associated = 0;
87 mac->associnfo.associating = 0;
88 spin_unlock_irqrestore(&mac->lock, flags);
89}
90
91static inline int
92we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
93{
94 int idx, search, found;
95 u8 rate, search_rate;
96
97 for (idx = 0; idx < (from_len); idx++) {
98 rate = (from)[idx];
99 if (!(rate & IEEE80211_BASIC_RATE_MASK))
100 continue;
101 found = 0;
102 rate &= ~IEEE80211_BASIC_RATE_MASK;
103 for (search = 0; search < mac->ratesinfo.count; search++) {
104 search_rate = mac->ratesinfo.rates[search];
105 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
106 if (rate == search_rate) {
107 found = 1;
108 break;
109 }
110 }
111 if (!found)
112 return 0;
113 }
114 return 1;
115}
116
117static int
118network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
119{
120 /* we cannot associate to networks whose name we don't know */
121 if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
122 return 0;
123 /* do not associate to a network whose BSSBasicRateSet we cannot support */
124 if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
125 return 0;
126 /* do we really need to check the ex rates? */
127 if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
128 return 0;
129
130 /* if 'ANY' network requested, take any that doesn't have privacy enabled */
131 if (mac->associnfo.req_essid.len == 0
132 && !(net->capability & WLAN_CAPABILITY_PRIVACY))
133 return 1;
134 if (net->ssid_len != mac->associnfo.req_essid.len)
135 return 0;
136 if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
137 return 1;
138 return 0;
139}
140
141static void
142ieee80211softmac_assoc_notify(struct net_device *dev, void *context)
143{
144 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
145 ieee80211softmac_assoc_work((void*)mac);
146}
147
148/* This function is called to handle userspace requests (asynchronously) */
149void
150ieee80211softmac_assoc_work(void *d)
151{
152 struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
153 struct ieee80211softmac_network *found = NULL;
154 struct ieee80211_network *net = NULL, *best = NULL;
155 unsigned long flags;
156
157 function_enter();
158
159 /* meh */
160 if (mac->associated)
161 ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
162
163 /* try to find the requested network in our list, if we found one already */
164 if (mac->associnfo.bssvalid)
165 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
166
167 /* Search the ieee80211 networks for this network if we didn't find it */
168 if (!found)
169 {
170 spin_lock_irqsave(&mac->ieee->lock, flags);
171 list_for_each_entry(net, &mac->ieee->network_list, list) {
172 /* we're supposed to find the network with
173 * the best signal here, as we're asked to join
174 * any network with a specific ESSID, and many
175 * different ones could have that.
176 *
177 * I'll for now implement just finding one at all
178 *
179 * We also should take into account the rateset
180 * here to find the best BSSID to try.
181 */
182 if (network_matches_request(mac, net)) {
183 if (!best) {
184 best = net;
185 continue;
186 }
187 /* we already had a matching network, so
188 * compare their properties to get the
189 * better of the two ... (see above)
190 */
191 /* TODO */
192 /* for now, just */
193 break;
194 }
195 }
196 /* if we unlock here, we might get interrupted and the `best'
197 * pointer could go stale */
198 if (best) {
199 found = ieee80211softmac_create_network(mac, best);
200 /* if found is still NULL, then we got -ENOMEM somewhere */
201 if (found)
202 ieee80211softmac_add_network(mac, found);
203 }
204 spin_unlock_irqrestore(&mac->ieee->lock, flags);
205 }
206
207 if (!found) {
208 if (mac->associnfo.scan_retry > 0) {
209 spin_lock_irqsave(&mac->lock, flags);
210 mac->associnfo.scan_retry--;
211 spin_unlock_irqrestore(&mac->lock, flags);
212
213 /* We know of no such network. Let's scan.
214 * NB: this also happens if we had no memory to copy the network info...
215 * Maybe we can hope to have more memory after scanning finishes ;)
216 */
217 dprintk(KERN_INFO PFX "Associate: Network not known, trying to initiate scan: ");
218 ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL);
219 if (ieee80211softmac_start_scan(mac))
220 dprintk("failed.\n");
221 else
222 dprintk("ok.\n");
223 return;
224 }
225 else {
226 spin_lock_irqsave(&mac->lock, flags);
227 mac->associnfo.associating = 0;
228 mac->associated = 0;
229 spin_unlock_irqrestore(&mac->lock, flags);
230
231 dprintk(KERN_INFO PFX "Unable to find network after scan!\n");
232 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
233 return;
234 }
235 }
236
237 mac->associnfo.bssvalid = 1;
238 memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
239 /* copy the ESSID for displaying it */
240 mac->associnfo.associate_essid.len = found->essid.len;
241 memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
242
243 /* we found a network! authenticate (if necessary) and associate to it. */
244 if (!found->authenticated) {
245 /* This relies on the fact that _auth_req only queues the work,
246 * otherwise adding the notification would be racy. */
247 if (!ieee80211softmac_auth_req(mac, found)) {
248 dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
249 ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL);
250 } else {
251 printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
252 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
253 }
254 return;
255 }
256 /* finally! now we can start associating */
257 ieee80211softmac_assoc(mac, found);
258}
259
260/* call this to do whatever is necessary when we're associated */
261static void
262ieee80211softmac_associated(struct ieee80211softmac_device *mac,
263 struct ieee80211_assoc_response * resp,
264 struct ieee80211softmac_network *net)
265{
266 mac->associnfo.associating = 0;
267 mac->associated = 1;
268 if (mac->set_bssid_filter)
269 mac->set_bssid_filter(mac->dev, net->bssid);
270 memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
271 mac->dev->flags |= IFF_RUNNING;
272
273 mac->association_id = le16_to_cpup(&resp->aid);
274}
275
276/* received frame handling functions */
277int
278ieee80211softmac_handle_assoc_response(struct net_device * dev,
279 struct ieee80211_assoc_response * resp,
280 struct ieee80211_network * _ieee80211_network_do_not_use)
281{
282 /* NOTE: the network parameter has to be ignored by
283 * this code because it is the ieee80211's pointer
284 * to the struct, not ours (we made a copy)
285 */
286 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
287 u16 status = le16_to_cpup(&resp->status);
288 struct ieee80211softmac_network *network = NULL;
289 unsigned long flags;
290
291 spin_lock_irqsave(&mac->lock, flags);
292
293 if (!mac->associnfo.associating) {
294 /* we race against the timeout function, so make sure
295 * only one of us can do work */
296 spin_unlock_irqrestore(&mac->lock, flags);
297 return 0;
298 }
299 network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
300
301 /* someone sending us things without us knowing him? Ignore. */
302 if (!network) {
303 dprintk(KERN_INFO PFX "Received unrequested assocation response from " MAC_FMT "\n", MAC_ARG(resp->header.addr3));
304 spin_unlock_irqrestore(&mac->lock, flags);
305 return 0;
306 }
307
308 /* now that we know it was for us, we can cancel the timeout */
309 cancel_delayed_work(&mac->associnfo.timeout);
310
311 switch (status) {
312 case 0:
313 dprintk(KERN_INFO PFX "associated!\n");
314 ieee80211softmac_associated(mac, resp, network);
315 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
316 break;
317 case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
318 if (!network->auth_desynced_once) {
319 /* there seem to be a few rare cases where our view of
320 * the world is obscured, or buggy APs that don't DEAUTH
321 * us properly. So we handle that, but allow it only once.
322 */
323 printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
324 network->authenticated = 0;
325 /* we don't want to do this more than once ... */
326 network->auth_desynced_once = 1;
327 queue_work(mac->workqueue, &mac->associnfo.work);
328 break;
329 }
330 default:
331 dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
332 mac->associnfo.associating = 0;
333 mac->associnfo.bssvalid = 0;
334 mac->associated = 0;
335 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
336 }
337
338 spin_unlock_irqrestore(&mac->lock, flags);
339 return 0;
340}
341
342int
343ieee80211softmac_handle_disassoc(struct net_device * dev,
344 struct ieee80211_disassoc *disassoc)
345{
346 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
347 unsigned long flags;
348 dprintk(KERN_INFO PFX "got disassoc frame\n");
349
350 spin_lock_irqsave(&mac->lock, flags);
351 mac->associnfo.bssvalid = 0;
352 mac->associated = 0;
353 spin_unlock_irqrestore(&mac->lock, flags);
354
355 return 0;
356}
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
new file mode 100644
index 000000000000..94cac14bc1d4
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -0,0 +1,348 @@
1#include "ieee80211softmac_priv.h"
2
3static void ieee80211softmac_auth_queue(void *data);
4
5/* Queues an auth request to the desired AP */
6int
7ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
8 struct ieee80211softmac_network *net)
9{
10 struct ieee80211softmac_auth_queue_item *auth;
11 unsigned long flags;
12
13 function_enter();
14
15 if (net->authenticating)
16 return 0;
17
18 /* Add the network if it's not already added */
19 ieee80211softmac_add_network(mac, net);
20
21 dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid));
22 /* Queue the auth request */
23 auth = (struct ieee80211softmac_auth_queue_item *)
24 kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
25 if(auth == NULL)
26 return -ENOMEM;
27
28 auth->net = net;
29 auth->mac = mac;
30 auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
31 auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
32 INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth);
33
34 /* Lock (for list) */
35 spin_lock_irqsave(&mac->lock, flags);
36
37 /* add to list */
38 list_add_tail(&auth->list, &mac->auth_queue);
39 queue_work(mac->workqueue, &auth->work);
40 spin_unlock_irqrestore(&mac->lock, flags);
41
42 return 0;
43}
44
45
46/* Sends an auth request to the desired AP and handles timeouts */
47static void
48ieee80211softmac_auth_queue(void *data)
49{
50 struct ieee80211softmac_device *mac;
51 struct ieee80211softmac_auth_queue_item *auth;
52 struct ieee80211softmac_network *net;
53 unsigned long flags;
54
55 function_enter();
56
57 auth = (struct ieee80211softmac_auth_queue_item *)data;
58 net = auth->net;
59 mac = auth->mac;
60
61 if(auth->retry > 0) {
62 /* Switch to correct channel for this network */
63 mac->set_channel(mac->dev, net->channel);
64
65 /* Lock and set flags */
66 spin_lock_irqsave(&mac->lock, flags);
67 net->authenticated = 0;
68 net->authenticating = 1;
69 /* add a timeout call so we eventually give up waiting for an auth reply */
70 queue_delayed_work(mac->workqueue, &auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
71 auth->retry--;
72 spin_unlock_irqrestore(&mac->lock, flags);
73 if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
74 dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid));
75 else
76 dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid));
77 return;
78 }
79
80 printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid));
81 /* Remove this item from the queue */
82 spin_lock_irqsave(&mac->lock, flags);
83 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
84 cancel_delayed_work(&auth->work); /* just to make sure... */
85 list_del(&auth->list);
86 spin_unlock_irqrestore(&mac->lock, flags);
87 /* Free it */
88 kfree(auth);
89}
90
91/* Handle the auth response from the AP
92 * This should be registered with ieee80211 as handle_auth
93 */
94int
95ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
96{
97
98 struct list_head *list_ptr;
99 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
100 struct ieee80211softmac_auth_queue_item *aq = NULL;
101 struct ieee80211softmac_network *net = NULL;
102 unsigned long flags;
103 u8 * data;
104
105 function_enter();
106
107 /* Find correct auth queue item */
108 spin_lock_irqsave(&mac->lock, flags);
109 list_for_each(list_ptr, &mac->auth_queue) {
110 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
111 net = aq->net;
112 if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
113 break;
114 else
115 aq = NULL;
116 }
117 spin_unlock_irqrestore(&mac->lock, flags);
118
119 /* Make sure that we've got an auth queue item for this request */
120 if(aq == NULL)
121 {
122 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2));
123 /* Error #? */
124 return -1;
125 }
126
127 /* Check for out of order authentication */
128 if(!net->authenticating)
129 {
130 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2));
131 return -1;
132 }
133
134 /* Parse the auth packet */
135 switch(auth->algorithm) {
136 case WLAN_AUTH_OPEN:
137 /* Check the status code of the response */
138
139 switch(auth->status) {
140 case WLAN_STATUS_SUCCESS:
141 /* Update the status to Authenticated */
142 spin_lock_irqsave(&mac->lock, flags);
143 net->authenticating = 0;
144 net->authenticated = 1;
145 spin_unlock_irqrestore(&mac->lock, flags);
146
147 /* Send event */
148 printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid));
149 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
150 break;
151 default:
152 /* Lock and reset flags */
153 spin_lock_irqsave(&mac->lock, flags);
154 net->authenticated = 0;
155 net->authenticating = 0;
156 spin_unlock_irqrestore(&mac->lock, flags);
157
158 printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n",
159 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
160 /* Count the error? */
161 break;
162 }
163 goto free_aq;
164 break;
165 case WLAN_AUTH_SHARED_KEY:
166 /* Figure out where we are in the process */
167 switch(auth->transaction) {
168 case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
169 /* Check to make sure we have a challenge IE */
170 data = (u8 *)auth->info_element;
171 if(*data++ != MFIE_TYPE_CHALLENGE){
172 printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
173 break;
174 }
175 /* Save the challenge */
176 spin_lock_irqsave(&mac->lock, flags);
177 net->challenge_len = *data++;
178 if(net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
179 net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
180 if(net->challenge != NULL)
181 kfree(net->challenge);
182 net->challenge = kmalloc(net->challenge_len, GFP_ATOMIC);
183 memcpy(net->challenge, data, net->challenge_len);
184 aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
185 spin_unlock_irqrestore(&mac->lock, flags);
186
187 /* Switch to correct channel for this network */
188 mac->set_channel(mac->dev, net->channel);
189
190 /* Send our response (How to encrypt?) */
191 ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
192 break;
193 case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
194 /* Check the status code of the response */
195 switch(auth->status) {
196 case WLAN_STATUS_SUCCESS:
197 /* Update the status to Authenticated */
198 spin_lock_irqsave(&mac->lock, flags);
199 net->authenticating = 0;
200 net->authenticated = 1;
201 spin_unlock_irqrestore(&mac->lock, flags);
202 printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n",
203 MAC_ARG(net->bssid));
204 break;
205 default:
206 printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n",
207 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
208 /* Lock and reset flags */
209 spin_lock_irqsave(&mac->lock, flags);
210 net->authenticating = 0;
211 net->authenticated = 0;
212 spin_unlock_irqrestore(&mac->lock, flags);
213 /* Count the error? */
214 break;
215 }
216 goto free_aq;
217 break;
218 default:
219 printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
220 break;
221 }
222 goto free_aq;
223 break;
224 default:
225 /* ERROR */
226 goto free_aq;
227 break;
228 }
229 return 0;
230free_aq:
231 /* Cancel the timeout */
232 spin_lock_irqsave(&mac->lock, flags);
233 cancel_delayed_work(&aq->work);
234 /* Remove this item from the queue */
235 list_del(&aq->list);
236 spin_unlock_irqrestore(&mac->lock, flags);
237
238 /* Free it */
239 kfree(aq);
240 return 0;
241}
242
243/*
244 * Handle deauthorization
245 */
246void
247ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
248 struct ieee80211softmac_network *net)
249{
250 struct ieee80211softmac_auth_queue_item *aq = NULL;
251 struct list_head *list_ptr;
252 unsigned long flags;
253
254 function_enter();
255
256 /* Lock and reset status flags */
257 spin_lock_irqsave(&mac->lock, flags);
258 net->authenticating = 0;
259 net->authenticated = 0;
260
261 /* Find correct auth queue item, if it exists */
262 list_for_each(list_ptr, &mac->auth_queue) {
263 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
264 if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
265 break;
266 else
267 aq = NULL;
268 }
269
270 /* Cancel pending work */
271 if(aq != NULL)
272 /* Not entirely safe? What about running work? */
273 cancel_delayed_work(&aq->work);
274
275 /* Free our network ref */
276 ieee80211softmac_del_network_locked(mac, net);
277 if(net->challenge != NULL)
278 kfree(net->challenge);
279 kfree(net);
280
281 /* let's try to re-associate */
282 queue_work(mac->workqueue, &mac->associnfo.work);
283 spin_unlock_irqrestore(&mac->lock, flags);
284}
285
286/*
287 * Sends a deauth request to the desired AP
288 */
289int
290ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
291 struct ieee80211softmac_network *net, int reason)
292{
293 int ret;
294
295 function_enter();
296
297 /* Make sure the network is authenticated */
298 if (!net->authenticated)
299 {
300 printkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
301 /* Error okay? */
302 return -EPERM;
303 }
304
305 /* Send the de-auth packet */
306 if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
307 return ret;
308
309 ieee80211softmac_deauth_from_net(mac, net);
310 return 0;
311}
312
313/*
314 * This should be registered with ieee80211 as handle_deauth
315 */
316int
317ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_auth *auth)
318{
319
320 struct ieee80211softmac_network *net = NULL;
321 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
322
323 function_enter();
324
325 if (!auth) {
326 dprintk("deauth without deauth packet. eek!\n");
327 return 0;
328 }
329
330 net = ieee80211softmac_get_network_by_bssid(mac, auth->header.addr2);
331
332 if (net == NULL) {
333 printkl(KERN_DEBUG PFX "Recieved deauthentication packet from "MAC_FMT", but that network is unknown.\n",
334 MAC_ARG(auth->header.addr2));
335 return 0;
336 }
337
338 /* Make sure the network is authenticated */
339 if(!net->authenticated)
340 {
341 printkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
342 /* Error okay? */
343 return -EPERM;
344 }
345
346 ieee80211softmac_deauth_from_net(mac, net);
347 return 0;
348}
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c
new file mode 100644
index 000000000000..0d0a8327252f
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_event.c
@@ -0,0 +1,135 @@
1#include "ieee80211softmac_priv.h"
2
3/*
4 * Event system
5 * Also see comments in public header file
6 *
7 * Each event has associated to it
8 * - an event type (see constants in public header)
9 * - an event context (see below)
10 * - the function to be called
11 * - a context (extra parameter to call the function with)
12 * - and the softmac struct
13 *
14 * The event context is private and can only be used from
15 * within this module. Its meaning varies with the event
16 * type:
17 * SCAN_FINISHED: no special meaning
18 * ASSOCIATED,
19 * ASSOCIATE_FAILED,
20 * ASSOCIATE_TIMEOUT,
21 * AUTHENTICATED,
22 * AUTH_FAILED,
23 * AUTH_TIMEOUT: a pointer to the network struct
24 * ...
25 * Code within this module can use the event context to be only
26 * called when the event is true for that specific context
27 * as per above table.
28 * If the event context is NULL, then the notification is always called,
29 * regardless of the event context. The event context is not passed to
30 * the callback, it is assumed that the context suffices.
31 *
32 * You can also use the event context only by setting the event type
33 * to -1 (private use only), in which case you'll be notified
34 * whenever the event context matches.
35 */
36
37static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
38 "scan finished",
39 "associated",
40 "associating failed",
41 "associating timed out",
42 "authenticated",
43 "authenticating failed",
44 "authenticating timed out",
45 "associating failed because no suitable network was found",
46};
47
48
49static void
50ieee80211softmac_notify_callback(void *d)
51{
52 struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d;
53 kfree(d);
54
55 event.fun(event.mac->dev, event.context);
56}
57
58int
59ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
60 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
61{
62 struct ieee80211softmac_event *eventptr;
63 unsigned long flags;
64
65 if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
66 return -ENOSYS;
67
68 if (!fun)
69 return -EINVAL;
70
71 eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
72 if (!eventptr)
73 return -ENOMEM;
74
75 eventptr->event_type = event;
76 INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr);
77 eventptr->fun = fun;
78 eventptr->context = context;
79 eventptr->mac = mac;
80 eventptr->event_context = event_context;
81
82 spin_lock_irqsave(&mac->lock, flags);
83 list_add(&eventptr->list, &mac->events);
84 spin_unlock_irqrestore(&mac->lock, flags);
85
86 return 0;
87}
88
89int
90ieee80211softmac_notify_gfp(struct net_device *dev,
91 int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
92{
93 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
94
95 if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
96 return -ENOSYS;
97
98 return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
99}
100EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
101
102/* private -- calling all callbacks that were specified */
103void
104ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
105{
106 struct ieee80211softmac_event *eventptr, *tmp;
107 union iwreq_data wrqu;
108 char *msg;
109
110 if (event >= 0) {
111 msg = event_descriptions[event];
112 wrqu.data.length = strlen(msg);
113 wireless_send_event(mac->dev, IWEVCUSTOM, &wrqu, msg);
114 }
115
116 if (!list_empty(&mac->events))
117 list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
118 if ((eventptr->event_type == event || eventptr->event_type == -1)
119 && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
120 list_del(&eventptr->list);
121 queue_work(mac->workqueue, &eventptr->work);
122 }
123 }
124}
125
126void
127ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
128{
129 unsigned long flags;
130
131 spin_lock_irqsave(&mac->lock, flags);
132 ieee80211softmac_call_events_locked(mac, event, event_ctx);
133
134 spin_unlock_irqrestore(&mac->lock, flags);
135}
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
new file mode 100644
index 000000000000..2cb3087197d8
--- /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 */
158u32
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 */
209u32
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 */
256u32
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 */
304u32
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 */
321u32
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 */
350u32
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 */
433u32
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..1244a659cd83
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -0,0 +1,441 @@
1#include "ieee80211softmac_priv.h"
2#include <linux/sort.h>
3
4struct net_device *alloc_ieee80211softmac(int sizeof_priv)
5{
6 struct ieee80211softmac_device *softmac;
7 struct net_device *dev;
8
9 dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
10 softmac = ieee80211_priv(dev);
11 softmac->dev = dev;
12 softmac->ieee = netdev_priv(dev);
13 spin_lock_init(&softmac->lock);
14
15 softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
16 softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
17 softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
18 softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
19 softmac->scaninfo = NULL;
20
21 /* TODO: initialise all the other callbacks in the ieee struct
22 * (once they're written)
23 */
24
25 softmac->workqueue = create_workqueue("80211softmac");
26 if (!softmac->workqueue)
27 goto err_free_ieee80211;
28
29 INIT_LIST_HEAD(&softmac->auth_queue);
30 INIT_LIST_HEAD(&softmac->network_list);
31 INIT_LIST_HEAD(&softmac->events);
32
33 INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
34 INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
35 softmac->start_scan = ieee80211softmac_start_scan_implementation;
36 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
37 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
38
39 //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
40 // It has to be set to the highest rate all stations in the current network can handle.
41 softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
42 softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
43 /* This is reassigned in ieee80211softmac_start to sane values. */
44 softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
45 softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
46
47 /* should we also assign softmac->mgmt_xmit here so
48 * that it is always valid? If so, we probably want
49 * to define a new function for that which just
50 * wraps ieee80211_tx_frame
51 */
52
53 /* until associated, we're not ready */
54 dev->flags &= ~IFF_RUNNING;
55
56 return dev;
57
58err_free_ieee80211:
59 free_ieee80211(dev);
60
61 return NULL;
62}
63
64/* Clears the pending work queue items, stops all scans, etc. */
65void
66ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
67{
68 unsigned long flags;
69 struct ieee80211softmac_event *eventptr, *eventtmp;
70 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
71 struct ieee80211softmac_network *netptr, *nettmp;
72
73 ieee80211softmac_stop_scan(sm);
74 ieee80211softmac_wait_for_scan(sm);
75
76 spin_lock_irqsave(&sm->lock, flags);
77 /* Free all pending assoc work items */
78 cancel_delayed_work(&sm->associnfo.work);
79
80 /* Free all pending scan work items */
81 if(sm->scaninfo != NULL)
82 cancel_delayed_work(&sm->scaninfo->softmac_scan);
83
84 /* Free all pending auth work items */
85 list_for_each_entry(authptr, &sm->auth_queue, list)
86 cancel_delayed_work(&authptr->work);
87
88 /* delete all pending event calls and work items */
89 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
90 cancel_delayed_work(&eventptr->work);
91
92 spin_unlock_irqrestore(&sm->lock, flags);
93 flush_workqueue(sm->workqueue);
94
95 // now we should be save and no longer need locking...
96 spin_lock_irqsave(&sm->lock, flags);
97 /* Free all pending auth work items */
98 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
99 list_del(&authptr->list);
100 kfree(authptr);
101 }
102
103 /* delete all pending event calls and work items */
104 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
105 list_del(&eventptr->list);
106 kfree(eventptr);
107 }
108
109 /* Free all networks */
110 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
111 ieee80211softmac_del_network_locked(sm, netptr);
112 if(netptr->challenge != NULL)
113 kfree(netptr->challenge);
114 kfree(netptr);
115 }
116
117 spin_unlock_irqrestore(&sm->lock, flags);
118}
119
120void free_ieee80211softmac(struct net_device *dev)
121{
122 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
123 ieee80211softmac_clear_pending_work(sm);
124 destroy_workqueue(sm->workqueue);
125 kfree(sm->scaninfo);
126 kfree(sm->wpa.IE);
127 free_ieee80211(dev);
128}
129
130static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
131{
132 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
133 /* I took out the sorting check, we're seperating by modulation now. */
134 if (ri->count)
135 return;
136 /* otherwise assume we hav'em all! */
137 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
138 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
139 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
140 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
141 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
142 }
143 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
144 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
145 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
146 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
147 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
148 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
149 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
150 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
151 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
152 }
153}
154
155void ieee80211softmac_start(struct net_device *dev)
156{
157 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
158 struct ieee80211_device *ieee = mac->ieee;
159 u32 change = 0;
160 struct ieee80211softmac_txrates oldrates;
161
162 ieee80211softmac_start_check_rates(mac);
163
164 /* TODO: We need some kind of state machine to lower the default rates
165 * if we loose too many packets.
166 */
167 /* Change the default txrate to the highest possible value.
168 * The txrate machine will lower it, if it is too high.
169 */
170 if (mac->txrates_change)
171 oldrates = mac->txrates;
172 if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
173 mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
174 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
175 mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
176 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
177 } else if (ieee->modulation & IEEE80211_CCK_MODULATION) {
178 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
179 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
180 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
181 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
182 } else
183 assert(0);
184 if (mac->txrates_change)
185 mac->txrates_change(dev, change, &oldrates);
186}
187
188void ieee80211softmac_stop(struct net_device *dev)
189{
190 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
191
192 ieee80211softmac_clear_pending_work(mac);
193}
194
195void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
196{
197 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
198 unsigned long flags;
199
200 spin_lock_irqsave(&mac->lock, flags);
201 memcpy(mac->ratesinfo.rates, rates, count);
202 mac->ratesinfo.count = count;
203 spin_unlock_irqrestore(&mac->lock, flags);
204}
205
206static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
207{
208 int i;
209 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
210
211 for (i=0; i<ri->count-1; i++) {
212 if (ri->rates[i] == rate)
213 return ri->rates[i+1];
214 }
215 /* I guess we can't go any higher... */
216 return ri->rates[ri->count];
217}
218
219u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
220{
221 int i;
222 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
223
224 for (i=delta; i<ri->count; i++) {
225 if (ri->rates[i] == rate)
226 return ri->rates[i-delta];
227 }
228 /* I guess we can't go any lower... */
229 return ri->rates[0];
230}
231
232static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
233 int amount)
234{
235 struct ieee80211softmac_txrates oldrates;
236 u8 default_rate = mac->txrates.default_rate;
237 u8 default_fallback = mac->txrates.default_fallback;
238 u32 changes = 0;
239
240 //TODO: This is highly experimental code.
241 // Maybe the dynamic rate selection does not work
242 // and it has to be removed again.
243
244printk("badness %d\n", mac->txrate_badness);
245 mac->txrate_badness += amount;
246 if (mac->txrate_badness <= -1000) {
247 /* Very small badness. Try a faster bitrate. */
248 if (mac->txrates_change)
249 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
250 default_rate = raise_rate(mac, default_rate);
251 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
252 default_fallback = get_fallback_rate(mac, default_rate);
253 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
254 mac->txrate_badness = 0;
255printk("Bitrate raised to %u\n", default_rate);
256 } else if (mac->txrate_badness >= 10000) {
257 /* Very high badness. Try a slower bitrate. */
258 if (mac->txrates_change)
259 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
260 default_rate = lower_rate(mac, default_rate);
261 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
262 default_fallback = get_fallback_rate(mac, default_rate);
263 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
264 mac->txrate_badness = 0;
265printk("Bitrate lowered to %u\n", default_rate);
266 }
267
268 mac->txrates.default_rate = default_rate;
269 mac->txrates.default_fallback = default_fallback;
270
271 if (changes && mac->txrates_change)
272 mac->txrates_change(mac->dev, changes, &oldrates);
273}
274
275void ieee80211softmac_fragment_lost(struct net_device *dev,
276 u16 wl_seq)
277{
278 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
279 unsigned long flags;
280
281 spin_lock_irqsave(&mac->lock, flags);
282 ieee80211softmac_add_txrates_badness(mac, 1000);
283 //TODO
284
285 spin_unlock_irqrestore(&mac->lock, flags);
286}
287
288static int rate_cmp(const void *a_, const void *b_) {
289 u8 *a, *b;
290 a = (u8*)a_;
291 b = (u8*)b_;
292 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
293}
294
295/* Allocate a softmac network struct and fill it from a network */
296struct ieee80211softmac_network *
297ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
298 struct ieee80211_network *net)
299{
300 struct ieee80211softmac_network *softnet;
301 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
302 if(softnet == NULL)
303 return NULL;
304 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
305 softnet->channel = net->channel;
306 softnet->essid.len = net->ssid_len;
307 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
308
309 /* copy rates over */
310 softnet->supported_rates.count = net->rates_len;
311 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
312 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
313 softnet->supported_rates.count += net->rates_ex_len;
314 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
315
316 softnet->capabilities = net->capability;
317 return softnet;
318}
319
320
321/* Add a network to the list, while locked */
322void
323ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
324 struct ieee80211softmac_network *add_net)
325{
326 struct list_head *list_ptr;
327 struct ieee80211softmac_network *softmac_net = NULL;
328
329 list_for_each(list_ptr, &mac->network_list) {
330 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
331 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
332 break;
333 else
334 softmac_net = NULL;
335 }
336 if(softmac_net == NULL)
337 list_add(&(add_net->list), &mac->network_list);
338}
339
340/* Add a network to the list, with locking */
341void
342ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
343 struct ieee80211softmac_network *add_net)
344{
345 unsigned long flags;
346 spin_lock_irqsave(&mac->lock, flags);
347 ieee80211softmac_add_network_locked(mac, add_net);
348 spin_unlock_irqrestore(&mac->lock, flags);
349}
350
351
352/* Delete a network from the list, while locked*/
353void
354ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
355 struct ieee80211softmac_network *del_net)
356{
357 list_del(&(del_net->list));
358}
359
360/* Delete a network from the list with locking */
361void
362ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
363 struct ieee80211softmac_network *del_net)
364{
365 unsigned long flags;
366 spin_lock_irqsave(&mac->lock, flags);
367 ieee80211softmac_del_network_locked(mac, del_net);
368 spin_unlock_irqrestore(&mac->lock, flags);
369}
370
371/* Get a network from the list by MAC while locked */
372struct ieee80211softmac_network *
373ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
374 u8 *bssid)
375{
376 struct list_head *list_ptr;
377 struct ieee80211softmac_network *softmac_net = NULL;
378 list_for_each(list_ptr, &mac->network_list) {
379 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
380 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
381 break;
382 else
383 softmac_net = NULL;
384 }
385 return softmac_net;
386}
387
388/* Get a network from the list by BSSID with locking */
389struct ieee80211softmac_network *
390ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
391 u8 *bssid)
392{
393 unsigned long flags;
394 struct ieee80211softmac_network *softmac_net;
395
396 spin_lock_irqsave(&mac->lock, flags);
397 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
398 spin_unlock_irqrestore(&mac->lock, flags);
399 return softmac_net;
400}
401
402/* Get a network from the list by ESSID while locked */
403struct ieee80211softmac_network *
404ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
405 struct ieee80211softmac_essid *essid)
406{
407 struct list_head *list_ptr;
408 struct ieee80211softmac_network *softmac_net = NULL;
409
410 list_for_each(list_ptr, &mac->network_list) {
411 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
412 if (softmac_net->essid.len == essid->len &&
413 !memcmp(softmac_net->essid.data, essid->data, essid->len))
414 return softmac_net;
415 }
416 return NULL;
417}
418
419/* Get a network from the list by ESSID with locking */
420struct ieee80211softmac_network *
421ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
422 struct ieee80211softmac_essid *essid)
423{
424 unsigned long flags;
425 struct ieee80211softmac_network *softmac_net = NULL;
426
427 spin_lock_irqsave(&mac->lock, flags);
428 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
429 spin_unlock_irqrestore(&mac->lock, flags);
430 return softmac_net;
431}
432
433MODULE_LICENSE("GPL");
434
435EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
436EXPORT_SYMBOL_GPL(free_ieee80211softmac);
437EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
438EXPORT_SYMBOL_GPL(ieee80211softmac_start);
439EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
440EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
441EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
new file mode 100644
index 000000000000..591d3bdf37ee
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -0,0 +1,206 @@
1#ifndef IEEE80211SOFTMAC_PRIV_H_
2#define IEEE80211SOFTMAC_PRIV_H_
3
4#include <net/ieee80211softmac.h>
5#include <net/ieee80211softmac_wx.h>
6#include <linux/kernel.h>
7#include <linux/stringify.h>
8
9
10#define PFX "SoftMAC: "
11
12#ifdef assert
13# undef assert
14#endif
15#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
16#define assert(expr) \
17 do { \
18 if (unlikely(!(expr))) { \
19 printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \
20 __FILE__, __LINE__, __FUNCTION__); \
21 } \
22 } while (0)
23#else
24#define assert(expr) do {} while (0)
25#endif
26
27/* rate limited printk(). */
28#ifdef printkl
29# undef printkl
30#endif
31#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0)
32/* rate limited printk() for debugging */
33#ifdef dprintkl
34# undef dprintkl
35#endif
36#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
37# define dprintkl printkl
38#else
39# define dprintkl(f, x...) do { /* nothing */ } while (0)
40#endif
41
42/* debugging printk() */
43#ifdef dprintk
44# undef dprintk
45#endif
46#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
47# define dprintk(f, x...) do { printk(f ,##x); } while (0)
48#else
49# define dprintk(f, x...) do { /* nothing */ } while (0)
50#endif
51
52#ifdef function_enter
53# undef function_enter
54#endif
55#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
56# define function_enter() do { printk(KERN_DEBUG PFX "%s:%d:%s()\n", __FILE__, __LINE__, __FUNCTION__); } while (0)
57#else
58# define function_enter() do { /* nothing */ } while (0)
59#endif
60
61/* private definitions and prototypes */
62
63/*** prototypes from _scan.c */
64void ieee80211softmac_scan(void *sm);
65/* for internal use if scanning is needed */
66int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
67void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
68void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac);
69
70/* for use by _module.c to assign to the callbacks */
71int ieee80211softmac_start_scan_implementation(struct net_device *dev);
72void ieee80211softmac_stop_scan_implementation(struct net_device *dev);
73void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev);
74
75/*** Network prototypes from _module.c */
76struct ieee80211softmac_network * ieee80211softmac_create_network(
77 struct ieee80211softmac_device *mac, struct ieee80211_network *net);
78void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
79 struct ieee80211softmac_network *net);
80void ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
81 struct ieee80211softmac_network *net);
82void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
83 struct ieee80211softmac_network *net);
84void ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
85 struct ieee80211softmac_network *net);
86struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked(
87 struct ieee80211softmac_device *mac, u8 *ea);
88struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid(
89 struct ieee80211softmac_device *mac, u8 *ea);
90struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked(
91 struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
92struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid(
93 struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
94
95
96/* Rates related */
97u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
98static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
99 return ieee80211softmac_lower_rate_delta(mac, rate, 1);
100}
101
102static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
103{
104 return ieee80211softmac_lower_rate_delta(mac, rate, 2);
105}
106
107
108/*** prototypes from _io.c */
109int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
110 void* ptrarg, u32 type, u32 arg);
111
112/*** prototypes from _auth.c */
113/* do these have to go into the public header? */
114int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
115int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
116
117/* for use by _module.c to assign to the callbacks */
118int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
119int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_auth *auth);
120
121/*** prototypes from _assoc.c */
122void ieee80211softmac_assoc_work(void *d);
123int ieee80211softmac_handle_assoc_response(struct net_device * dev,
124 struct ieee80211_assoc_response * resp,
125 struct ieee80211_network * network);
126int ieee80211softmac_handle_disassoc(struct net_device * dev,
127 struct ieee80211_disassoc * disassoc);
128void ieee80211softmac_assoc_timeout(void *d);
129
130/* some helper functions */
131static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
132{
133 return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
134 (sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
135 (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
136}
137
138static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
139{
140 return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
141 (sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
142 (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
143 ) || ieee80211softmac_scan_handlers_check_self(sm);
144}
145
146#define IEEE80211SOFTMAC_PROBE_DELAY HZ/2
147#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ)
148
149struct ieee80211softmac_network {
150 struct list_head list; /* List */
151 /* Network information copied from ieee80211_network */
152 u8 bssid[ETH_ALEN];
153 u8 channel;
154 struct ieee80211softmac_essid essid;
155
156 struct ieee80211softmac_ratesinfo supported_rates;
157
158 /* SoftMAC specific */
159 u16 authenticating:1, /* Status Flags */
160 authenticated:1,
161 auth_desynced_once:1;
162
163 u16 capabilities; /* Capabilities bitfield */
164 u8 challenge_len; /* Auth Challenge length */
165 char *challenge; /* Challenge Text */
166};
167
168/* structure used to keep track of networks we're auth'ing to */
169struct ieee80211softmac_auth_queue_item {
170 struct list_head list; /* List head */
171 struct ieee80211softmac_network *net; /* Network to auth */
172 struct ieee80211softmac_device *mac; /* SoftMAC device */
173 u8 retry; /* Retry limit */
174 u8 state; /* Auth State */
175 struct work_struct work; /* Work queue */
176};
177
178/* scanning information */
179struct ieee80211softmac_scaninfo {
180 u8 current_channel_idx,
181 number_channels;
182 struct ieee80211_channel *channels;
183 u8 started:1,
184 stop:1;
185 u8 skip_flags;
186 struct completion finished;
187 struct work_struct softmac_scan;
188};
189
190/* private event struct */
191struct ieee80211softmac_event {
192 struct list_head list;
193 int event_type;
194 void *event_context;
195 struct work_struct work;
196 notify_function_ptr fun;
197 void *context;
198 struct ieee80211softmac_device *mac;
199};
200
201void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
202void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
203int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
204 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
205
206#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..b4b44fa8727d
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_scan.c
@@ -0,0 +1,216 @@
1/*
2 * Scanning routines.
3 *
4 * These are not exported because they're assigned to the function pointers.
5 */
6
7#include <linux/completion.h>
8#include "ieee80211softmac_priv.h"
9
10/* internal, use to trigger scanning if needed.
11 * Returns -EBUSY if already scanning,
12 * result of start_scan otherwise */
13int
14ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
15{
16 unsigned long flags;
17 int ret;
18
19 spin_lock_irqsave(&sm->lock, flags);
20 if (sm->scanning)
21 {
22 spin_unlock_irqrestore(&sm->lock, flags);
23 return -EINPROGRESS;
24 }
25 sm->scanning = 1;
26 spin_unlock_irqrestore(&sm->lock, flags);
27
28 ret = sm->start_scan(sm->dev);
29 if (ret) {
30 spin_lock_irqsave(&sm->lock, flags);
31 sm->scanning = 0;
32 spin_unlock_irqrestore(&sm->lock, flags);
33 }
34 return ret;
35}
36
37void
38ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm)
39{
40 unsigned long flags;
41
42 spin_lock_irqsave(&sm->lock, flags);
43
44 if (!sm->scanning) {
45 spin_unlock_irqrestore(&sm->lock, flags);
46 return;
47 }
48
49 spin_unlock_irqrestore(&sm->lock, flags);
50 sm->stop_scan(sm->dev);
51}
52
53void
54ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm)
55{
56 unsigned long flags;
57
58 spin_lock_irqsave(&sm->lock, flags);
59
60 if (!sm->scanning) {
61 spin_unlock_irqrestore(&sm->lock, flags);
62 return;
63 }
64
65 spin_unlock_irqrestore(&sm->lock, flags);
66 sm->wait_for_scan(sm->dev);
67}
68
69
70/* internal scanning implementation follows */
71void ieee80211softmac_scan(void *d)
72{
73 int invalid_channel;
74 u8 current_channel_idx;
75 struct ieee80211softmac_device *sm = (struct ieee80211softmac_device *)d;
76 struct ieee80211softmac_scaninfo *si = sm->scaninfo;
77 unsigned long flags;
78
79 while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
80 current_channel_idx = si->current_channel_idx;
81 si->current_channel_idx++; /* go to the next channel */
82
83 invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
84
85 if (!invalid_channel) {
86 sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
87 //TODO: Probe the channel
88 // FIXME make this user configurable (active/passive)
89 if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
90 printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
91
92 /* also send directed management frame for the network we're looking for */
93 // TODO: is this if correct, or should we do this only if scanning from assoc request?
94 if (sm->associnfo.req_essid.len)
95 ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
96 queue_delayed_work(sm->workqueue, &si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
97 return;
98 } else {
99 dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
100 }
101 }
102
103 spin_lock_irqsave(&sm->lock, flags);
104 cancel_delayed_work(&si->softmac_scan);
105 si->started = 0;
106 spin_unlock_irqrestore(&sm->lock, flags);
107
108 dprintk(PFX "Scanning finished\n");
109 ieee80211softmac_scan_finished(sm);
110 complete_all(&sm->scaninfo->finished);
111}
112
113static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
114{
115 /* ugh. can we call this without having the spinlock held? */
116 struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
117 if (unlikely(!info))
118 return NULL;
119 INIT_WORK(&info->softmac_scan, ieee80211softmac_scan, mac);
120 init_completion(&info->finished);
121 return info;
122}
123
124int ieee80211softmac_start_scan_implementation(struct net_device *dev)
125{
126 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
127 unsigned long flags;
128
129 if (!(dev->flags & IFF_UP))
130 return -ENODEV;
131
132 assert(ieee80211softmac_scan_handlers_check_self(sm));
133 if (!ieee80211softmac_scan_handlers_check_self(sm))
134 return -EINVAL;
135
136 spin_lock_irqsave(&sm->lock, flags);
137 /* it looks like we need to hold the lock here
138 * to make sure we don't allocate two of these... */
139 if (unlikely(!sm->scaninfo))
140 sm->scaninfo = allocate_scaninfo(sm);
141 if (unlikely(!sm->scaninfo)) {
142 spin_unlock_irqrestore(&sm->lock, flags);
143 return -ENOMEM;
144 }
145
146 sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
147 if (0 /* not scanning in IEEE802.11b */)//TODO
148 sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
149 if (0 /* IEEE802.11a */) {//TODO
150 sm->scaninfo->channels = sm->ieee->geo.a;
151 sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
152 } else {
153 sm->scaninfo->channels = sm->ieee->geo.bg;
154 sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
155 }
156 dprintk(PFX "Start scanning with channel: %d\n", sm->scaninfo->channels[0].channel);
157 dprintk(PFX "Scanning %d channels\n", sm->scaninfo->number_channels);
158 sm->scaninfo->current_channel_idx = 0;
159 sm->scaninfo->started = 1;
160 INIT_COMPLETION(sm->scaninfo->finished);
161 queue_work(sm->workqueue, &sm->scaninfo->softmac_scan);
162 spin_unlock_irqrestore(&sm->lock, flags);
163 return 0;
164}
165
166void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
167{
168 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
169 unsigned long flags;
170
171 assert(ieee80211softmac_scan_handlers_check_self(sm));
172 if (!ieee80211softmac_scan_handlers_check_self(sm))
173 return;
174
175 spin_lock_irqsave(&sm->lock, flags);
176 assert(sm->scaninfo != NULL);
177 if (sm->scaninfo) {
178 if (sm->scaninfo->started)
179 sm->scaninfo->stop = 1;
180 else
181 complete_all(&sm->scaninfo->finished);
182 }
183 spin_unlock_irqrestore(&sm->lock, flags);
184}
185
186void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
187{
188 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
189 unsigned long flags;
190
191 assert(ieee80211softmac_scan_handlers_check_self(sm));
192 if (!ieee80211softmac_scan_handlers_check_self(sm))
193 return;
194
195 spin_lock_irqsave(&sm->lock, flags);
196 if (!sm->scaninfo->started) {
197 spin_unlock_irqrestore(&sm->lock, flags);
198 return;
199 }
200 spin_unlock_irqrestore(&sm->lock, flags);
201 wait_for_completion(&sm->scaninfo->finished);
202}
203
204/* this is what drivers (that do scanning) call when they're done */
205void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
206{
207 unsigned long flags;
208
209 spin_lock_irqsave(&sm->lock, flags);
210 sm->scanning = 0;
211 spin_unlock_irqrestore(&sm->lock, flags);
212
213 ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
214}
215
216EXPORT_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..bae5fcc11967
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -0,0 +1,390 @@
1/*
2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
3 */
4
5#include "ieee80211softmac_priv.h"
6
7#include <net/iw_handler.h>
8
9
10int
11ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
12 struct iw_request_info *info,
13 union iwreq_data *data,
14 char *extra)
15{
16 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
17 return ieee80211softmac_start_scan(sm);
18}
19EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
20
21
22int
23ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
24 struct iw_request_info *info,
25 union iwreq_data *data,
26 char *extra)
27{
28 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
29 return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
30}
31EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
32
33int
34ieee80211softmac_wx_set_essid(struct net_device *net_dev,
35 struct iw_request_info *info,
36 union iwreq_data *data,
37 char *extra)
38{
39 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
40 int length = 0;
41 unsigned long flags;
42
43 spin_lock_irqsave(&sm->lock, flags);
44
45 sm->associnfo.static_essid = 0;
46
47 if (data->essid.flags && data->essid.length && extra /*required?*/) {
48 length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
49 if (length) {
50 memcpy(sm->associnfo.req_essid.data, extra, length);
51 sm->associnfo.static_essid = 1;
52 }
53 }
54 sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
55
56 /* set our requested ESSID length.
57 * If applicable, we have already copied the data in */
58 sm->associnfo.req_essid.len = length;
59
60 /* queue lower level code to do work (if necessary) */
61 queue_work(sm->workqueue, &sm->associnfo.work);
62
63 spin_unlock_irqrestore(&sm->lock, flags);
64 return 0;
65}
66EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
67
68int
69ieee80211softmac_wx_get_essid(struct net_device *net_dev,
70 struct iw_request_info *info,
71 union iwreq_data *data,
72 char *extra)
73{
74 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
75 unsigned long flags;
76
77 /* avoid getting inconsistent information */
78 spin_lock_irqsave(&sm->lock, flags);
79 /* If all fails, return ANY (empty) */
80 data->essid.length = 0;
81 data->essid.flags = 0; /* active */
82
83 /* If we have a statically configured ESSID then return it */
84 if (sm->associnfo.static_essid) {
85 data->essid.length = sm->associnfo.req_essid.len;
86 data->essid.flags = 1; /* active */
87 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
88 }
89
90 /* If we're associating/associated, return that */
91 if (sm->associated || sm->associnfo.associating) {
92 data->essid.length = sm->associnfo.associate_essid.len;
93 data->essid.flags = 1; /* active */
94 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
95 }
96 spin_unlock_irqrestore(&sm->lock, flags);
97 return 0;
98}
99EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
100
101int
102ieee80211softmac_wx_set_rate(struct net_device *net_dev,
103 struct iw_request_info *info,
104 union iwreq_data *data,
105 char *extra)
106{
107 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
108 struct ieee80211_device *ieee = mac->ieee;
109 unsigned long flags;
110 s32 in_rate = data->bitrate.value;
111 u8 rate;
112 int is_ofdm = 0;
113 int err = -EINVAL;
114
115 if (in_rate == -1) {
116 /* automatic detect */
117 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
118 in_rate = 54000000;
119 else
120 in_rate = 11000000;
121 }
122
123 switch (in_rate) {
124 case 1000000:
125 rate = IEEE80211_CCK_RATE_1MB;
126 break;
127 case 2000000:
128 rate = IEEE80211_CCK_RATE_2MB;
129 break;
130 case 5500000:
131 rate = IEEE80211_CCK_RATE_5MB;
132 break;
133 case 11000000:
134 rate = IEEE80211_CCK_RATE_11MB;
135 break;
136 case 6000000:
137 rate = IEEE80211_OFDM_RATE_6MB;
138 is_ofdm = 1;
139 break;
140 case 9000000:
141 rate = IEEE80211_OFDM_RATE_9MB;
142 is_ofdm = 1;
143 break;
144 case 12000000:
145 rate = IEEE80211_OFDM_RATE_12MB;
146 is_ofdm = 1;
147 break;
148 case 18000000:
149 rate = IEEE80211_OFDM_RATE_18MB;
150 is_ofdm = 1;
151 break;
152 case 24000000:
153 rate = IEEE80211_OFDM_RATE_24MB;
154 is_ofdm = 1;
155 break;
156 case 36000000:
157 rate = IEEE80211_OFDM_RATE_36MB;
158 is_ofdm = 1;
159 break;
160 case 48000000:
161 rate = IEEE80211_OFDM_RATE_48MB;
162 is_ofdm = 1;
163 break;
164 case 54000000:
165 rate = IEEE80211_OFDM_RATE_54MB;
166 is_ofdm = 1;
167 break;
168 default:
169 goto out;
170 }
171
172 spin_lock_irqsave(&mac->lock, flags);
173
174 /* Check if correct modulation for this PHY. */
175 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
176 goto out_unlock;
177
178 mac->txrates.default_rate = rate;
179 mac->txrates.default_fallback = lower_rate(mac, rate);
180 err = 0;
181
182out_unlock:
183 spin_unlock_irqrestore(&mac->lock, flags);
184out:
185 return err;
186}
187EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
188
189int
190ieee80211softmac_wx_get_rate(struct net_device *net_dev,
191 struct iw_request_info *info,
192 union iwreq_data *data,
193 char *extra)
194{
195 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
196 unsigned long flags;
197 int err = -EINVAL;
198
199 spin_lock_irqsave(&mac->lock, flags);
200 switch (mac->txrates.default_rate) {
201 case IEEE80211_CCK_RATE_1MB:
202 data->bitrate.value = 1000000;
203 break;
204 case IEEE80211_CCK_RATE_2MB:
205 data->bitrate.value = 2000000;
206 break;
207 case IEEE80211_CCK_RATE_5MB:
208 data->bitrate.value = 5500000;
209 break;
210 case IEEE80211_CCK_RATE_11MB:
211 data->bitrate.value = 11000000;
212 break;
213 case IEEE80211_OFDM_RATE_6MB:
214 data->bitrate.value = 6000000;
215 break;
216 case IEEE80211_OFDM_RATE_9MB:
217 data->bitrate.value = 9000000;
218 break;
219 case IEEE80211_OFDM_RATE_12MB:
220 data->bitrate.value = 12000000;
221 break;
222 case IEEE80211_OFDM_RATE_18MB:
223 data->bitrate.value = 18000000;
224 break;
225 case IEEE80211_OFDM_RATE_24MB:
226 data->bitrate.value = 24000000;
227 break;
228 case IEEE80211_OFDM_RATE_36MB:
229 data->bitrate.value = 36000000;
230 break;
231 case IEEE80211_OFDM_RATE_48MB:
232 data->bitrate.value = 48000000;
233 break;
234 case IEEE80211_OFDM_RATE_54MB:
235 data->bitrate.value = 54000000;
236 break;
237 default:
238 assert(0);
239 goto out_unlock;
240 }
241 err = 0;
242out_unlock:
243 spin_unlock_irqrestore(&mac->lock, flags);
244
245 return err;
246}
247EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
248
249int
250ieee80211softmac_wx_get_wap(struct net_device *net_dev,
251 struct iw_request_info *info,
252 union iwreq_data *data,
253 char *extra)
254{
255 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
256 int err = 0;
257 unsigned long flags;
258
259 spin_lock_irqsave(&mac->lock, flags);
260 if (mac->associnfo.bssvalid)
261 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
262 else
263 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
264 data->ap_addr.sa_family = ARPHRD_ETHER;
265 spin_unlock_irqrestore(&mac->lock, flags);
266 return err;
267}
268EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
269
270int
271ieee80211softmac_wx_set_wap(struct net_device *net_dev,
272 struct iw_request_info *info,
273 union iwreq_data *data,
274 char *extra)
275{
276 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
277 static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
278 static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
279 unsigned long flags;
280
281 /* sanity check */
282 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
283 return -EINVAL;
284 }
285
286 spin_lock_irqsave(&mac->lock, flags);
287 if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
288 !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
289 queue_work(mac->workqueue, &mac->associnfo.work);
290 goto out;
291 } else {
292 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
293 if (mac->associnfo.associating || mac->associated) {
294 /* bssid unchanged and associated or associating - just return */
295 goto out;
296 }
297 } else {
298 /* copy new value in data->ap_addr.sa_data to bssid */
299 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
300 }
301 /* queue associate if new bssid or (old one again and not associated) */
302 queue_work(mac->workqueue,&mac->associnfo.work);
303 }
304
305out:
306 spin_unlock_irqrestore(&mac->lock, flags);
307 return 0;
308}
309EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
310
311int
312ieee80211softmac_wx_set_genie(struct net_device *dev,
313 struct iw_request_info *info,
314 union iwreq_data *wrqu,
315 char *extra)
316{
317 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
318 unsigned long flags;
319 int err = 0;
320 char *buf;
321 int i;
322
323 spin_lock_irqsave(&mac->lock, flags);
324 /* bleh. shouldn't be locked for that kmalloc... */
325
326 if (wrqu->data.length) {
327 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
328 /* this is an IE, so the length must be
329 * correct. Is it possible though that
330 * more than one IE is passed in?
331 */
332 err = -EINVAL;
333 goto out;
334 }
335 if (mac->wpa.IEbuflen <= wrqu->data.length) {
336 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
337 if (!buf) {
338 err = -ENOMEM;
339 goto out;
340 }
341 kfree(mac->wpa.IE);
342 mac->wpa.IE = buf;
343 mac->wpa.IEbuflen = wrqu->data.length;
344 }
345 memcpy(mac->wpa.IE, extra, wrqu->data.length);
346 dprintk(KERN_INFO PFX "generic IE set to ");
347 for (i=0;i<wrqu->data.length;i++)
348 dprintk("%.2x", mac->wpa.IE[i]);
349 dprintk("\n");
350 mac->wpa.IElen = wrqu->data.length;
351 } else {
352 kfree(mac->wpa.IE);
353 mac->wpa.IE = NULL;
354 mac->wpa.IElen = 0;
355 mac->wpa.IEbuflen = 0;
356 }
357
358 out:
359 spin_unlock_irqrestore(&mac->lock, flags);
360 return err;
361}
362EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
363
364int
365ieee80211softmac_wx_get_genie(struct net_device *dev,
366 struct iw_request_info *info,
367 union iwreq_data *wrqu,
368 char *extra)
369{
370 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
371 unsigned long flags;
372 int err = 0;
373 int space = wrqu->data.length;
374
375 spin_lock_irqsave(&mac->lock, flags);
376
377 wrqu->data.length = 0;
378
379 if (mac->wpa.IE && mac->wpa.IElen) {
380 wrqu->data.length = mac->wpa.IElen;
381 if (mac->wpa.IElen <= space)
382 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
383 else
384 err = -E2BIG;
385 }
386 spin_unlock_irqrestore(&mac->lock, flags);
387 return err;
388}
389EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
390