blob: 2ffaebd21c53d8931819853735bd07ddc47b16a8 [file] [log] [blame]
Johannes Berg370121e2006-01-04 16:32:16 +01001/*
2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
Johannes Berg4855d252006-01-12 21:12:59 +01003 *
Johannes Berg79859052006-01-31 19:31:41 +01004 * 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>
Johannes Berg4855d252006-01-12 21:12:59 +01009 *
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.
Johannes Berg370121e2006-01-04 16:32:16 +010025 */
26
27#include "ieee80211softmac_priv.h"
28
29#include <net/iw_handler.h>
Johannes Berg818667f2006-04-20 20:02:03 +020030/* for is_broadcast_ether_addr and is_zero_ether_addr */
31#include <linux/etherdevice.h>
Johannes Berg370121e2006-01-04 16:32:16 +010032
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
johannes@sipsolutions.netba2f8c12006-04-11 10:58:06 +020045/* if we're still scanning, return -EAGAIN so that userspace tools
46 * can get the complete scan results, otherwise return 0. */
Johannes Berg370121e2006-01-04 16:32:16 +010047int
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{
johannes@sipsolutions.netba2f8c12006-04-11 10:58:06 +020053 unsigned long flags;
Johannes Berg370121e2006-01-04 16:32:16 +010054 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
johannes@sipsolutions.netba2f8c12006-04-11 10:58:06 +020055
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);
Johannes Berg370121e2006-01-04 16:32:16 +010062 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);
Joseph Jezakcb74c432006-06-11 12:00:37 -040073 struct ieee80211softmac_network *n;
74 struct ieee80211softmac_auth_queue_item *authptr;
Johannes Berg370121e2006-01-04 16:32:16 +010075 int length = 0;
Michael Buesch7c28ad22006-09-27 15:26:33 +030076
77 mutex_lock(&sm->associnfo.mutex);
Joseph Jezakcb74c432006-06-11 12:00:37 -040078
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!
82 */
Michael Buesch7c28ad22006-09-27 15:26:33 +030083 if((sm->associnfo.associating || sm->associnfo.associated) &&
Larry Fingerb978d022006-08-31 10:01:39 -050084 (data->essid.flags && data->essid.length)) {
Joseph Jezakcb74c432006-06-11 12:00:37 -040085 /* Get the associating network */
86 n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
Larry Fingerb978d022006-08-31 10:01:39 -050087 if(n && n->essid.len == data->essid.length &&
Joseph Jezakcb74c432006-06-11 12:00:37 -040088 !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));
Michael Buesch7c28ad22006-09-27 15:26:33 +030091 goto out;
Joseph Jezakcb74c432006-06-11 12:00:37 -040092 } else {
93 dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
Joseph Jezakcb74c432006-06-11 12:00:37 -040094 /* 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;
Joseph Jezakcb74c432006-06-11 12:00:37 -0400101 flush_scheduled_work();
Michael Buesch7c28ad22006-09-27 15:26:33 +0300102 sm->associnfo.associating = 0;
103 sm->associnfo.associated = 0;
Joseph Jezakcb74c432006-06-11 12:00:37 -0400104 }
105 }
106
107
Johannes Berg370121e2006-01-04 16:32:16 +0100108 sm->associnfo.static_essid = 0;
Joseph Jezakcb74c432006-06-11 12:00:37 -0400109 sm->associnfo.assoc_wait = 0;
Johannes Berg370121e2006-01-04 16:32:16 +0100110
Larry Fingerb978d022006-08-31 10:01:39 -0500111 if (data->essid.flags && data->essid.length) {
112 length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
Johannes Berg370121e2006-01-04 16:32:16 +0100113 if (length) {
114 memcpy(sm->associnfo.req_essid.data, extra, length);
115 sm->associnfo.static_essid = 1;
116 }
117 }
Johannes Berg370121e2006-01-04 16:32:16 +0100118
119 /* set our requested ESSID length.
120 * If applicable, we have already copied the data in */
121 sm->associnfo.req_essid.len = length;
122
Michael Buesch7c28ad22006-09-27 15:26:33 +0300123 sm->associnfo.associating = 1;
Johannes Berg370121e2006-01-04 16:32:16 +0100124 /* queue lower level code to do work (if necessary) */
David Howellsc4028952006-11-22 14:57:56 +0000125 schedule_delayed_work(&sm->associnfo.work, 0);
Michael Buesch7c28ad22006-09-27 15:26:33 +0300126out:
127 mutex_unlock(&sm->associnfo.mutex);
Johannes Berg370121e2006-01-04 16:32:16 +0100128
Johannes Berg370121e2006-01-04 16:32:16 +0100129 return 0;
130}
131EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
132
133int
134ieee80211softmac_wx_get_essid(struct net_device *net_dev,
135 struct iw_request_info *info,
136 union iwreq_data *data,
137 char *extra)
138{
139 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
Johannes Berg370121e2006-01-04 16:32:16 +0100140
Michael Buesch7c28ad22006-09-27 15:26:33 +0300141 mutex_lock(&sm->associnfo.mutex);
Johannes Berg370121e2006-01-04 16:32:16 +0100142 /* If all fails, return ANY (empty) */
143 data->essid.length = 0;
144 data->essid.flags = 0; /* active */
145
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);
151 }
152
153 /* If we're associating/associated, return that */
Michael Buesch7c28ad22006-09-27 15:26:33 +0300154 if (sm->associnfo.associated || sm->associnfo.associating) {
Johannes Berg370121e2006-01-04 16:32:16 +0100155 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);
158 }
Michael Buesch7c28ad22006-09-27 15:26:33 +0300159 mutex_unlock(&sm->associnfo.mutex);
160
Johannes Berg370121e2006-01-04 16:32:16 +0100161 return 0;
162}
163EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
164
165int
166ieee80211softmac_wx_set_rate(struct net_device *net_dev,
167 struct iw_request_info *info,
168 union iwreq_data *data,
169 char *extra)
170{
171 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
172 struct ieee80211_device *ieee = mac->ieee;
173 unsigned long flags;
174 s32 in_rate = data->bitrate.value;
175 u8 rate;
176 int is_ofdm = 0;
177 int err = -EINVAL;
178
179 if (in_rate == -1) {
David Woodhouse2638fed2006-03-23 22:43:38 +0000180 /* 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)
Johannes Berg370121e2006-01-04 16:32:16 +0100186 in_rate = 11000000;
David Woodhouse2638fed2006-03-23 22:43:38 +0000187 else
188 in_rate = 54000000;
Johannes Berg370121e2006-01-04 16:32:16 +0100189 }
190
191 switch (in_rate) {
192 case 1000000:
193 rate = IEEE80211_CCK_RATE_1MB;
194 break;
195 case 2000000:
196 rate = IEEE80211_CCK_RATE_2MB;
197 break;
198 case 5500000:
199 rate = IEEE80211_CCK_RATE_5MB;
200 break;
201 case 11000000:
202 rate = IEEE80211_CCK_RATE_11MB;
203 break;
204 case 6000000:
205 rate = IEEE80211_OFDM_RATE_6MB;
206 is_ofdm = 1;
207 break;
208 case 9000000:
209 rate = IEEE80211_OFDM_RATE_9MB;
210 is_ofdm = 1;
211 break;
212 case 12000000:
213 rate = IEEE80211_OFDM_RATE_12MB;
214 is_ofdm = 1;
215 break;
216 case 18000000:
217 rate = IEEE80211_OFDM_RATE_18MB;
218 is_ofdm = 1;
219 break;
220 case 24000000:
221 rate = IEEE80211_OFDM_RATE_24MB;
222 is_ofdm = 1;
223 break;
224 case 36000000:
225 rate = IEEE80211_OFDM_RATE_36MB;
226 is_ofdm = 1;
227 break;
228 case 48000000:
229 rate = IEEE80211_OFDM_RATE_48MB;
230 is_ofdm = 1;
231 break;
232 case 54000000:
233 rate = IEEE80211_OFDM_RATE_54MB;
234 is_ofdm = 1;
235 break;
236 default:
237 goto out;
238 }
239
240 spin_lock_irqsave(&mac->lock, flags);
241
242 /* Check if correct modulation for this PHY. */
243 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
244 goto out_unlock;
245
Daniel Drake8462fe32006-05-01 22:45:50 +0100246 mac->txrates.user_rate = rate;
247 ieee80211softmac_recalc_txrates(mac);
Johannes Berg370121e2006-01-04 16:32:16 +0100248 err = 0;
249
250out_unlock:
251 spin_unlock_irqrestore(&mac->lock, flags);
252out:
253 return err;
254}
255EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
256
257int
258ieee80211softmac_wx_get_rate(struct net_device *net_dev,
259 struct iw_request_info *info,
260 union iwreq_data *data,
261 char *extra)
262{
263 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
264 unsigned long flags;
265 int err = -EINVAL;
266
267 spin_lock_irqsave(&mac->lock, flags);
268 switch (mac->txrates.default_rate) {
269 case IEEE80211_CCK_RATE_1MB:
270 data->bitrate.value = 1000000;
271 break;
272 case IEEE80211_CCK_RATE_2MB:
273 data->bitrate.value = 2000000;
274 break;
275 case IEEE80211_CCK_RATE_5MB:
276 data->bitrate.value = 5500000;
277 break;
278 case IEEE80211_CCK_RATE_11MB:
279 data->bitrate.value = 11000000;
280 break;
281 case IEEE80211_OFDM_RATE_6MB:
282 data->bitrate.value = 6000000;
283 break;
284 case IEEE80211_OFDM_RATE_9MB:
285 data->bitrate.value = 9000000;
286 break;
287 case IEEE80211_OFDM_RATE_12MB:
288 data->bitrate.value = 12000000;
289 break;
290 case IEEE80211_OFDM_RATE_18MB:
291 data->bitrate.value = 18000000;
292 break;
293 case IEEE80211_OFDM_RATE_24MB:
294 data->bitrate.value = 24000000;
295 break;
296 case IEEE80211_OFDM_RATE_36MB:
297 data->bitrate.value = 36000000;
298 break;
299 case IEEE80211_OFDM_RATE_48MB:
300 data->bitrate.value = 48000000;
301 break;
302 case IEEE80211_OFDM_RATE_54MB:
303 data->bitrate.value = 54000000;
304 break;
305 default:
306 assert(0);
307 goto out_unlock;
308 }
309 err = 0;
310out_unlock:
311 spin_unlock_irqrestore(&mac->lock, flags);
312
313 return err;
314}
315EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
316
317int
318ieee80211softmac_wx_get_wap(struct net_device *net_dev,
319 struct iw_request_info *info,
320 union iwreq_data *data,
321 char *extra)
322{
323 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
324 int err = 0;
Johannes Berg370121e2006-01-04 16:32:16 +0100325
Michael Buesch7c28ad22006-09-27 15:26:33 +0300326 mutex_lock(&mac->associnfo.mutex);
Johannes Berg370121e2006-01-04 16:32:16 +0100327 if (mac->associnfo.bssvalid)
328 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
329 else
330 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
331 data->ap_addr.sa_family = ARPHRD_ETHER;
Michael Buesch7c28ad22006-09-27 15:26:33 +0300332 mutex_unlock(&mac->associnfo.mutex);
333
Johannes Berg370121e2006-01-04 16:32:16 +0100334 return err;
335}
336EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
337
338int
339ieee80211softmac_wx_set_wap(struct net_device *net_dev,
340 struct iw_request_info *info,
341 union iwreq_data *data,
342 char *extra)
343{
344 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
Johannes Berg370121e2006-01-04 16:32:16 +0100345
346 /* sanity check */
347 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
348 return -EINVAL;
349 }
350
Michael Buesch7c28ad22006-09-27 15:26:33 +0300351 mutex_lock(&mac->associnfo.mutex);
Johannes Berg818667f2006-04-20 20:02:03 +0200352 if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
353 /* the bssid we have is not to be fixed any longer,
354 * and we should reassociate to the best AP. */
355 mac->associnfo.bssfixed = 0;
356 /* force reassociation */
357 mac->associnfo.bssvalid = 0;
Michael Buesch7c28ad22006-09-27 15:26:33 +0300358 if (mac->associnfo.associated)
David Howellsc4028952006-11-22 14:57:56 +0000359 schedule_delayed_work(&mac->associnfo.work, 0);
Johannes Berg818667f2006-04-20 20:02:03 +0200360 } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
361 /* the bssid we have is no longer fixed */
362 mac->associnfo.bssfixed = 0;
Johannes Berg370121e2006-01-04 16:32:16 +0100363 } else {
364 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
Michael Buesch7c28ad22006-09-27 15:26:33 +0300365 if (mac->associnfo.associating || mac->associnfo.associated) {
Johannes Berg370121e2006-01-04 16:32:16 +0100366 /* bssid unchanged and associated or associating - just return */
367 goto out;
368 }
369 } else {
370 /* copy new value in data->ap_addr.sa_data to bssid */
371 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
Johannes Berg818667f2006-04-20 20:02:03 +0200372 }
373 /* tell the other code that this bssid should be used no matter what */
374 mac->associnfo.bssfixed = 1;
Johannes Berg370121e2006-01-04 16:32:16 +0100375 /* queue associate if new bssid or (old one again and not associated) */
David Howellsc4028952006-11-22 14:57:56 +0000376 schedule_delayed_work(&mac->associnfo.work, 0);
Johannes Berg370121e2006-01-04 16:32:16 +0100377 }
378
Johannes Berg818667f2006-04-20 20:02:03 +0200379 out:
Michael Buesch7c28ad22006-09-27 15:26:33 +0300380 mutex_unlock(&mac->associnfo.mutex);
381
Johannes Berg370121e2006-01-04 16:32:16 +0100382 return 0;
383}
384EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
385
386int
387ieee80211softmac_wx_set_genie(struct net_device *dev,
388 struct iw_request_info *info,
389 union iwreq_data *wrqu,
390 char *extra)
391{
392 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
393 unsigned long flags;
394 int err = 0;
395 char *buf;
396 int i;
Michael Buesch7c28ad22006-09-27 15:26:33 +0300397
398 mutex_lock(&mac->associnfo.mutex);
Johannes Berg370121e2006-01-04 16:32:16 +0100399 spin_lock_irqsave(&mac->lock, flags);
400 /* bleh. shouldn't be locked for that kmalloc... */
401
402 if (wrqu->data.length) {
403 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
404 /* this is an IE, so the length must be
405 * correct. Is it possible though that
406 * more than one IE is passed in?
407 */
408 err = -EINVAL;
409 goto out;
410 }
411 if (mac->wpa.IEbuflen <= wrqu->data.length) {
412 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
413 if (!buf) {
414 err = -ENOMEM;
415 goto out;
416 }
417 kfree(mac->wpa.IE);
418 mac->wpa.IE = buf;
419 mac->wpa.IEbuflen = wrqu->data.length;
420 }
421 memcpy(mac->wpa.IE, extra, wrqu->data.length);
422 dprintk(KERN_INFO PFX "generic IE set to ");
423 for (i=0;i<wrqu->data.length;i++)
Larry Finger7bd6b912006-06-08 09:47:42 -0500424 dprintk("%.2x", (u8)mac->wpa.IE[i]);
Johannes Berg370121e2006-01-04 16:32:16 +0100425 dprintk("\n");
426 mac->wpa.IElen = wrqu->data.length;
427 } else {
428 kfree(mac->wpa.IE);
429 mac->wpa.IE = NULL;
430 mac->wpa.IElen = 0;
431 mac->wpa.IEbuflen = 0;
432 }
433
434 out:
435 spin_unlock_irqrestore(&mac->lock, flags);
Michael Buesch7c28ad22006-09-27 15:26:33 +0300436 mutex_unlock(&mac->associnfo.mutex);
437
Johannes Berg370121e2006-01-04 16:32:16 +0100438 return err;
439}
440EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
441
442int
443ieee80211softmac_wx_get_genie(struct net_device *dev,
444 struct iw_request_info *info,
445 union iwreq_data *wrqu,
446 char *extra)
447{
448 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
449 unsigned long flags;
450 int err = 0;
451 int space = wrqu->data.length;
Michael Buesch7c28ad22006-09-27 15:26:33 +0300452
453 mutex_lock(&mac->associnfo.mutex);
Johannes Berg370121e2006-01-04 16:32:16 +0100454 spin_lock_irqsave(&mac->lock, flags);
455
456 wrqu->data.length = 0;
457
458 if (mac->wpa.IE && mac->wpa.IElen) {
459 wrqu->data.length = mac->wpa.IElen;
460 if (mac->wpa.IElen <= space)
461 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
462 else
463 err = -E2BIG;
464 }
465 spin_unlock_irqrestore(&mac->lock, flags);
Michael Buesch7c28ad22006-09-27 15:26:33 +0300466 mutex_lock(&mac->associnfo.mutex);
467
Johannes Berg370121e2006-01-04 16:32:16 +0100468 return err;
469}
470EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
471
Johannes Berg9a1771e82006-04-20 20:02:02 +0200472int
473ieee80211softmac_wx_set_mlme(struct net_device *dev,
474 struct iw_request_info *info,
475 union iwreq_data *wrqu,
476 char *extra)
477{
478 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
479 struct iw_mlme *mlme = (struct iw_mlme *)extra;
480 u16 reason = cpu_to_le16(mlme->reason_code);
481 struct ieee80211softmac_network *net;
Michael Buesch7c28ad22006-09-27 15:26:33 +0300482 int err = -EINVAL;
483
484 mutex_lock(&mac->associnfo.mutex);
Johannes Berg9a1771e82006-04-20 20:02:02 +0200485
486 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
487 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
Michael Buesch7c28ad22006-09-27 15:26:33 +0300488 goto out;
Johannes Berg9a1771e82006-04-20 20:02:02 +0200489 }
490
491 switch (mlme->cmd) {
492 case IW_MLME_DEAUTH:
493 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
494 if (!net) {
495 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
Michael Buesch7c28ad22006-09-27 15:26:33 +0300496 goto out;
Johannes Berg9a1771e82006-04-20 20:02:02 +0200497 }
498 return ieee80211softmac_deauth_req(mac, net, reason);
499 case IW_MLME_DISASSOC:
Daniel Drake6d92f832006-05-01 22:23:27 +0100500 ieee80211softmac_send_disassoc_req(mac, reason);
Michael Buesch7c28ad22006-09-27 15:26:33 +0300501 mac->associnfo.associated = 0;
502 mac->associnfo.associating = 0;
503 err = 0;
504 goto out;
Johannes Berg9a1771e82006-04-20 20:02:02 +0200505 default:
Michael Buesch7c28ad22006-09-27 15:26:33 +0300506 err = -EOPNOTSUPP;
Johannes Berg9a1771e82006-04-20 20:02:02 +0200507 }
Michael Buesch7c28ad22006-09-27 15:26:33 +0300508
509out:
510 mutex_unlock(&mac->associnfo.mutex);
511
512 return err;
Johannes Berg9a1771e82006-04-20 20:02:02 +0200513}
514EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);