]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/ieee80211/softmac/ieee80211softmac_wx.c
WorkStruct: make allyesconfig
[mirror_ubuntu-bionic-kernel.git] / net / ieee80211 / softmac / ieee80211softmac_wx.c
CommitLineData
370121e5
JB
1/*
2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
4855d25b 3 *
79859051
JB
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>
4855d25b
JB
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.
370121e5
JB
25 */
26
27#include "ieee80211softmac_priv.h"
28
29#include <net/iw_handler.h>
818667f7
JB
30/* for is_broadcast_ether_addr and is_zero_ether_addr */
31#include <linux/etherdevice.h>
370121e5
JB
32
33int
34ieee80211softmac_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}
42EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
43
44
ba2f8c18 45/* if we're still scanning, return -EAGAIN so that userspace tools
46 * can get the complete scan results, otherwise return 0. */
370121e5
JB
47int
48ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
49 struct iw_request_info *info,
50 union iwreq_data *data,
51 char *extra)
52{
ba2f8c18 53 unsigned long flags;
370121e5 54 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
ba2f8c18 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);
370121e5
JB
62 return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
63}
64EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
65
66int
67ieee80211softmac_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);
cb74c432
JJ
73 struct ieee80211softmac_network *n;
74 struct ieee80211softmac_auth_queue_item *authptr;
370121e5 75 int length = 0;
7c28ad2d
MB
76
77 mutex_lock(&sm->associnfo.mutex);
cb74c432
JJ
78
79 /* Check if we're already associating to this or another network
80 * If it's another network, cancel and start over with our new network
81 * If it's our network, ignore the change, we're already doing it!
82 */
7c28ad2d 83 if((sm->associnfo.associating || sm->associnfo.associated) &&
b978d027 84 (data->essid.flags && data->essid.length)) {
cb74c432
JJ
85 /* Get the associating network */
86 n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
b978d027 87 if(n && n->essid.len == data->essid.length &&
cb74c432
JJ
88 !memcmp(n->essid.data, extra, n->essid.len)) {
89 dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
90 MAC_ARG(sm->associnfo.bssid));
7c28ad2d 91 goto out;
cb74c432
JJ
92 } else {
93 dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
cb74c432
JJ
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;
cb74c432 101 flush_scheduled_work();
7c28ad2d
MB
102 sm->associnfo.associating = 0;
103 sm->associnfo.associated = 0;
cb74c432
JJ
104 }
105 }
106
107
370121e5 108 sm->associnfo.static_essid = 0;
cb74c432 109 sm->associnfo.assoc_wait = 0;
370121e5 110
b978d027
LF
111 if (data->essid.flags && data->essid.length) {
112 length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
370121e5
JB
113 if (length) {
114 memcpy(sm->associnfo.req_essid.data, extra, length);
115 sm->associnfo.static_essid = 1;
116 }
117 }
370121e5
JB
118
119 /* set our requested ESSID length.
120 * If applicable, we have already copied the data in */
121 sm->associnfo.req_essid.len = length;
122
7c28ad2d 123 sm->associnfo.associating = 1;
370121e5 124 /* queue lower level code to do work (if necessary) */
c4028958 125 schedule_delayed_work(&sm->associnfo.work, 0);
7c28ad2d
MB
126out:
127 mutex_unlock(&sm->associnfo.mutex);
370121e5 128
370121e5
JB
129 return 0;
130}
131EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
132
133int
134ieee80211softmac_wx_get_essid(struct net_device *net_dev,
135 struct iw_request_info *info,
136 union iwreq_data *data,
137 char *extra)
138{
139 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
370121e5 140
7c28ad2d 141 mutex_lock(&sm->associnfo.mutex);
370121e5
JB
142 /* If all fails, return ANY (empty) */
143 data->essid.length = 0;
144 data->essid.flags = 0; /* active */
145
146 /* If we have a statically configured ESSID then return it */
147 if (sm->associnfo.static_essid) {
148 data->essid.length = sm->associnfo.req_essid.len;
149 data->essid.flags = 1; /* active */
150 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
151 }
152
153 /* If we're associating/associated, return that */
7c28ad2d 154 if (sm->associnfo.associated || sm->associnfo.associating) {
370121e5
JB
155 data->essid.length = sm->associnfo.associate_essid.len;
156 data->essid.flags = 1; /* active */
157 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
158 }
7c28ad2d
MB
159 mutex_unlock(&sm->associnfo.mutex);
160
370121e5
JB
161 return 0;
162}
163EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
164
165int
166ieee80211softmac_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) {
2638fed7
DW
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)
370121e5 186 in_rate = 11000000;
2638fed7
DW
187 else
188 in_rate = 54000000;
370121e5
JB
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
8462fe3c
DD
246 mac->txrates.user_rate = rate;
247 ieee80211softmac_recalc_txrates(mac);
370121e5
JB
248 err = 0;
249
250out_unlock:
251 spin_unlock_irqrestore(&mac->lock, flags);
252out:
253 return err;
254}
255EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
256
257int
258ieee80211softmac_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;
310out_unlock:
311 spin_unlock_irqrestore(&mac->lock, flags);
312
313 return err;
314}
315EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
316
317int
318ieee80211softmac_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;
370121e5 325
7c28ad2d 326 mutex_lock(&mac->associnfo.mutex);
370121e5
JB
327 if (mac->associnfo.bssvalid)
328 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
329 else
330 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
331 data->ap_addr.sa_family = ARPHRD_ETHER;
7c28ad2d
MB
332 mutex_unlock(&mac->associnfo.mutex);
333
370121e5
JB
334 return err;
335}
336EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
337
338int
339ieee80211softmac_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);
370121e5
JB
345
346 /* sanity check */
347 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
348 return -EINVAL;
349 }
350
7c28ad2d 351 mutex_lock(&mac->associnfo.mutex);
818667f7
JB
352 if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
353 /* the bssid we have is not to be fixed any longer,
354 * and we should reassociate to the best AP. */
355 mac->associnfo.bssfixed = 0;
356 /* force reassociation */
357 mac->associnfo.bssvalid = 0;
7c28ad2d 358 if (mac->associnfo.associated)
c4028958 359 schedule_delayed_work(&mac->associnfo.work, 0);
818667f7
JB
360 } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
361 /* the bssid we have is no longer fixed */
362 mac->associnfo.bssfixed = 0;
370121e5
JB
363 } else {
364 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
7c28ad2d 365 if (mac->associnfo.associating || mac->associnfo.associated) {
370121e5
JB
366 /* bssid unchanged and associated or associating - just return */
367 goto out;
368 }
369 } else {
370 /* copy new value in data->ap_addr.sa_data to bssid */
371 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
818667f7
JB
372 }
373 /* tell the other code that this bssid should be used no matter what */
374 mac->associnfo.bssfixed = 1;
370121e5 375 /* queue associate if new bssid or (old one again and not associated) */
c4028958 376 schedule_delayed_work(&mac->associnfo.work, 0);
370121e5
JB
377 }
378
818667f7 379 out:
7c28ad2d
MB
380 mutex_unlock(&mac->associnfo.mutex);
381
370121e5
JB
382 return 0;
383}
384EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
385
386int
387ieee80211softmac_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;
7c28ad2d
MB
397
398 mutex_lock(&mac->associnfo.mutex);
370121e5
JB
399 spin_lock_irqsave(&mac->lock, flags);
400 /* bleh. shouldn't be locked for that kmalloc... */
401
402 if (wrqu->data.length) {
403 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
404 /* this is an IE, so the length must be
405 * correct. Is it possible though that
406 * more than one IE is passed in?
407 */
408 err = -EINVAL;
409 goto out;
410 }
411 if (mac->wpa.IEbuflen <= wrqu->data.length) {
412 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
413 if (!buf) {
414 err = -ENOMEM;
415 goto out;
416 }
417 kfree(mac->wpa.IE);
418 mac->wpa.IE = buf;
419 mac->wpa.IEbuflen = wrqu->data.length;
420 }
421 memcpy(mac->wpa.IE, extra, wrqu->data.length);
422 dprintk(KERN_INFO PFX "generic IE set to ");
423 for (i=0;i<wrqu->data.length;i++)
7bd6b918 424 dprintk("%.2x", (u8)mac->wpa.IE[i]);
370121e5
JB
425 dprintk("\n");
426 mac->wpa.IElen = wrqu->data.length;
427 } else {
428 kfree(mac->wpa.IE);
429 mac->wpa.IE = NULL;
430 mac->wpa.IElen = 0;
431 mac->wpa.IEbuflen = 0;
432 }
433
434 out:
435 spin_unlock_irqrestore(&mac->lock, flags);
7c28ad2d
MB
436 mutex_unlock(&mac->associnfo.mutex);
437
370121e5
JB
438 return err;
439}
440EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
441
442int
443ieee80211softmac_wx_get_genie(struct net_device *dev,
444 struct iw_request_info *info,
445 union iwreq_data *wrqu,
446 char *extra)
447{
448 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
449 unsigned long flags;
450 int err = 0;
451 int space = wrqu->data.length;
7c28ad2d
MB
452
453 mutex_lock(&mac->associnfo.mutex);
370121e5
JB
454 spin_lock_irqsave(&mac->lock, flags);
455
456 wrqu->data.length = 0;
457
458 if (mac->wpa.IE && mac->wpa.IElen) {
459 wrqu->data.length = mac->wpa.IElen;
460 if (mac->wpa.IElen <= space)
461 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
462 else
463 err = -E2BIG;
464 }
465 spin_unlock_irqrestore(&mac->lock, flags);
7c28ad2d
MB
466 mutex_lock(&mac->associnfo.mutex);
467
370121e5
JB
468 return err;
469}
470EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
471
9a1771e8
JB
472int
473ieee80211softmac_wx_set_mlme(struct net_device *dev,
474 struct iw_request_info *info,
475 union iwreq_data *wrqu,
476 char *extra)
477{
478 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
479 struct iw_mlme *mlme = (struct iw_mlme *)extra;
480 u16 reason = cpu_to_le16(mlme->reason_code);
481 struct ieee80211softmac_network *net;
7c28ad2d
MB
482 int err = -EINVAL;
483
484 mutex_lock(&mac->associnfo.mutex);
9a1771e8
JB
485
486 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
487 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
7c28ad2d 488 goto out;
9a1771e8
JB
489 }
490
491 switch (mlme->cmd) {
492 case IW_MLME_DEAUTH:
493 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
494 if (!net) {
495 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
7c28ad2d 496 goto out;
9a1771e8
JB
497 }
498 return ieee80211softmac_deauth_req(mac, net, reason);
499 case IW_MLME_DISASSOC:
6d92f83f 500 ieee80211softmac_send_disassoc_req(mac, reason);
7c28ad2d
MB
501 mac->associnfo.associated = 0;
502 mac->associnfo.associating = 0;
503 err = 0;
504 goto out;
9a1771e8 505 default:
7c28ad2d 506 err = -EOPNOTSUPP;
9a1771e8 507 }
7c28ad2d
MB
508
509out:
510 mutex_unlock(&mac->associnfo.mutex);
511
512 return err;
9a1771e8
JB
513}
514EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);