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 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 sm->associnfo.associating = 0;
102 sm->associnfo.associated = 0;
103 /* We must unlock to avoid deadlocks with the assoc workqueue
104 * on the associnfo.mutex */
105 mutex_unlock(&sm->associnfo.mutex);
106 flush_scheduled_work();
107 /* Avoid race! Check assoc status again. Maybe someone started an
108 * association while we flushed. */
109 goto check_assoc_again;
113 sm->associnfo.static_essid = 0;
114 sm->associnfo.assoc_wait = 0;
116 if (data->essid.flags && data->essid.length) {
117 length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
119 memcpy(sm->associnfo.req_essid.data, extra, length);
120 sm->associnfo.static_essid = 1;
124 /* set our requested ESSID length.
125 * If applicable, we have already copied the data in */
126 sm->associnfo.req_essid.len = length;
128 sm->associnfo.associating = 1;
129 /* queue lower level code to do work (if necessary) */
130 schedule_delayed_work(&sm->associnfo.work, 0);
132 mutex_unlock(&sm->associnfo.mutex);
136 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
139 ieee80211softmac_wx_get_essid(struct net_device *net_dev,
140 struct iw_request_info *info,
141 union iwreq_data *data,
144 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
146 mutex_lock(&sm->associnfo.mutex);
147 /* If all fails, return ANY (empty) */
148 data->essid.length = 0;
149 data->essid.flags = 0; /* active */
151 /* If we have a statically configured ESSID then return it */
152 if (sm->associnfo.static_essid) {
153 data->essid.length = sm->associnfo.req_essid.len;
154 data->essid.flags = 1; /* active */
155 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
158 /* If we're associating/associated, return that */
159 if (sm->associnfo.associated || sm->associnfo.associating) {
160 data->essid.length = sm->associnfo.associate_essid.len;
161 data->essid.flags = 1; /* active */
162 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
164 mutex_unlock(&sm->associnfo.mutex);
168 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
171 ieee80211softmac_wx_set_rate(struct net_device *net_dev,
172 struct iw_request_info *info,
173 union iwreq_data *data,
176 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
177 struct ieee80211_device *ieee = mac->ieee;
179 s32 in_rate = data->bitrate.value;
185 /* FIXME: We don't correctly handle backing down to lower
186 rates, so 801.11g devices start off at 11M for now. People
187 can manually change it if they really need to, but 11M is
188 more reliable. Note similar logic in
189 ieee80211softmac_wx_set_rate() */
190 if (ieee->modulation & IEEE80211_CCK_MODULATION)
198 rate = IEEE80211_CCK_RATE_1MB;
201 rate = IEEE80211_CCK_RATE_2MB;
204 rate = IEEE80211_CCK_RATE_5MB;
207 rate = IEEE80211_CCK_RATE_11MB;
210 rate = IEEE80211_OFDM_RATE_6MB;
214 rate = IEEE80211_OFDM_RATE_9MB;
218 rate = IEEE80211_OFDM_RATE_12MB;
222 rate = IEEE80211_OFDM_RATE_18MB;
226 rate = IEEE80211_OFDM_RATE_24MB;
230 rate = IEEE80211_OFDM_RATE_36MB;
234 rate = IEEE80211_OFDM_RATE_48MB;
238 rate = IEEE80211_OFDM_RATE_54MB;
245 spin_lock_irqsave(&mac->lock, flags);
247 /* Check if correct modulation for this PHY. */
248 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
251 mac->txrates.user_rate = rate;
252 ieee80211softmac_recalc_txrates(mac);
256 spin_unlock_irqrestore(&mac->lock, flags);
260 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
263 ieee80211softmac_wx_get_rate(struct net_device *net_dev,
264 struct iw_request_info *info,
265 union iwreq_data *data,
268 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
272 spin_lock_irqsave(&mac->lock, flags);
274 if (unlikely(!mac->running)) {
279 switch (mac->txrates.default_rate) {
280 case IEEE80211_CCK_RATE_1MB:
281 data->bitrate.value = 1000000;
283 case IEEE80211_CCK_RATE_2MB:
284 data->bitrate.value = 2000000;
286 case IEEE80211_CCK_RATE_5MB:
287 data->bitrate.value = 5500000;
289 case IEEE80211_CCK_RATE_11MB:
290 data->bitrate.value = 11000000;
292 case IEEE80211_OFDM_RATE_6MB:
293 data->bitrate.value = 6000000;
295 case IEEE80211_OFDM_RATE_9MB:
296 data->bitrate.value = 9000000;
298 case IEEE80211_OFDM_RATE_12MB:
299 data->bitrate.value = 12000000;
301 case IEEE80211_OFDM_RATE_18MB:
302 data->bitrate.value = 18000000;
304 case IEEE80211_OFDM_RATE_24MB:
305 data->bitrate.value = 24000000;
307 case IEEE80211_OFDM_RATE_36MB:
308 data->bitrate.value = 36000000;
310 case IEEE80211_OFDM_RATE_48MB:
311 data->bitrate.value = 48000000;
313 case IEEE80211_OFDM_RATE_54MB:
314 data->bitrate.value = 54000000;
322 spin_unlock_irqrestore(&mac->lock, flags);
326 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
329 ieee80211softmac_wx_get_wap(struct net_device *net_dev,
330 struct iw_request_info *info,
331 union iwreq_data *data,
334 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
337 mutex_lock(&mac->associnfo.mutex);
338 if (mac->associnfo.bssvalid)
339 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
341 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
342 data->ap_addr.sa_family = ARPHRD_ETHER;
343 mutex_unlock(&mac->associnfo.mutex);
347 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
350 ieee80211softmac_wx_set_wap(struct net_device *net_dev,
351 struct iw_request_info *info,
352 union iwreq_data *data,
355 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
358 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
362 mutex_lock(&mac->associnfo.mutex);
363 if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
364 /* the bssid we have is not to be fixed any longer,
365 * and we should reassociate to the best AP. */
366 mac->associnfo.bssfixed = 0;
367 /* force reassociation */
368 mac->associnfo.bssvalid = 0;
369 if (mac->associnfo.associated)
370 schedule_delayed_work(&mac->associnfo.work, 0);
371 } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
372 /* the bssid we have is no longer fixed */
373 mac->associnfo.bssfixed = 0;
375 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
376 if (mac->associnfo.associating || mac->associnfo.associated) {
377 /* bssid unchanged and associated or associating - just return */
381 /* copy new value in data->ap_addr.sa_data to bssid */
382 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
384 /* tell the other code that this bssid should be used no matter what */
385 mac->associnfo.bssfixed = 1;
386 /* queue associate if new bssid or (old one again and not associated) */
387 schedule_delayed_work(&mac->associnfo.work, 0);
391 mutex_unlock(&mac->associnfo.mutex);
395 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
398 ieee80211softmac_wx_set_genie(struct net_device *dev,
399 struct iw_request_info *info,
400 union iwreq_data *wrqu,
403 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
409 mutex_lock(&mac->associnfo.mutex);
410 spin_lock_irqsave(&mac->lock, flags);
411 /* bleh. shouldn't be locked for that kmalloc... */
413 if (wrqu->data.length) {
414 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
415 /* this is an IE, so the length must be
416 * correct. Is it possible though that
417 * more than one IE is passed in?
422 if (mac->wpa.IEbuflen <= wrqu->data.length) {
423 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
430 mac->wpa.IEbuflen = wrqu->data.length;
432 memcpy(mac->wpa.IE, extra, wrqu->data.length);
433 dprintk(KERN_INFO PFX "generic IE set to ");
434 for (i=0;i<wrqu->data.length;i++)
435 dprintk("%.2x", (u8)mac->wpa.IE[i]);
437 mac->wpa.IElen = wrqu->data.length;
442 mac->wpa.IEbuflen = 0;
446 spin_unlock_irqrestore(&mac->lock, flags);
447 mutex_unlock(&mac->associnfo.mutex);
451 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
454 ieee80211softmac_wx_get_genie(struct net_device *dev,
455 struct iw_request_info *info,
456 union iwreq_data *wrqu,
459 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
462 int space = wrqu->data.length;
464 mutex_lock(&mac->associnfo.mutex);
465 spin_lock_irqsave(&mac->lock, flags);
467 wrqu->data.length = 0;
469 if (mac->wpa.IE && mac->wpa.IElen) {
470 wrqu->data.length = mac->wpa.IElen;
471 if (mac->wpa.IElen <= space)
472 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
476 spin_unlock_irqrestore(&mac->lock, flags);
477 mutex_unlock(&mac->associnfo.mutex);
481 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
484 ieee80211softmac_wx_set_mlme(struct net_device *dev,
485 struct iw_request_info *info,
486 union iwreq_data *wrqu,
489 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
490 struct iw_mlme *mlme = (struct iw_mlme *)extra;
491 u16 reason = cpu_to_le16(mlme->reason_code);
492 struct ieee80211softmac_network *net;
495 mutex_lock(&mac->associnfo.mutex);
497 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
498 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
504 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
506 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
509 err = ieee80211softmac_deauth_req(mac, net, reason);
511 case IW_MLME_DISASSOC:
512 ieee80211softmac_send_disassoc_req(mac, reason);
513 mac->associnfo.associated = 0;
514 mac->associnfo.associating = 0;
522 mutex_unlock(&mac->associnfo.mutex);
526 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);