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);