]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - net/ieee80211/softmac/ieee80211softmac_wx.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[mirror_ubuntu-zesty-kernel.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_network *n;
74 struct ieee80211softmac_auth_queue_item *authptr;
75 int length = 0;
76 unsigned long flags;
77
78 /* Check if we're already associating to this or another network
79 * If it's another network, cancel and start over with our new network
80 * If it's our network, ignore the change, we're already doing it!
81 */
82 if((sm->associnfo.associating || sm->associated) &&
83 (data->essid.flags && data->essid.length && extra)) {
84 /* Get the associating network */
85 n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
86 if(n && n->essid.len == (data->essid.length - 1) &&
87 !memcmp(n->essid.data, extra, n->essid.len)) {
88 dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
89 MAC_ARG(sm->associnfo.bssid));
90 return 0;
91 } else {
92 dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
93 spin_lock_irqsave(&sm->lock,flags);
94 /* Cancel assoc work */
95 cancel_delayed_work(&sm->associnfo.work);
96 /* We don't have to do this, but it's a little cleaner */
97 list_for_each_entry(authptr, &sm->auth_queue, list)
98 cancel_delayed_work(&authptr->work);
99 sm->associnfo.bssvalid = 0;
100 sm->associnfo.bssfixed = 0;
101 spin_unlock_irqrestore(&sm->lock,flags);
102 flush_scheduled_work();
103 }
104 }
105
106
107 spin_lock_irqsave(&sm->lock, flags);
108
109 sm->associnfo.static_essid = 0;
110 sm->associnfo.assoc_wait = 0;
111
112 if (data->essid.flags && data->essid.length && extra /*required?*/) {
113 length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
114 if (length) {
115 memcpy(sm->associnfo.req_essid.data, extra, length);
116 sm->associnfo.static_essid = 1;
117 }
118 }
119
120 /* set our requested ESSID length.
121 * If applicable, we have already copied the data in */
122 sm->associnfo.req_essid.len = length;
123
124 /* queue lower level code to do work (if necessary) */
125 schedule_work(&sm->associnfo.work);
126
127 spin_unlock_irqrestore(&sm->lock, flags);
128 return 0;
129 }
130 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
131
132 int
133 ieee80211softmac_wx_get_essid(struct net_device *net_dev,
134 struct iw_request_info *info,
135 union iwreq_data *data,
136 char *extra)
137 {
138 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
139 unsigned long flags;
140
141 /* avoid getting inconsistent information */
142 spin_lock_irqsave(&sm->lock, flags);
143 /* If all fails, return ANY (empty) */
144 data->essid.length = 0;
145 data->essid.flags = 0; /* active */
146
147 /* If we have a statically configured ESSID then return it */
148 if (sm->associnfo.static_essid) {
149 data->essid.length = sm->associnfo.req_essid.len;
150 data->essid.flags = 1; /* active */
151 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
152 }
153
154 /* If we're associating/associated, return that */
155 if (sm->associated || sm->associnfo.associating) {
156 data->essid.length = sm->associnfo.associate_essid.len;
157 data->essid.flags = 1; /* active */
158 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
159 }
160 spin_unlock_irqrestore(&sm->lock, flags);
161 return 0;
162 }
163 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
164
165 int
166 ieee80211softmac_wx_set_rate(struct net_device *net_dev,
167 struct iw_request_info *info,
168 union iwreq_data *data,
169 char *extra)
170 {
171 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
172 struct ieee80211_device *ieee = mac->ieee;
173 unsigned long flags;
174 s32 in_rate = data->bitrate.value;
175 u8 rate;
176 int is_ofdm = 0;
177 int err = -EINVAL;
178
179 if (in_rate == -1) {
180 /* FIXME: We don't correctly handle backing down to lower
181 rates, so 801.11g devices start off at 11M for now. People
182 can manually change it if they really need to, but 11M is
183 more reliable. Note similar logic in
184 ieee80211softmac_wx_set_rate() */
185 if (ieee->modulation & IEEE80211_CCK_MODULATION)
186 in_rate = 11000000;
187 else
188 in_rate = 54000000;
189 }
190
191 switch (in_rate) {
192 case 1000000:
193 rate = IEEE80211_CCK_RATE_1MB;
194 break;
195 case 2000000:
196 rate = IEEE80211_CCK_RATE_2MB;
197 break;
198 case 5500000:
199 rate = IEEE80211_CCK_RATE_5MB;
200 break;
201 case 11000000:
202 rate = IEEE80211_CCK_RATE_11MB;
203 break;
204 case 6000000:
205 rate = IEEE80211_OFDM_RATE_6MB;
206 is_ofdm = 1;
207 break;
208 case 9000000:
209 rate = IEEE80211_OFDM_RATE_9MB;
210 is_ofdm = 1;
211 break;
212 case 12000000:
213 rate = IEEE80211_OFDM_RATE_12MB;
214 is_ofdm = 1;
215 break;
216 case 18000000:
217 rate = IEEE80211_OFDM_RATE_18MB;
218 is_ofdm = 1;
219 break;
220 case 24000000:
221 rate = IEEE80211_OFDM_RATE_24MB;
222 is_ofdm = 1;
223 break;
224 case 36000000:
225 rate = IEEE80211_OFDM_RATE_36MB;
226 is_ofdm = 1;
227 break;
228 case 48000000:
229 rate = IEEE80211_OFDM_RATE_48MB;
230 is_ofdm = 1;
231 break;
232 case 54000000:
233 rate = IEEE80211_OFDM_RATE_54MB;
234 is_ofdm = 1;
235 break;
236 default:
237 goto out;
238 }
239
240 spin_lock_irqsave(&mac->lock, flags);
241
242 /* Check if correct modulation for this PHY. */
243 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
244 goto out_unlock;
245
246 mac->txrates.user_rate = rate;
247 ieee80211softmac_recalc_txrates(mac);
248 err = 0;
249
250 out_unlock:
251 spin_unlock_irqrestore(&mac->lock, flags);
252 out:
253 return err;
254 }
255 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
256
257 int
258 ieee80211softmac_wx_get_rate(struct net_device *net_dev,
259 struct iw_request_info *info,
260 union iwreq_data *data,
261 char *extra)
262 {
263 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
264 unsigned long flags;
265 int err = -EINVAL;
266
267 spin_lock_irqsave(&mac->lock, flags);
268 switch (mac->txrates.default_rate) {
269 case IEEE80211_CCK_RATE_1MB:
270 data->bitrate.value = 1000000;
271 break;
272 case IEEE80211_CCK_RATE_2MB:
273 data->bitrate.value = 2000000;
274 break;
275 case IEEE80211_CCK_RATE_5MB:
276 data->bitrate.value = 5500000;
277 break;
278 case IEEE80211_CCK_RATE_11MB:
279 data->bitrate.value = 11000000;
280 break;
281 case IEEE80211_OFDM_RATE_6MB:
282 data->bitrate.value = 6000000;
283 break;
284 case IEEE80211_OFDM_RATE_9MB:
285 data->bitrate.value = 9000000;
286 break;
287 case IEEE80211_OFDM_RATE_12MB:
288 data->bitrate.value = 12000000;
289 break;
290 case IEEE80211_OFDM_RATE_18MB:
291 data->bitrate.value = 18000000;
292 break;
293 case IEEE80211_OFDM_RATE_24MB:
294 data->bitrate.value = 24000000;
295 break;
296 case IEEE80211_OFDM_RATE_36MB:
297 data->bitrate.value = 36000000;
298 break;
299 case IEEE80211_OFDM_RATE_48MB:
300 data->bitrate.value = 48000000;
301 break;
302 case IEEE80211_OFDM_RATE_54MB:
303 data->bitrate.value = 54000000;
304 break;
305 default:
306 assert(0);
307 goto out_unlock;
308 }
309 err = 0;
310 out_unlock:
311 spin_unlock_irqrestore(&mac->lock, flags);
312
313 return err;
314 }
315 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
316
317 int
318 ieee80211softmac_wx_get_wap(struct net_device *net_dev,
319 struct iw_request_info *info,
320 union iwreq_data *data,
321 char *extra)
322 {
323 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
324 int err = 0;
325 unsigned long flags;
326
327 spin_lock_irqsave(&mac->lock, flags);
328 if (mac->associnfo.bssvalid)
329 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
330 else
331 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
332 data->ap_addr.sa_family = ARPHRD_ETHER;
333 spin_unlock_irqrestore(&mac->lock, flags);
334 return err;
335 }
336 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
337
338 int
339 ieee80211softmac_wx_set_wap(struct net_device *net_dev,
340 struct iw_request_info *info,
341 union iwreq_data *data,
342 char *extra)
343 {
344 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
345 unsigned long flags;
346
347 /* sanity check */
348 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
349 return -EINVAL;
350 }
351
352 spin_lock_irqsave(&mac->lock, flags);
353 if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
354 /* the bssid we have is not to be fixed any longer,
355 * and we should reassociate to the best AP. */
356 mac->associnfo.bssfixed = 0;
357 /* force reassociation */
358 mac->associnfo.bssvalid = 0;
359 if (mac->associated)
360 schedule_work(&mac->associnfo.work);
361 } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
362 /* the bssid we have is no longer fixed */
363 mac->associnfo.bssfixed = 0;
364 } else {
365 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
366 if (mac->associnfo.associating || mac->associated) {
367 /* bssid unchanged and associated or associating - just return */
368 goto out;
369 }
370 } else {
371 /* copy new value in data->ap_addr.sa_data to bssid */
372 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
373 }
374 /* tell the other code that this bssid should be used no matter what */
375 mac->associnfo.bssfixed = 1;
376 /* queue associate if new bssid or (old one again and not associated) */
377 schedule_work(&mac->associnfo.work);
378 }
379
380 out:
381 spin_unlock_irqrestore(&mac->lock, flags);
382 return 0;
383 }
384 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
385
386 int
387 ieee80211softmac_wx_set_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 char *buf;
396 int i;
397
398 spin_lock_irqsave(&mac->lock, flags);
399 /* bleh. shouldn't be locked for that kmalloc... */
400
401 if (wrqu->data.length) {
402 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
403 /* this is an IE, so the length must be
404 * correct. Is it possible though that
405 * more than one IE is passed in?
406 */
407 err = -EINVAL;
408 goto out;
409 }
410 if (mac->wpa.IEbuflen <= wrqu->data.length) {
411 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
412 if (!buf) {
413 err = -ENOMEM;
414 goto out;
415 }
416 kfree(mac->wpa.IE);
417 mac->wpa.IE = buf;
418 mac->wpa.IEbuflen = wrqu->data.length;
419 }
420 memcpy(mac->wpa.IE, extra, wrqu->data.length);
421 dprintk(KERN_INFO PFX "generic IE set to ");
422 for (i=0;i<wrqu->data.length;i++)
423 dprintk("%.2x", (u8)mac->wpa.IE[i]);
424 dprintk("\n");
425 mac->wpa.IElen = wrqu->data.length;
426 } else {
427 kfree(mac->wpa.IE);
428 mac->wpa.IE = NULL;
429 mac->wpa.IElen = 0;
430 mac->wpa.IEbuflen = 0;
431 }
432
433 out:
434 spin_unlock_irqrestore(&mac->lock, flags);
435 return err;
436 }
437 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
438
439 int
440 ieee80211softmac_wx_get_genie(struct net_device *dev,
441 struct iw_request_info *info,
442 union iwreq_data *wrqu,
443 char *extra)
444 {
445 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
446 unsigned long flags;
447 int err = 0;
448 int space = wrqu->data.length;
449
450 spin_lock_irqsave(&mac->lock, flags);
451
452 wrqu->data.length = 0;
453
454 if (mac->wpa.IE && mac->wpa.IElen) {
455 wrqu->data.length = mac->wpa.IElen;
456 if (mac->wpa.IElen <= space)
457 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
458 else
459 err = -E2BIG;
460 }
461 spin_unlock_irqrestore(&mac->lock, flags);
462 return err;
463 }
464 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
465
466 int
467 ieee80211softmac_wx_set_mlme(struct net_device *dev,
468 struct iw_request_info *info,
469 union iwreq_data *wrqu,
470 char *extra)
471 {
472 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
473 struct iw_mlme *mlme = (struct iw_mlme *)extra;
474 u16 reason = cpu_to_le16(mlme->reason_code);
475 struct ieee80211softmac_network *net;
476
477 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
478 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
479 return -EINVAL;
480 }
481
482 switch (mlme->cmd) {
483 case IW_MLME_DEAUTH:
484 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
485 if (!net) {
486 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
487 return -EINVAL;
488 }
489 return ieee80211softmac_deauth_req(mac, net, reason);
490 case IW_MLME_DISASSOC:
491 ieee80211softmac_send_disassoc_req(mac, reason);
492 return 0;
493 default:
494 return -EOPNOTSUPP;
495 }
496 }
497 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);