Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hpa/linux...
[deliverable/linux.git] / net / ieee80211 / softmac / ieee80211softmac_wx.c
1 /*
2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
3 *
4 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
5 * Joseph Jezak <josejx@gentoo.org>
6 * Larry Finger <Larry.Finger@lwfinger.net>
7 * Danny van Dyk <kugelfang@gentoo.org>
8 * Michael Buesch <mbuesch@freenet.de>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
25 */
26
27 #include "ieee80211softmac_priv.h"
28
29 #include <net/iw_handler.h>
30 /* for is_broadcast_ether_addr and is_zero_ether_addr */
31 #include <linux/etherdevice.h>
32
33 int
34 ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
35 struct iw_request_info *info,
36 union iwreq_data *data,
37 char *extra)
38 {
39 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
40 return ieee80211softmac_start_scan(sm);
41 }
42 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
43
44
45 /* if we're still scanning, return -EAGAIN so that userspace tools
46 * can get the complete scan results, otherwise return 0. */
47 int
48 ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
49 struct iw_request_info *info,
50 union iwreq_data *data,
51 char *extra)
52 {
53 unsigned long flags;
54 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
55
56 spin_lock_irqsave(&sm->lock, flags);
57 if (sm->scanning) {
58 spin_unlock_irqrestore(&sm->lock, flags);
59 return -EAGAIN;
60 }
61 spin_unlock_irqrestore(&sm->lock, flags);
62 return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
63 }
64 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
65
66 int
67 ieee80211softmac_wx_set_essid(struct net_device *net_dev,
68 struct iw_request_info *info,
69 union iwreq_data *data,
70 char *extra)
71 {
72 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
73 struct ieee80211softmac_auth_queue_item *authptr;
74 int length = 0;
75
76 check_assoc_again:
77 mutex_lock(&sm->associnfo.mutex);
78 if((sm->associnfo.associating || sm->associnfo.associated) &&
79 (data->essid.flags && data->essid.length)) {
80 dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
81 /* Cancel assoc work */
82 cancel_delayed_work(&sm->associnfo.work);
83 /* We don't have to do this, but it's a little cleaner */
84 list_for_each_entry(authptr, &sm->auth_queue, list)
85 cancel_delayed_work(&authptr->work);
86 sm->associnfo.bssvalid = 0;
87 sm->associnfo.bssfixed = 0;
88 sm->associnfo.associating = 0;
89 sm->associnfo.associated = 0;
90 /* We must unlock to avoid deadlocks with the assoc workqueue
91 * on the associnfo.mutex */
92 mutex_unlock(&sm->associnfo.mutex);
93 flush_scheduled_work();
94 /* Avoid race! Check assoc status again. Maybe someone started an
95 * association while we flushed. */
96 goto check_assoc_again;
97 }
98
99 sm->associnfo.static_essid = 0;
100 sm->associnfo.assoc_wait = 0;
101
102 if (data->essid.flags && data->essid.length) {
103 length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
104 if (length) {
105 memcpy(sm->associnfo.req_essid.data, extra, length);
106 sm->associnfo.static_essid = 1;
107 }
108 }
109
110 /* set our requested ESSID length.
111 * If applicable, we have already copied the data in */
112 sm->associnfo.req_essid.len = length;
113
114 sm->associnfo.associating = 1;
115 /* queue lower level code to do work (if necessary) */
116 schedule_delayed_work(&sm->associnfo.work, 0);
117 out:
118 mutex_unlock(&sm->associnfo.mutex);
119
120 return 0;
121 }
122 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
123
124 int
125 ieee80211softmac_wx_get_essid(struct net_device *net_dev,
126 struct iw_request_info *info,
127 union iwreq_data *data,
128 char *extra)
129 {
130 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
131
132 mutex_lock(&sm->associnfo.mutex);
133 /* If all fails, return ANY (empty) */
134 data->essid.length = 0;
135 data->essid.flags = 0; /* active */
136
137 /* If we have a statically configured ESSID then return it */
138 if (sm->associnfo.static_essid) {
139 data->essid.length = sm->associnfo.req_essid.len;
140 data->essid.flags = 1; /* active */
141 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
142 dprintk(KERN_INFO PFX "Getting essid from req_essid\n");
143 } else if (sm->associnfo.associated || sm->associnfo.associating) {
144 /* If we're associating/associated, return that */
145 data->essid.length = sm->associnfo.associate_essid.len;
146 data->essid.flags = 1; /* active */
147 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
148 dprintk(KERN_INFO PFX "Getting essid from associate_essid\n");
149 }
150 mutex_unlock(&sm->associnfo.mutex);
151
152 return 0;
153 }
154 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
155
156 int
157 ieee80211softmac_wx_set_rate(struct net_device *net_dev,
158 struct iw_request_info *info,
159 union iwreq_data *data,
160 char *extra)
161 {
162 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
163 struct ieee80211_device *ieee = mac->ieee;
164 unsigned long flags;
165 s32 in_rate = data->bitrate.value;
166 u8 rate;
167 int is_ofdm = 0;
168 int err = -EINVAL;
169
170 if (in_rate == -1) {
171 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
172 in_rate = 24000000;
173 else
174 in_rate = 11000000;
175 }
176
177 switch (in_rate) {
178 case 1000000:
179 rate = IEEE80211_CCK_RATE_1MB;
180 break;
181 case 2000000:
182 rate = IEEE80211_CCK_RATE_2MB;
183 break;
184 case 5500000:
185 rate = IEEE80211_CCK_RATE_5MB;
186 break;
187 case 11000000:
188 rate = IEEE80211_CCK_RATE_11MB;
189 break;
190 case 6000000:
191 rate = IEEE80211_OFDM_RATE_6MB;
192 is_ofdm = 1;
193 break;
194 case 9000000:
195 rate = IEEE80211_OFDM_RATE_9MB;
196 is_ofdm = 1;
197 break;
198 case 12000000:
199 rate = IEEE80211_OFDM_RATE_12MB;
200 is_ofdm = 1;
201 break;
202 case 18000000:
203 rate = IEEE80211_OFDM_RATE_18MB;
204 is_ofdm = 1;
205 break;
206 case 24000000:
207 rate = IEEE80211_OFDM_RATE_24MB;
208 is_ofdm = 1;
209 break;
210 case 36000000:
211 rate = IEEE80211_OFDM_RATE_36MB;
212 is_ofdm = 1;
213 break;
214 case 48000000:
215 rate = IEEE80211_OFDM_RATE_48MB;
216 is_ofdm = 1;
217 break;
218 case 54000000:
219 rate = IEEE80211_OFDM_RATE_54MB;
220 is_ofdm = 1;
221 break;
222 default:
223 goto out;
224 }
225
226 spin_lock_irqsave(&mac->lock, flags);
227
228 /* Check if correct modulation for this PHY. */
229 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
230 goto out_unlock;
231
232 mac->txrates.user_rate = rate;
233 ieee80211softmac_recalc_txrates(mac);
234 err = 0;
235
236 out_unlock:
237 spin_unlock_irqrestore(&mac->lock, flags);
238 out:
239 return err;
240 }
241 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
242
243 int
244 ieee80211softmac_wx_get_rate(struct net_device *net_dev,
245 struct iw_request_info *info,
246 union iwreq_data *data,
247 char *extra)
248 {
249 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
250 unsigned long flags;
251 int err = -EINVAL;
252
253 spin_lock_irqsave(&mac->lock, flags);
254
255 if (unlikely(!mac->running)) {
256 err = -ENODEV;
257 goto out_unlock;
258 }
259
260 switch (mac->txrates.default_rate) {
261 case IEEE80211_CCK_RATE_1MB:
262 data->bitrate.value = 1000000;
263 break;
264 case IEEE80211_CCK_RATE_2MB:
265 data->bitrate.value = 2000000;
266 break;
267 case IEEE80211_CCK_RATE_5MB:
268 data->bitrate.value = 5500000;
269 break;
270 case IEEE80211_CCK_RATE_11MB:
271 data->bitrate.value = 11000000;
272 break;
273 case IEEE80211_OFDM_RATE_6MB:
274 data->bitrate.value = 6000000;
275 break;
276 case IEEE80211_OFDM_RATE_9MB:
277 data->bitrate.value = 9000000;
278 break;
279 case IEEE80211_OFDM_RATE_12MB:
280 data->bitrate.value = 12000000;
281 break;
282 case IEEE80211_OFDM_RATE_18MB:
283 data->bitrate.value = 18000000;
284 break;
285 case IEEE80211_OFDM_RATE_24MB:
286 data->bitrate.value = 24000000;
287 break;
288 case IEEE80211_OFDM_RATE_36MB:
289 data->bitrate.value = 36000000;
290 break;
291 case IEEE80211_OFDM_RATE_48MB:
292 data->bitrate.value = 48000000;
293 break;
294 case IEEE80211_OFDM_RATE_54MB:
295 data->bitrate.value = 54000000;
296 break;
297 default:
298 assert(0);
299 goto out_unlock;
300 }
301 err = 0;
302 out_unlock:
303 spin_unlock_irqrestore(&mac->lock, flags);
304
305 return err;
306 }
307 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
308
309 int
310 ieee80211softmac_wx_get_wap(struct net_device *net_dev,
311 struct iw_request_info *info,
312 union iwreq_data *data,
313 char *extra)
314 {
315 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
316 int err = 0;
317
318 mutex_lock(&mac->associnfo.mutex);
319 if (mac->associnfo.bssvalid)
320 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
321 else
322 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
323 data->ap_addr.sa_family = ARPHRD_ETHER;
324 mutex_unlock(&mac->associnfo.mutex);
325
326 return err;
327 }
328 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
329
330 int
331 ieee80211softmac_wx_set_wap(struct net_device *net_dev,
332 struct iw_request_info *info,
333 union iwreq_data *data,
334 char *extra)
335 {
336 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
337
338 /* sanity check */
339 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
340 return -EINVAL;
341 }
342
343 mutex_lock(&mac->associnfo.mutex);
344 if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
345 /* the bssid we have is not to be fixed any longer,
346 * and we should reassociate to the best AP. */
347 mac->associnfo.bssfixed = 0;
348 /* force reassociation */
349 mac->associnfo.bssvalid = 0;
350 if (mac->associnfo.associated)
351 schedule_delayed_work(&mac->associnfo.work, 0);
352 } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
353 /* the bssid we have is no longer fixed */
354 mac->associnfo.bssfixed = 0;
355 } else {
356 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
357 if (mac->associnfo.associating || mac->associnfo.associated) {
358 /* bssid unchanged and associated or associating - just return */
359 goto out;
360 }
361 } else {
362 /* copy new value in data->ap_addr.sa_data to bssid */
363 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
364 }
365 /* tell the other code that this bssid should be used no matter what */
366 mac->associnfo.bssfixed = 1;
367 /* queue associate if new bssid or (old one again and not associated) */
368 schedule_delayed_work(&mac->associnfo.work, 0);
369 }
370
371 out:
372 mutex_unlock(&mac->associnfo.mutex);
373
374 return 0;
375 }
376 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
377
378 int
379 ieee80211softmac_wx_set_genie(struct net_device *dev,
380 struct iw_request_info *info,
381 union iwreq_data *wrqu,
382 char *extra)
383 {
384 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
385 unsigned long flags;
386 int err = 0;
387 char *buf;
388 int i;
389
390 mutex_lock(&mac->associnfo.mutex);
391 spin_lock_irqsave(&mac->lock, flags);
392 /* bleh. shouldn't be locked for that kmalloc... */
393
394 if (wrqu->data.length) {
395 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
396 /* this is an IE, so the length must be
397 * correct. Is it possible though that
398 * more than one IE is passed in?
399 */
400 err = -EINVAL;
401 goto out;
402 }
403 if (mac->wpa.IEbuflen <= wrqu->data.length) {
404 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
405 if (!buf) {
406 err = -ENOMEM;
407 goto out;
408 }
409 kfree(mac->wpa.IE);
410 mac->wpa.IE = buf;
411 mac->wpa.IEbuflen = wrqu->data.length;
412 }
413 memcpy(mac->wpa.IE, extra, wrqu->data.length);
414 dprintk(KERN_INFO PFX "generic IE set to ");
415 for (i=0;i<wrqu->data.length;i++)
416 dprintk("%.2x", (u8)mac->wpa.IE[i]);
417 dprintk("\n");
418 mac->wpa.IElen = wrqu->data.length;
419 } else {
420 kfree(mac->wpa.IE);
421 mac->wpa.IE = NULL;
422 mac->wpa.IElen = 0;
423 mac->wpa.IEbuflen = 0;
424 }
425
426 out:
427 spin_unlock_irqrestore(&mac->lock, flags);
428 mutex_unlock(&mac->associnfo.mutex);
429
430 return err;
431 }
432 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
433
434 int
435 ieee80211softmac_wx_get_genie(struct net_device *dev,
436 struct iw_request_info *info,
437 union iwreq_data *wrqu,
438 char *extra)
439 {
440 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
441 unsigned long flags;
442 int err = 0;
443 int space = wrqu->data.length;
444
445 mutex_lock(&mac->associnfo.mutex);
446 spin_lock_irqsave(&mac->lock, flags);
447
448 wrqu->data.length = 0;
449
450 if (mac->wpa.IE && mac->wpa.IElen) {
451 wrqu->data.length = mac->wpa.IElen;
452 if (mac->wpa.IElen <= space)
453 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
454 else
455 err = -E2BIG;
456 }
457 spin_unlock_irqrestore(&mac->lock, flags);
458 mutex_unlock(&mac->associnfo.mutex);
459
460 return err;
461 }
462 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
463
464 int
465 ieee80211softmac_wx_set_mlme(struct net_device *dev,
466 struct iw_request_info *info,
467 union iwreq_data *wrqu,
468 char *extra)
469 {
470 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
471 struct iw_mlme *mlme = (struct iw_mlme *)extra;
472 u16 reason = cpu_to_le16(mlme->reason_code);
473 struct ieee80211softmac_network *net;
474 int err = -EINVAL;
475
476 mutex_lock(&mac->associnfo.mutex);
477
478 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
479 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
480 goto out;
481 }
482
483 switch (mlme->cmd) {
484 case IW_MLME_DEAUTH:
485 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
486 if (!net) {
487 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
488 goto out;
489 }
490 err = ieee80211softmac_deauth_req(mac, net, reason);
491 goto out;
492 case IW_MLME_DISASSOC:
493 ieee80211softmac_send_disassoc_req(mac, reason);
494 mac->associnfo.associated = 0;
495 mac->associnfo.associating = 0;
496 err = 0;
497 goto out;
498 default:
499 err = -EOPNOTSUPP;
500 }
501
502 out:
503 mutex_unlock(&mac->associnfo.mutex);
504
505 return err;
506 }
507 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);
This page took 0.049251 seconds and 6 git commands to generate.