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
;
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!
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
));
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();
107 spin_lock_irqsave(&sm
->lock
, flags
);
109 sm
->associnfo
.static_essid
= 0;
110 sm
->associnfo
.assoc_wait
= 0;
112 if (data
->essid
.flags
&& data
->essid
.length
&& extra
/*required?*/) {
113 length
= min(data
->essid
.length
- 1, IW_ESSID_MAX_SIZE
);
115 memcpy(sm
->associnfo
.req_essid
.data
, extra
, length
);
116 sm
->associnfo
.static_essid
= 1;
120 /* set our requested ESSID length.
121 * If applicable, we have already copied the data in */
122 sm
->associnfo
.req_essid
.len
= length
;
124 /* queue lower level code to do work (if necessary) */
125 schedule_work(&sm
->associnfo
.work
);
127 spin_unlock_irqrestore(&sm
->lock
, flags
);
130 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid
);
133 ieee80211softmac_wx_get_essid(struct net_device
*net_dev
,
134 struct iw_request_info
*info
,
135 union iwreq_data
*data
,
138 struct ieee80211softmac_device
*sm
= ieee80211_priv(net_dev
);
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 */
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
);
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
);
160 spin_unlock_irqrestore(&sm
->lock
, flags
);
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 /* 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
)
193 rate
= IEEE80211_CCK_RATE_1MB
;
196 rate
= IEEE80211_CCK_RATE_2MB
;
199 rate
= IEEE80211_CCK_RATE_5MB
;
202 rate
= IEEE80211_CCK_RATE_11MB
;
205 rate
= IEEE80211_OFDM_RATE_6MB
;
209 rate
= IEEE80211_OFDM_RATE_9MB
;
213 rate
= IEEE80211_OFDM_RATE_12MB
;
217 rate
= IEEE80211_OFDM_RATE_18MB
;
221 rate
= IEEE80211_OFDM_RATE_24MB
;
225 rate
= IEEE80211_OFDM_RATE_36MB
;
229 rate
= IEEE80211_OFDM_RATE_48MB
;
233 rate
= IEEE80211_OFDM_RATE_54MB
;
240 spin_lock_irqsave(&mac
->lock
, flags
);
242 /* Check if correct modulation for this PHY. */
243 if (is_ofdm
&& !(ieee
->modulation
& IEEE80211_OFDM_MODULATION
))
246 mac
->txrates
.user_rate
= rate
;
247 ieee80211softmac_recalc_txrates(mac
);
251 spin_unlock_irqrestore(&mac
->lock
, flags
);
255 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate
);
258 ieee80211softmac_wx_get_rate(struct net_device
*net_dev
,
259 struct iw_request_info
*info
,
260 union iwreq_data
*data
,
263 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
267 spin_lock_irqsave(&mac
->lock
, flags
);
268 switch (mac
->txrates
.default_rate
) {
269 case IEEE80211_CCK_RATE_1MB
:
270 data
->bitrate
.value
= 1000000;
272 case IEEE80211_CCK_RATE_2MB
:
273 data
->bitrate
.value
= 2000000;
275 case IEEE80211_CCK_RATE_5MB
:
276 data
->bitrate
.value
= 5500000;
278 case IEEE80211_CCK_RATE_11MB
:
279 data
->bitrate
.value
= 11000000;
281 case IEEE80211_OFDM_RATE_6MB
:
282 data
->bitrate
.value
= 6000000;
284 case IEEE80211_OFDM_RATE_9MB
:
285 data
->bitrate
.value
= 9000000;
287 case IEEE80211_OFDM_RATE_12MB
:
288 data
->bitrate
.value
= 12000000;
290 case IEEE80211_OFDM_RATE_18MB
:
291 data
->bitrate
.value
= 18000000;
293 case IEEE80211_OFDM_RATE_24MB
:
294 data
->bitrate
.value
= 24000000;
296 case IEEE80211_OFDM_RATE_36MB
:
297 data
->bitrate
.value
= 36000000;
299 case IEEE80211_OFDM_RATE_48MB
:
300 data
->bitrate
.value
= 48000000;
302 case IEEE80211_OFDM_RATE_54MB
:
303 data
->bitrate
.value
= 54000000;
311 spin_unlock_irqrestore(&mac
->lock
, flags
);
315 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate
);
318 ieee80211softmac_wx_get_wap(struct net_device
*net_dev
,
319 struct iw_request_info
*info
,
320 union iwreq_data
*data
,
323 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
327 spin_lock_irqsave(&mac
->lock
, flags
);
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 spin_unlock_irqrestore(&mac
->lock
, flags
);
336 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap
);
339 ieee80211softmac_wx_set_wap(struct net_device
*net_dev
,
340 struct iw_request_info
*info
,
341 union iwreq_data
*data
,
344 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
348 if (data
->ap_addr
.sa_family
!= ARPHRD_ETHER
) {
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;
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;
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 */
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_work(&mac
->associnfo
.work
);
381 spin_unlock_irqrestore(&mac
->lock
, flags
);
384 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap
);
387 ieee80211softmac_wx_set_genie(struct net_device
*dev
,
388 struct iw_request_info
*info
,
389 union iwreq_data
*wrqu
,
392 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
398 spin_lock_irqsave(&mac
->lock
, flags
);
399 /* bleh. shouldn't be locked for that kmalloc... */
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?
410 if (mac
->wpa
.IEbuflen
<= wrqu
->data
.length
) {
411 buf
= kmalloc(wrqu
->data
.length
, GFP_ATOMIC
);
418 mac
->wpa
.IEbuflen
= wrqu
->data
.length
;
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
]);
425 mac
->wpa
.IElen
= wrqu
->data
.length
;
430 mac
->wpa
.IEbuflen
= 0;
434 spin_unlock_irqrestore(&mac
->lock
, flags
);
437 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie
);
440 ieee80211softmac_wx_get_genie(struct net_device
*dev
,
441 struct iw_request_info
*info
,
442 union iwreq_data
*wrqu
,
445 struct ieee80211softmac_device
*mac
= ieee80211_priv(dev
);
448 int space
= wrqu
->data
.length
;
450 spin_lock_irqsave(&mac
->lock
, flags
);
452 wrqu
->data
.length
= 0;
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
);
461 spin_unlock_irqrestore(&mac
->lock
, flags
);
464 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie
);
467 ieee80211softmac_wx_set_mlme(struct net_device
*dev
,
468 struct iw_request_info
*info
,
469 union iwreq_data
*wrqu
,
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
;
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");
484 net
= ieee80211softmac_get_network_by_bssid_locked(mac
, mlme
->addr
.sa_data
);
486 printk(KERN_DEBUG PFX
"wx_set_mlme: we should know the net here...\n");
489 return ieee80211softmac_deauth_req(mac
, net
, reason
);
490 case IW_MLME_DISASSOC
:
491 ieee80211softmac_send_disassoc_req(mac
, reason
);
497 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme
);