[PATCH] pci: bcm43xx avoid pci_find_device
[deliverable/linux.git] / net / ieee80211 / softmac / ieee80211softmac_wx.c
CommitLineData
370121e5
JB
1/*
2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
4855d25b 3 *
79859051
JB
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>
4855d25b
JB
9 *
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.
13 *
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
17 * more details.
18 *
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
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
370121e5
JB
25 */
26
27#include "ieee80211softmac_priv.h"
28
29#include <net/iw_handler.h>
818667f7
JB
30/* for is_broadcast_ether_addr and is_zero_ether_addr */
31#include <linux/etherdevice.h>
370121e5
JB
32
33int
34ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
35 struct iw_request_info *info,
36 union iwreq_data *data,
37 char *extra)
38{
39 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
40 return ieee80211softmac_start_scan(sm);
41}
42EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
43
44
ba2f8c18 45/* if we're still scanning, return -EAGAIN so that userspace tools
46 * can get the complete scan results, otherwise return 0. */
370121e5
JB
47int
48ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
49 struct iw_request_info *info,
50 union iwreq_data *data,
51 char *extra)
52{
ba2f8c18 53 unsigned long flags;
370121e5 54 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
ba2f8c18 55
56 spin_lock_irqsave(&sm->lock, flags);
57 if (sm->scanning) {
58 spin_unlock_irqrestore(&sm->lock, flags);
59 return -EAGAIN;
60 }
61 spin_unlock_irqrestore(&sm->lock, flags);
370121e5
JB
62 return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
63}
64EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
65
66int
67ieee80211softmac_wx_set_essid(struct net_device *net_dev,
68 struct iw_request_info *info,
69 union iwreq_data *data,
70 char *extra)
71{
72 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
73 int length = 0;
74 unsigned long flags;
75
76 spin_lock_irqsave(&sm->lock, flags);
77
78 sm->associnfo.static_essid = 0;
79
80 if (data->essid.flags && data->essid.length && extra /*required?*/) {
81 length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
82 if (length) {
83 memcpy(sm->associnfo.req_essid.data, extra, length);
84 sm->associnfo.static_essid = 1;
85 }
86 }
370121e5
JB
87
88 /* set our requested ESSID length.
89 * If applicable, we have already copied the data in */
90 sm->associnfo.req_essid.len = length;
91
92 /* queue lower level code to do work (if necessary) */
5c4df6da 93 schedule_work(&sm->associnfo.work);
370121e5
JB
94
95 spin_unlock_irqrestore(&sm->lock, flags);
96 return 0;
97}
98EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
99
100int
101ieee80211softmac_wx_get_essid(struct net_device *net_dev,
102 struct iw_request_info *info,
103 union iwreq_data *data,
104 char *extra)
105{
106 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
107 unsigned long flags;
108
109 /* avoid getting inconsistent information */
110 spin_lock_irqsave(&sm->lock, flags);
111 /* If all fails, return ANY (empty) */
112 data->essid.length = 0;
113 data->essid.flags = 0; /* active */
114
115 /* If we have a statically configured ESSID then return it */
116 if (sm->associnfo.static_essid) {
117 data->essid.length = sm->associnfo.req_essid.len;
118 data->essid.flags = 1; /* active */
119 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
120 }
121
122 /* If we're associating/associated, return that */
123 if (sm->associated || sm->associnfo.associating) {
124 data->essid.length = sm->associnfo.associate_essid.len;
125 data->essid.flags = 1; /* active */
126 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
127 }
128 spin_unlock_irqrestore(&sm->lock, flags);
129 return 0;
130}
131EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
132
133int
134ieee80211softmac_wx_set_rate(struct net_device *net_dev,
135 struct iw_request_info *info,
136 union iwreq_data *data,
137 char *extra)
138{
139 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
140 struct ieee80211_device *ieee = mac->ieee;
141 unsigned long flags;
142 s32 in_rate = data->bitrate.value;
143 u8 rate;
144 int is_ofdm = 0;
145 int err = -EINVAL;
146
147 if (in_rate == -1) {
2638fed7
DW
148 /* FIXME: We don't correctly handle backing down to lower
149 rates, so 801.11g devices start off at 11M for now. People
150 can manually change it if they really need to, but 11M is
151 more reliable. Note similar logic in
152 ieee80211softmac_wx_set_rate() */
153 if (ieee->modulation & IEEE80211_CCK_MODULATION)
370121e5 154 in_rate = 11000000;
2638fed7
DW
155 else
156 in_rate = 54000000;
370121e5
JB
157 }
158
159 switch (in_rate) {
160 case 1000000:
161 rate = IEEE80211_CCK_RATE_1MB;
162 break;
163 case 2000000:
164 rate = IEEE80211_CCK_RATE_2MB;
165 break;
166 case 5500000:
167 rate = IEEE80211_CCK_RATE_5MB;
168 break;
169 case 11000000:
170 rate = IEEE80211_CCK_RATE_11MB;
171 break;
172 case 6000000:
173 rate = IEEE80211_OFDM_RATE_6MB;
174 is_ofdm = 1;
175 break;
176 case 9000000:
177 rate = IEEE80211_OFDM_RATE_9MB;
178 is_ofdm = 1;
179 break;
180 case 12000000:
181 rate = IEEE80211_OFDM_RATE_12MB;
182 is_ofdm = 1;
183 break;
184 case 18000000:
185 rate = IEEE80211_OFDM_RATE_18MB;
186 is_ofdm = 1;
187 break;
188 case 24000000:
189 rate = IEEE80211_OFDM_RATE_24MB;
190 is_ofdm = 1;
191 break;
192 case 36000000:
193 rate = IEEE80211_OFDM_RATE_36MB;
194 is_ofdm = 1;
195 break;
196 case 48000000:
197 rate = IEEE80211_OFDM_RATE_48MB;
198 is_ofdm = 1;
199 break;
200 case 54000000:
201 rate = IEEE80211_OFDM_RATE_54MB;
202 is_ofdm = 1;
203 break;
204 default:
205 goto out;
206 }
207
208 spin_lock_irqsave(&mac->lock, flags);
209
210 /* Check if correct modulation for this PHY. */
211 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
212 goto out_unlock;
213
8462fe3c
DD
214 mac->txrates.user_rate = rate;
215 ieee80211softmac_recalc_txrates(mac);
370121e5
JB
216 err = 0;
217
218out_unlock:
219 spin_unlock_irqrestore(&mac->lock, flags);
220out:
221 return err;
222}
223EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
224
225int
226ieee80211softmac_wx_get_rate(struct net_device *net_dev,
227 struct iw_request_info *info,
228 union iwreq_data *data,
229 char *extra)
230{
231 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
232 unsigned long flags;
233 int err = -EINVAL;
234
235 spin_lock_irqsave(&mac->lock, flags);
236 switch (mac->txrates.default_rate) {
237 case IEEE80211_CCK_RATE_1MB:
238 data->bitrate.value = 1000000;
239 break;
240 case IEEE80211_CCK_RATE_2MB:
241 data->bitrate.value = 2000000;
242 break;
243 case IEEE80211_CCK_RATE_5MB:
244 data->bitrate.value = 5500000;
245 break;
246 case IEEE80211_CCK_RATE_11MB:
247 data->bitrate.value = 11000000;
248 break;
249 case IEEE80211_OFDM_RATE_6MB:
250 data->bitrate.value = 6000000;
251 break;
252 case IEEE80211_OFDM_RATE_9MB:
253 data->bitrate.value = 9000000;
254 break;
255 case IEEE80211_OFDM_RATE_12MB:
256 data->bitrate.value = 12000000;
257 break;
258 case IEEE80211_OFDM_RATE_18MB:
259 data->bitrate.value = 18000000;
260 break;
261 case IEEE80211_OFDM_RATE_24MB:
262 data->bitrate.value = 24000000;
263 break;
264 case IEEE80211_OFDM_RATE_36MB:
265 data->bitrate.value = 36000000;
266 break;
267 case IEEE80211_OFDM_RATE_48MB:
268 data->bitrate.value = 48000000;
269 break;
270 case IEEE80211_OFDM_RATE_54MB:
271 data->bitrate.value = 54000000;
272 break;
273 default:
274 assert(0);
275 goto out_unlock;
276 }
277 err = 0;
278out_unlock:
279 spin_unlock_irqrestore(&mac->lock, flags);
280
281 return err;
282}
283EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
284
285int
286ieee80211softmac_wx_get_wap(struct net_device *net_dev,
287 struct iw_request_info *info,
288 union iwreq_data *data,
289 char *extra)
290{
291 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
292 int err = 0;
293 unsigned long flags;
294
295 spin_lock_irqsave(&mac->lock, flags);
296 if (mac->associnfo.bssvalid)
297 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
298 else
299 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
300 data->ap_addr.sa_family = ARPHRD_ETHER;
301 spin_unlock_irqrestore(&mac->lock, flags);
302 return err;
303}
304EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
305
306int
307ieee80211softmac_wx_set_wap(struct net_device *net_dev,
308 struct iw_request_info *info,
309 union iwreq_data *data,
310 char *extra)
311{
312 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
370121e5
JB
313 unsigned long flags;
314
315 /* sanity check */
316 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
317 return -EINVAL;
318 }
319
320 spin_lock_irqsave(&mac->lock, flags);
818667f7
JB
321 if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
322 /* the bssid we have is not to be fixed any longer,
323 * and we should reassociate to the best AP. */
324 mac->associnfo.bssfixed = 0;
325 /* force reassociation */
326 mac->associnfo.bssvalid = 0;
327 if (mac->associated)
328 schedule_work(&mac->associnfo.work);
329 } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
330 /* the bssid we have is no longer fixed */
331 mac->associnfo.bssfixed = 0;
370121e5
JB
332 } else {
333 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
334 if (mac->associnfo.associating || mac->associated) {
335 /* bssid unchanged and associated or associating - just return */
336 goto out;
337 }
338 } else {
339 /* copy new value in data->ap_addr.sa_data to bssid */
340 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
818667f7
JB
341 }
342 /* tell the other code that this bssid should be used no matter what */
343 mac->associnfo.bssfixed = 1;
370121e5 344 /* queue associate if new bssid or (old one again and not associated) */
5c4df6da 345 schedule_work(&mac->associnfo.work);
370121e5
JB
346 }
347
818667f7 348 out:
370121e5
JB
349 spin_unlock_irqrestore(&mac->lock, flags);
350 return 0;
351}
352EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
353
354int
355ieee80211softmac_wx_set_genie(struct net_device *dev,
356 struct iw_request_info *info,
357 union iwreq_data *wrqu,
358 char *extra)
359{
360 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
361 unsigned long flags;
362 int err = 0;
363 char *buf;
364 int i;
365
366 spin_lock_irqsave(&mac->lock, flags);
367 /* bleh. shouldn't be locked for that kmalloc... */
368
369 if (wrqu->data.length) {
370 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
371 /* this is an IE, so the length must be
372 * correct. Is it possible though that
373 * more than one IE is passed in?
374 */
375 err = -EINVAL;
376 goto out;
377 }
378 if (mac->wpa.IEbuflen <= wrqu->data.length) {
379 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
380 if (!buf) {
381 err = -ENOMEM;
382 goto out;
383 }
384 kfree(mac->wpa.IE);
385 mac->wpa.IE = buf;
386 mac->wpa.IEbuflen = wrqu->data.length;
387 }
388 memcpy(mac->wpa.IE, extra, wrqu->data.length);
389 dprintk(KERN_INFO PFX "generic IE set to ");
390 for (i=0;i<wrqu->data.length;i++)
391 dprintk("%.2x", mac->wpa.IE[i]);
392 dprintk("\n");
393 mac->wpa.IElen = wrqu->data.length;
394 } else {
395 kfree(mac->wpa.IE);
396 mac->wpa.IE = NULL;
397 mac->wpa.IElen = 0;
398 mac->wpa.IEbuflen = 0;
399 }
400
401 out:
402 spin_unlock_irqrestore(&mac->lock, flags);
403 return err;
404}
405EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
406
407int
408ieee80211softmac_wx_get_genie(struct net_device *dev,
409 struct iw_request_info *info,
410 union iwreq_data *wrqu,
411 char *extra)
412{
413 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
414 unsigned long flags;
415 int err = 0;
416 int space = wrqu->data.length;
417
418 spin_lock_irqsave(&mac->lock, flags);
419
420 wrqu->data.length = 0;
421
422 if (mac->wpa.IE && mac->wpa.IElen) {
423 wrqu->data.length = mac->wpa.IElen;
424 if (mac->wpa.IElen <= space)
425 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
426 else
427 err = -E2BIG;
428 }
429 spin_unlock_irqrestore(&mac->lock, flags);
430 return err;
431}
432EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
433
9a1771e8
JB
434int
435ieee80211softmac_wx_set_mlme(struct net_device *dev,
436 struct iw_request_info *info,
437 union iwreq_data *wrqu,
438 char *extra)
439{
440 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
441 struct iw_mlme *mlme = (struct iw_mlme *)extra;
442 u16 reason = cpu_to_le16(mlme->reason_code);
443 struct ieee80211softmac_network *net;
444
445 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
446 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
447 return -EINVAL;
448 }
449
450 switch (mlme->cmd) {
451 case IW_MLME_DEAUTH:
452 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
453 if (!net) {
454 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
455 return -EINVAL;
456 }
457 return ieee80211softmac_deauth_req(mac, net, reason);
458 case IW_MLME_DISASSOC:
6d92f83f 459 ieee80211softmac_send_disassoc_req(mac, reason);
9a1771e8
JB
460 return 0;
461 default:
462 return -EOPNOTSUPP;
463 }
464}
465EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);
This page took 0.061894 seconds and 5 git commands to generate.