Merge branch 'for_paulus' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc
[pandora-kernel.git] / net / ieee80211 / softmac / ieee80211softmac_wx.c
1 /*
2  * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
3  *
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>
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.
25  */
26
27 #include "ieee80211softmac_priv.h"
28
29 #include <net/iw_handler.h>
30
31
32 int
33 ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
34                                  struct iw_request_info *info,
35                                  union iwreq_data *data,
36                                  char *extra)
37 {
38         struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
39         return ieee80211softmac_start_scan(sm);
40 }
41 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
42
43
44 /* if we're still scanning, return -EAGAIN so that userspace tools
45  * can get the complete scan results, otherwise return 0. */
46 int
47 ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
48                                      struct iw_request_info *info,
49                                      union iwreq_data *data,
50                                      char *extra)
51 {
52         unsigned long flags;
53         struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
54
55         spin_lock_irqsave(&sm->lock, flags);
56         if (sm->scanning) {
57                 spin_unlock_irqrestore(&sm->lock, flags);
58                 return -EAGAIN;
59         }
60         spin_unlock_irqrestore(&sm->lock, flags);
61         return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
62 }
63 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
64
65 int
66 ieee80211softmac_wx_set_essid(struct net_device *net_dev,
67                               struct iw_request_info *info,
68                               union iwreq_data *data,
69                               char *extra)
70 {
71         struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
72         int length = 0;
73         unsigned long flags;
74         
75         spin_lock_irqsave(&sm->lock, flags);
76         
77         sm->associnfo.static_essid = 0;
78
79         if (data->essid.flags && data->essid.length && extra /*required?*/) {
80                 length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
81                 if (length) {
82                         memcpy(sm->associnfo.req_essid.data, extra, length);
83                         sm->associnfo.static_essid = 1;
84                 }
85         }
86         sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
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) */
93         schedule_work(&sm->associnfo.work);
94
95         spin_unlock_irqrestore(&sm->lock, flags);
96         return 0;
97 }
98 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
99
100 int
101 ieee80211softmac_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 }
131 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
132
133 int
134 ieee80211softmac_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) {
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)
154                         in_rate = 11000000;
155                 else
156                         in_rate = 54000000;
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
214         mac->txrates.default_rate = rate;
215         mac->txrates.default_fallback = lower_rate(mac, rate);
216         err = 0;
217
218 out_unlock:     
219         spin_unlock_irqrestore(&mac->lock, flags);
220 out:
221         return err;
222 }
223 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
224
225 int
226 ieee80211softmac_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;
278 out_unlock:
279         spin_unlock_irqrestore(&mac->lock, flags);
280
281         return err;
282 }
283 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
284
285 int
286 ieee80211softmac_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 }
304 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
305
306 int
307 ieee80211softmac_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);
313         static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
314         static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
315         unsigned long flags;
316
317         /* sanity check */
318         if (data->ap_addr.sa_family != ARPHRD_ETHER) {
319                 return -EINVAL;
320         }
321
322         spin_lock_irqsave(&mac->lock, flags);
323         if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
324             !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
325                 schedule_work(&mac->associnfo.work);
326                 goto out;
327         } else {
328                 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
329                         if (mac->associnfo.associating || mac->associated) {
330                         /* bssid unchanged and associated or associating - just return */
331                                 goto out;
332                         }
333                 } else {
334                         /* copy new value in data->ap_addr.sa_data to bssid */
335                         memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
336                 }       
337                 /* queue associate if new bssid or (old one again and not associated) */
338                 schedule_work(&mac->associnfo.work);
339         }
340
341 out:
342         spin_unlock_irqrestore(&mac->lock, flags);
343         return 0;
344 }
345 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
346
347 int
348 ieee80211softmac_wx_set_genie(struct net_device *dev,
349                               struct iw_request_info *info,
350                               union iwreq_data *wrqu,
351                               char *extra)
352 {
353         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
354         unsigned long flags;
355         int err = 0;
356         char *buf;
357         int i;
358         
359         spin_lock_irqsave(&mac->lock, flags);
360         /* bleh. shouldn't be locked for that kmalloc... */
361
362         if (wrqu->data.length) {
363                 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
364                         /* this is an IE, so the length must be
365                          * correct. Is it possible though that
366                          * more than one IE is passed in?
367                          */
368                         err = -EINVAL;
369                         goto out;
370                 }
371                 if (mac->wpa.IEbuflen <= wrqu->data.length) {
372                         buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
373                         if (!buf) {
374                                 err = -ENOMEM;
375                                 goto out;
376                         }
377                         kfree(mac->wpa.IE);
378                         mac->wpa.IE = buf;
379                         mac->wpa.IEbuflen = wrqu->data.length;
380                 }
381                 memcpy(mac->wpa.IE, extra, wrqu->data.length);
382                 dprintk(KERN_INFO PFX "generic IE set to ");
383                 for (i=0;i<wrqu->data.length;i++)
384                         dprintk("%.2x", mac->wpa.IE[i]);
385                 dprintk("\n");
386                 mac->wpa.IElen = wrqu->data.length;
387         } else {
388                 kfree(mac->wpa.IE);
389                 mac->wpa.IE = NULL;
390                 mac->wpa.IElen = 0;
391                 mac->wpa.IEbuflen = 0;
392         }
393
394  out:   
395         spin_unlock_irqrestore(&mac->lock, flags);
396         return err;
397 }
398 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
399
400 int
401 ieee80211softmac_wx_get_genie(struct net_device *dev,
402                               struct iw_request_info *info,
403                               union iwreq_data *wrqu,
404                               char *extra)
405 {
406         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
407         unsigned long flags;
408         int err = 0;
409         int space = wrqu->data.length;
410         
411         spin_lock_irqsave(&mac->lock, flags);
412         
413         wrqu->data.length = 0;
414         
415         if (mac->wpa.IE && mac->wpa.IElen) {
416                 wrqu->data.length = mac->wpa.IElen;
417                 if (mac->wpa.IElen <= space)
418                         memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
419                 else
420                         err = -E2BIG;
421         }
422         spin_unlock_irqrestore(&mac->lock, flags);
423         return err;
424 }
425 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
426