aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee80211/softmac/ieee80211softmac_wx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee80211/softmac/ieee80211softmac_wx.c')
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
new file mode 100644
index 000000000000..e1a9bc6d36ff
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -0,0 +1,412 @@
1/*
2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
3 *
4 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
5 * Joseph Jezak <josejx@gentoo.org>
6 * Larry Finger <Larry.Finger@lwfinger.net>
7 * Danny van Dyk <kugelfang@gentoo.org>
8 * Michael Buesch <mbuesch@freenet.de>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
25 */
26
27#include "ieee80211softmac_priv.h"
28
29#include <net/iw_handler.h>
30
31
32int
33ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
34 struct iw_request_info *info,
35 union iwreq_data *data,
36 char *extra)
37{
38 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
39 return ieee80211softmac_start_scan(sm);
40}
41EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
42
43
44int
45ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
46 struct iw_request_info *info,
47 union iwreq_data *data,
48 char *extra)
49{
50 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
51 return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
52}
53EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
54
55int
56ieee80211softmac_wx_set_essid(struct net_device *net_dev,
57 struct iw_request_info *info,
58 union iwreq_data *data,
59 char *extra)
60{
61 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
62 int length = 0;
63 unsigned long flags;
64
65 spin_lock_irqsave(&sm->lock, flags);
66
67 sm->associnfo.static_essid = 0;
68
69 if (data->essid.flags && data->essid.length && extra /*required?*/) {
70 length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
71 if (length) {
72 memcpy(sm->associnfo.req_essid.data, extra, length);
73 sm->associnfo.static_essid = 1;
74 }
75 }
76 sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
77
78 /* set our requested ESSID length.
79 * If applicable, we have already copied the data in */
80 sm->associnfo.req_essid.len = length;
81
82 /* queue lower level code to do work (if necessary) */
83 schedule_work(&sm->associnfo.work);
84
85 spin_unlock_irqrestore(&sm->lock, flags);
86 return 0;
87}
88EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
89
90int
91ieee80211softmac_wx_get_essid(struct net_device *net_dev,
92 struct iw_request_info *info,
93 union iwreq_data *data,
94 char *extra)
95{
96 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
97 unsigned long flags;
98
99 /* avoid getting inconsistent information */
100 spin_lock_irqsave(&sm->lock, flags);
101 /* If all fails, return ANY (empty) */
102 data->essid.length = 0;
103 data->essid.flags = 0; /* active */
104
105 /* If we have a statically configured ESSID then return it */
106 if (sm->associnfo.static_essid) {
107 data->essid.length = sm->associnfo.req_essid.len;
108 data->essid.flags = 1; /* active */
109 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
110 }
111
112 /* If we're associating/associated, return that */
113 if (sm->associated || sm->associnfo.associating) {
114 data->essid.length = sm->associnfo.associate_essid.len;
115 data->essid.flags = 1; /* active */
116 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
117 }
118 spin_unlock_irqrestore(&sm->lock, flags);
119 return 0;
120}
121EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
122
123int
124ieee80211softmac_wx_set_rate(struct net_device *net_dev,
125 struct iw_request_info *info,
126 union iwreq_data *data,
127 char *extra)
128{
129 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
130 struct ieee80211_device *ieee = mac->ieee;
131 unsigned long flags;
132 s32 in_rate = data->bitrate.value;
133 u8 rate;
134 int is_ofdm = 0;
135 int err = -EINVAL;
136
137 if (in_rate == -1) {
138 /* automatic detect */
139 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
140 in_rate = 54000000;
141 else
142 in_rate = 11000000;
143 }
144
145 switch (in_rate) {
146 case 1000000:
147 rate = IEEE80211_CCK_RATE_1MB;
148 break;
149 case 2000000:
150 rate = IEEE80211_CCK_RATE_2MB;
151 break;
152 case 5500000:
153 rate = IEEE80211_CCK_RATE_5MB;
154 break;
155 case 11000000:
156 rate = IEEE80211_CCK_RATE_11MB;
157 break;
158 case 6000000:
159 rate = IEEE80211_OFDM_RATE_6MB;
160 is_ofdm = 1;
161 break;
162 case 9000000:
163 rate = IEEE80211_OFDM_RATE_9MB;
164 is_ofdm = 1;
165 break;
166 case 12000000:
167 rate = IEEE80211_OFDM_RATE_12MB;
168 is_ofdm = 1;
169 break;
170 case 18000000:
171 rate = IEEE80211_OFDM_RATE_18MB;
172 is_ofdm = 1;
173 break;
174 case 24000000:
175 rate = IEEE80211_OFDM_RATE_24MB;
176 is_ofdm = 1;
177 break;
178 case 36000000:
179 rate = IEEE80211_OFDM_RATE_36MB;
180 is_ofdm = 1;
181 break;
182 case 48000000:
183 rate = IEEE80211_OFDM_RATE_48MB;
184 is_ofdm = 1;
185 break;
186 case 54000000:
187 rate = IEEE80211_OFDM_RATE_54MB;
188 is_ofdm = 1;
189 break;
190 default:
191 goto out;
192 }
193
194 spin_lock_irqsave(&mac->lock, flags);
195
196 /* Check if correct modulation for this PHY. */
197 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
198 goto out_unlock;
199
200 mac->txrates.default_rate = rate;
201 mac->txrates.default_fallback = lower_rate(mac, rate);
202 err = 0;
203
204out_unlock:
205 spin_unlock_irqrestore(&mac->lock, flags);
206out:
207 return err;
208}
209EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
210
211int
212ieee80211softmac_wx_get_rate(struct net_device *net_dev,
213 struct iw_request_info *info,
214 union iwreq_data *data,
215 char *extra)
216{
217 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
218 unsigned long flags;
219 int err = -EINVAL;
220
221 spin_lock_irqsave(&mac->lock, flags);
222 switch (mac->txrates.default_rate) {
223 case IEEE80211_CCK_RATE_1MB:
224 data->bitrate.value = 1000000;
225 break;
226 case IEEE80211_CCK_RATE_2MB:
227 data->bitrate.value = 2000000;
228 break;
229 case IEEE80211_CCK_RATE_5MB:
230 data->bitrate.value = 5500000;
231 break;
232 case IEEE80211_CCK_RATE_11MB:
233 data->bitrate.value = 11000000;
234 break;
235 case IEEE80211_OFDM_RATE_6MB:
236 data->bitrate.value = 6000000;
237 break;
238 case IEEE80211_OFDM_RATE_9MB:
239 data->bitrate.value = 9000000;
240 break;
241 case IEEE80211_OFDM_RATE_12MB:
242 data->bitrate.value = 12000000;
243 break;
244 case IEEE80211_OFDM_RATE_18MB:
245 data->bitrate.value = 18000000;
246 break;
247 case IEEE80211_OFDM_RATE_24MB:
248 data->bitrate.value = 24000000;
249 break;
250 case IEEE80211_OFDM_RATE_36MB:
251 data->bitrate.value = 36000000;
252 break;
253 case IEEE80211_OFDM_RATE_48MB:
254 data->bitrate.value = 48000000;
255 break;
256 case IEEE80211_OFDM_RATE_54MB:
257 data->bitrate.value = 54000000;
258 break;
259 default:
260 assert(0);
261 goto out_unlock;
262 }
263 err = 0;
264out_unlock:
265 spin_unlock_irqrestore(&mac->lock, flags);
266
267 return err;
268}
269EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
270
271int
272ieee80211softmac_wx_get_wap(struct net_device *net_dev,
273 struct iw_request_info *info,
274 union iwreq_data *data,
275 char *extra)
276{
277 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
278 int err = 0;
279 unsigned long flags;
280
281 spin_lock_irqsave(&mac->lock, flags);
282 if (mac->associnfo.bssvalid)
283 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
284 else
285 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
286 data->ap_addr.sa_family = ARPHRD_ETHER;
287 spin_unlock_irqrestore(&mac->lock, flags);
288 return err;
289}
290EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
291
292int
293ieee80211softmac_wx_set_wap(struct net_device *net_dev,
294 struct iw_request_info *info,
295 union iwreq_data *data,
296 char *extra)
297{
298 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
299 static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
300 static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
301 unsigned long flags;
302
303 /* sanity check */
304 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
305 return -EINVAL;
306 }
307
308 spin_lock_irqsave(&mac->lock, flags);
309 if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
310 !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
311 schedule_work(&mac->associnfo.work);
312 goto out;
313 } else {
314 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
315 if (mac->associnfo.associating || mac->associated) {
316 /* bssid unchanged and associated or associating - just return */
317 goto out;
318 }
319 } else {
320 /* copy new value in data->ap_addr.sa_data to bssid */
321 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
322 }
323 /* queue associate if new bssid or (old one again and not associated) */
324 schedule_work(&mac->associnfo.work);
325 }
326
327out:
328 spin_unlock_irqrestore(&mac->lock, flags);
329 return 0;
330}
331EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
332
333int
334ieee80211softmac_wx_set_genie(struct net_device *dev,
335 struct iw_request_info *info,
336 union iwreq_data *wrqu,
337 char *extra)
338{
339 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
340 unsigned long flags;
341 int err = 0;
342 char *buf;
343 int i;
344
345 spin_lock_irqsave(&mac->lock, flags);
346 /* bleh. shouldn't be locked for that kmalloc... */
347
348 if (wrqu->data.length) {
349 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
350 /* this is an IE, so the length must be
351 * correct. Is it possible though that
352 * more than one IE is passed in?
353 */
354 err = -EINVAL;
355 goto out;
356 }
357 if (mac->wpa.IEbuflen <= wrqu->data.length) {
358 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
359 if (!buf) {
360 err = -ENOMEM;
361 goto out;
362 }
363 kfree(mac->wpa.IE);
364 mac->wpa.IE = buf;
365 mac->wpa.IEbuflen = wrqu->data.length;
366 }
367 memcpy(mac->wpa.IE, extra, wrqu->data.length);
368 dprintk(KERN_INFO PFX "generic IE set to ");
369 for (i=0;i<wrqu->data.length;i++)
370 dprintk("%.2x", mac->wpa.IE[i]);
371 dprintk("\n");
372 mac->wpa.IElen = wrqu->data.length;
373 } else {
374 kfree(mac->wpa.IE);
375 mac->wpa.IE = NULL;
376 mac->wpa.IElen = 0;
377 mac->wpa.IEbuflen = 0;
378 }
379
380 out:
381 spin_unlock_irqrestore(&mac->lock, flags);
382 return err;
383}
384EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
385
386int
387ieee80211softmac_wx_get_genie(struct net_device *dev,
388 struct iw_request_info *info,
389 union iwreq_data *wrqu,
390 char *extra)
391{
392 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
393 unsigned long flags;
394 int err = 0;
395 int space = wrqu->data.length;
396
397 spin_lock_irqsave(&mac->lock, flags);
398
399 wrqu->data.length = 0;
400
401 if (mac->wpa.IE && mac->wpa.IElen) {
402 wrqu->data.length = mac->wpa.IElen;
403 if (mac->wpa.IElen <= space)
404 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
405 else
406 err = -E2BIG;
407 }
408 spin_unlock_irqrestore(&mac->lock, flags);
409 return err;
410}
411EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
412