2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
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>
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.
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
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
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
27 #include "ieee80211softmac_priv.h"
29 #include <net/iw_handler.h>
30 /* for is_broadcast_ether_addr and is_zero_ether_addr */
31 #include <linux/etherdevice.h>
34 ieee80211softmac_wx_trigger_scan(struct net_device
*net_dev
,
35 struct iw_request_info
*info
,
36 union iwreq_data
*data
,
39 struct ieee80211softmac_device
*sm
= ieee80211_priv(net_dev
);
40 return ieee80211softmac_start_scan(sm
);
42 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan
);
45 /* if we're still scanning, return -EAGAIN so that userspace tools
46 * can get the complete scan results, otherwise return 0. */
48 ieee80211softmac_wx_get_scan_results(struct net_device
*net_dev
,
49 struct iw_request_info
*info
,
50 union iwreq_data
*data
,
54 struct ieee80211softmac_device
*sm
= ieee80211_priv(net_dev
);
56 spin_lock_irqsave(&sm
->lock
, flags
);
58 spin_unlock_irqrestore(&sm
->lock
, flags
);
61 spin_unlock_irqrestore(&sm
->lock
, flags
);
62 return ieee80211_wx_get_scan(sm
->ieee
, info
, data
, extra
);
64 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results
);
67 ieee80211softmac_wx_set_essid(struct net_device
*net_dev
,
68 struct iw_request_info
*info
,
69 union iwreq_data
*data
,
72 struct ieee80211softmac_device
*sm
= ieee80211_priv(net_dev
);
73 struct ieee80211softmac_network
*n
;
74 struct ieee80211softmac_auth_queue_item
*authptr
;
77 mutex_lock(&sm
->associnfo
.mutex
);
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!
83 if((sm
->associnfo
.associating
|| sm
->associnfo
.associated
) &&
84 (data
->essid
.flags
&& data
->essid
.length
)) {
85 /* Get the associating network */
86 n
= ieee80211softmac_get_network_by_bssid(sm
, sm
->associnfo
.bssid
);
87 if(n
&& n
->essid
.len
== data
->essid
.length
&&
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
));
93 dprintk(KERN_INFO PFX
"Canceling existing associate request!\n");
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 flush_scheduled_work();
102 sm
->associnfo
.associating
= 0;
103 sm
->associnfo
.associated
= 0;
108 sm
->associnfo
.static_essid
= 0;
109 sm
->associnfo
.assoc_wait
= 0;
111 if (data
->essid
.flags
&& data
->essid
.length
) {
112 length
= min((int)data
->essid
.length
, IW_ESSID_MAX_SIZE
);
114 memcpy(sm
->associnfo
.req_essid
.data
, extra
, length
);
115 sm
->associnfo
.static_essid
= 1;
119 /* set our requested ESSID length.
120 * If applicable, we have already copied the data in */
121 sm
->associnfo
.req_essid
.len
= length
;
123 sm
->associnfo
.associating
= 1;
124 /* queue lower level code to do work (if necessary) */
125 schedule_delayed_work(&sm
->associnfo
.work
, 0);
127 mutex_unlock(&sm
->associnfo
.mutex
);
131 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid
);
134 ieee80211softmac_wx_get_essid(struct net_device
*net_dev
,
135 struct iw_request_info
*info
,
136 union iwreq_data
*data
,
139 struct ieee80211softmac_device
*sm
= ieee80211_priv(net_dev
);
141 mutex_lock(&sm
->associnfo
.mutex
);
142 /* If all fails, return ANY (empty) */
143 data
->essid
.length
= 0;
144 data
->essid
.flags
= 0; /* active */
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
);
153 /* If we're associating/associated, return that */
154 if (sm
->associnfo
.associated
|| sm
->associnfo
.associating
) {
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
);
159 mutex_unlock(&sm
->associnfo
.mutex
);
163 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid
);
166 ieee80211softmac_wx_set_rate(struct net_device
*net_dev
,
167 struct iw_request_info
*info
,
168 union iwreq_data
*data
,
171 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
172 struct ieee80211_device
*ieee
= mac
->ieee
;
174 s32 in_rate
= data
->bitrate
.value
;
180 if (ieee
->modulation
& IEEE80211_OFDM_MODULATION
)
188 rate
= IEEE80211_CCK_RATE_1MB
;
191 rate
= IEEE80211_CCK_RATE_2MB
;
194 rate
= IEEE80211_CCK_RATE_5MB
;
197 rate
= IEEE80211_CCK_RATE_11MB
;
200 rate
= IEEE80211_OFDM_RATE_6MB
;
204 rate
= IEEE80211_OFDM_RATE_9MB
;
208 rate
= IEEE80211_OFDM_RATE_12MB
;
212 rate
= IEEE80211_OFDM_RATE_18MB
;
216 rate
= IEEE80211_OFDM_RATE_24MB
;
220 rate
= IEEE80211_OFDM_RATE_36MB
;
224 rate
= IEEE80211_OFDM_RATE_48MB
;
228 rate
= IEEE80211_OFDM_RATE_54MB
;
235 spin_lock_irqsave(&mac
->lock
, flags
);
237 /* Check if correct modulation for this PHY. */
238 if (is_ofdm
&& !(ieee
->modulation
& IEEE80211_OFDM_MODULATION
))
241 mac
->txrates
.user_rate
= rate
;
242 ieee80211softmac_recalc_txrates(mac
);
246 spin_unlock_irqrestore(&mac
->lock
, flags
);
250 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate
);
253 ieee80211softmac_wx_get_rate(struct net_device
*net_dev
,
254 struct iw_request_info
*info
,
255 union iwreq_data
*data
,
258 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
262 spin_lock_irqsave(&mac
->lock
, flags
);
264 if (unlikely(!mac
->running
)) {
269 switch (mac
->txrates
.default_rate
) {
270 case IEEE80211_CCK_RATE_1MB
:
271 data
->bitrate
.value
= 1000000;
273 case IEEE80211_CCK_RATE_2MB
:
274 data
->bitrate
.value
= 2000000;
276 case IEEE80211_CCK_RATE_5MB
:
277 data
->bitrate
.value
= 5500000;
279 case IEEE80211_CCK_RATE_11MB
:
280 data
->bitrate
.value
= 11000000;
282 case IEEE80211_OFDM_RATE_6MB
:
283 data
->bitrate
.value
= 6000000;
285 case IEEE80211_OFDM_RATE_9MB
:
286 data
->bitrate
.value
= 9000000;
288 case IEEE80211_OFDM_RATE_12MB
:
289 data
->bitrate
.value
= 12000000;
291 case IEEE80211_OFDM_RATE_18MB
:
292 data
->bitrate
.value
= 18000000;
294 case IEEE80211_OFDM_RATE_24MB
:
295 data
->bitrate
.value
= 24000000;
297 case IEEE80211_OFDM_RATE_36MB
:
298 data
->bitrate
.value
= 36000000;
300 case IEEE80211_OFDM_RATE_48MB
:
301 data
->bitrate
.value
= 48000000;
303 case IEEE80211_OFDM_RATE_54MB
:
304 data
->bitrate
.value
= 54000000;
312 spin_unlock_irqrestore(&mac
->lock
, flags
);
316 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate
);
319 ieee80211softmac_wx_get_wap(struct net_device
*net_dev
,
320 struct iw_request_info
*info
,
321 union iwreq_data
*data
,
324 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
327 mutex_lock(&mac
->associnfo
.mutex
);
328 if (mac
->associnfo
.bssvalid
)
329 memcpy(data
->ap_addr
.sa_data
, mac
->associnfo
.bssid
, ETH_ALEN
);
331 memset(data
->ap_addr
.sa_data
, 0xff, ETH_ALEN
);
332 data
->ap_addr
.sa_family
= ARPHRD_ETHER
;
333 mutex_unlock(&mac
->associnfo
.mutex
);
337 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap
);
340 ieee80211softmac_wx_set_wap(struct net_device
*net_dev
,
341 struct iw_request_info
*info
,
342 union iwreq_data
*data
,
345 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
348 if (data
->ap_addr
.sa_family
!= ARPHRD_ETHER
) {
352 mutex_lock(&mac
->associnfo
.mutex
);
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
->associnfo
.associated
)
360 schedule_delayed_work(&mac
->associnfo
.work
, 0);
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;
365 if (!memcmp(mac
->associnfo
.bssid
, data
->ap_addr
.sa_data
, ETH_ALEN
)) {
366 if (mac
->associnfo
.associating
|| mac
->associnfo
.associated
) {
367 /* bssid unchanged and associated or associating - just return */
371 /* copy new value in data->ap_addr.sa_data to bssid */
372 memcpy(mac
->associnfo
.bssid
, data
->ap_addr
.sa_data
, ETH_ALEN
);
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_delayed_work(&mac
->associnfo
.work
, 0);
381 mutex_unlock(&mac
->associnfo
.mutex
);
385 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap
);
388 ieee80211softmac_wx_set_genie(struct net_device
*dev
,
389 struct iw_request_info
*info
,
390 union iwreq_data
*wrqu
,
393 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
399 mutex_lock(&mac
->associnfo
.mutex
);
400 spin_lock_irqsave(&mac
->lock
, flags
);
401 /* bleh. shouldn't be locked for that kmalloc... */
403 if (wrqu
->data
.length
) {
404 if ((wrqu
->data
.length
< 2) || (extra
[1]+2 != wrqu
->data
.length
)) {
405 /* this is an IE, so the length must be
406 * correct. Is it possible though that
407 * more than one IE is passed in?
412 if (mac
->wpa
.IEbuflen
<= wrqu
->data
.length
) {
413 buf
= kmalloc(wrqu
->data
.length
, GFP_ATOMIC
);
420 mac
->wpa
.IEbuflen
= wrqu
->data
.length
;
422 memcpy(mac
->wpa
.IE
, extra
, wrqu
->data
.length
);
423 dprintk(KERN_INFO PFX
"generic IE set to ");
424 for (i
=0;i
<wrqu
->data
.length
;i
++)
425 dprintk("%.2x", (u8
)mac
->wpa
.IE
[i
]);
427 mac
->wpa
.IElen
= wrqu
->data
.length
;
432 mac
->wpa
.IEbuflen
= 0;
436 spin_unlock_irqrestore(&mac
->lock
, flags
);
437 mutex_unlock(&mac
->associnfo
.mutex
);
441 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie
);
444 ieee80211softmac_wx_get_genie(struct net_device
*dev
,
445 struct iw_request_info
*info
,
446 union iwreq_data
*wrqu
,
449 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
452 int space
= wrqu
->data
.length
;
454 mutex_lock(&mac
->associnfo
.mutex
);
455 spin_lock_irqsave(&mac
->lock
, flags
);
457 wrqu
->data
.length
= 0;
459 if (mac
->wpa
.IE
&& mac
->wpa
.IElen
) {
460 wrqu
->data
.length
= mac
->wpa
.IElen
;
461 if (mac
->wpa
.IElen
<= space
)
462 memcpy(extra
, mac
->wpa
.IE
, mac
->wpa
.IElen
);
466 spin_unlock_irqrestore(&mac
->lock
, flags
);
467 mutex_unlock(&mac
->associnfo
.mutex
);
471 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie
);
474 ieee80211softmac_wx_set_mlme(struct net_device
*dev
,
475 struct iw_request_info
*info
,
476 union iwreq_data
*wrqu
,
479 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
480 struct iw_mlme
*mlme
= (struct iw_mlme
*)extra
;
481 u16 reason
= cpu_to_le16(mlme
->reason_code
);
482 struct ieee80211softmac_network
*net
;
485 mutex_lock(&mac
->associnfo
.mutex
);
487 if (memcmp(mac
->associnfo
.bssid
, mlme
->addr
.sa_data
, ETH_ALEN
)) {
488 printk(KERN_DEBUG PFX
"wx_set_mlme: requested operation on net we don't use\n");
494 net
= ieee80211softmac_get_network_by_bssid_locked(mac
, mlme
->addr
.sa_data
);
496 printk(KERN_DEBUG PFX
"wx_set_mlme: we should know the net here...\n");
499 err
= ieee80211softmac_deauth_req(mac
, net
, reason
);
501 case IW_MLME_DISASSOC
:
502 ieee80211softmac_send_disassoc_req(mac
, reason
);
503 mac
->associnfo
.associated
= 0;
504 mac
->associnfo
.associating
= 0;
512 mutex_unlock(&mac
->associnfo
.mutex
);
516 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme
);