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 /* 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);
269 if (unlikely(!mac->running)) {
274 switch (mac->txrates.default_rate) {
275 case IEEE80211_CCK_RATE_1MB:
276 data->bitrate.value = 1000000;
278 case IEEE80211_CCK_RATE_2MB:
279 data->bitrate.value = 2000000;
281 case IEEE80211_CCK_RATE_5MB:
282 data->bitrate.value = 5500000;
284 case IEEE80211_CCK_RATE_11MB:
285 data->bitrate.value = 11000000;
287 case IEEE80211_OFDM_RATE_6MB:
288 data->bitrate.value = 6000000;
290 case IEEE80211_OFDM_RATE_9MB:
291 data->bitrate.value = 9000000;
293 case IEEE80211_OFDM_RATE_12MB:
294 data->bitrate.value = 12000000;
296 case IEEE80211_OFDM_RATE_18MB:
297 data->bitrate.value = 18000000;
299 case IEEE80211_OFDM_RATE_24MB:
300 data->bitrate.value = 24000000;
302 case IEEE80211_OFDM_RATE_36MB:
303 data->bitrate.value = 36000000;
305 case IEEE80211_OFDM_RATE_48MB:
306 data->bitrate.value = 48000000;
308 case IEEE80211_OFDM_RATE_54MB:
309 data->bitrate.value = 54000000;
317 spin_unlock_irqrestore(&mac->lock, flags);
321 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
324 ieee80211softmac_wx_get_wap(struct net_device *net_dev,
325 struct iw_request_info *info,
326 union iwreq_data *data,
329 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
332 mutex_lock(&mac->associnfo.mutex);
333 if (mac->associnfo.bssvalid)
334 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
336 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
337 data->ap_addr.sa_family = ARPHRD_ETHER;
338 mutex_unlock(&mac->associnfo.mutex);
342 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
345 ieee80211softmac_wx_set_wap(struct net_device *net_dev,
346 struct iw_request_info *info,
347 union iwreq_data *data,
350 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
353 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
357 mutex_lock(&mac->associnfo.mutex);
358 if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
359 /* the bssid we have is not to be fixed any longer,
360 * and we should reassociate to the best AP. */
361 mac->associnfo.bssfixed = 0;
362 /* force reassociation */
363 mac->associnfo.bssvalid = 0;
364 if (mac->associnfo.associated)
365 schedule_delayed_work(&mac->associnfo.work, 0);
366 } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
367 /* the bssid we have is no longer fixed */
368 mac->associnfo.bssfixed = 0;
370 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
371 if (mac->associnfo.associating || mac->associnfo.associated) {
372 /* bssid unchanged and associated or associating - just return */
376 /* copy new value in data->ap_addr.sa_data to bssid */
377 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
379 /* tell the other code that this bssid should be used no matter what */
380 mac->associnfo.bssfixed = 1;
381 /* queue associate if new bssid or (old one again and not associated) */
382 schedule_delayed_work(&mac->associnfo.work, 0);
386 mutex_unlock(&mac->associnfo.mutex);
390 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
393 ieee80211softmac_wx_set_genie(struct net_device *dev,
394 struct iw_request_info *info,
395 union iwreq_data *wrqu,
398 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
404 mutex_lock(&mac->associnfo.mutex);
405 spin_lock_irqsave(&mac->lock, flags);
406 /* bleh. shouldn't be locked for that kmalloc... */
408 if (wrqu->data.length) {
409 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
410 /* this is an IE, so the length must be
411 * correct. Is it possible though that
412 * more than one IE is passed in?
417 if (mac->wpa.IEbuflen <= wrqu->data.length) {
418 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
425 mac->wpa.IEbuflen = wrqu->data.length;
427 memcpy(mac->wpa.IE, extra, wrqu->data.length);
428 dprintk(KERN_INFO PFX "generic IE set to ");
429 for (i=0;i<wrqu->data.length;i++)
430 dprintk("%.2x", (u8)mac->wpa.IE[i]);
432 mac->wpa.IElen = wrqu->data.length;
437 mac->wpa.IEbuflen = 0;
441 spin_unlock_irqrestore(&mac->lock, flags);
442 mutex_unlock(&mac->associnfo.mutex);
446 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
449 ieee80211softmac_wx_get_genie(struct net_device *dev,
450 struct iw_request_info *info,
451 union iwreq_data *wrqu,
454 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
457 int space = wrqu->data.length;
459 mutex_lock(&mac->associnfo.mutex);
460 spin_lock_irqsave(&mac->lock, flags);
462 wrqu->data.length = 0;
464 if (mac->wpa.IE && mac->wpa.IElen) {
465 wrqu->data.length = mac->wpa.IElen;
466 if (mac->wpa.IElen <= space)
467 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
471 spin_unlock_irqrestore(&mac->lock, flags);
472 mutex_unlock(&mac->associnfo.mutex);
476 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
479 ieee80211softmac_wx_set_mlme(struct net_device *dev,
480 struct iw_request_info *info,
481 union iwreq_data *wrqu,
484 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
485 struct iw_mlme *mlme = (struct iw_mlme *)extra;
486 u16 reason = cpu_to_le16(mlme->reason_code);
487 struct ieee80211softmac_network *net;
490 mutex_lock(&mac->associnfo.mutex);
492 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
493 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
499 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
501 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
504 err = ieee80211softmac_deauth_req(mac, net, reason);
506 case IW_MLME_DISASSOC:
507 ieee80211softmac_send_disassoc_req(mac, reason);
508 mac->associnfo.associated = 0;
509 mac->associnfo.associating = 0;
517 mutex_unlock(&mac->associnfo.mutex);
521 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);