[PATCH] softmac: add copyright and license headers
[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 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 int
45 ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
46                                      struct iw_request_info *info,
47                                      union iwreq_data *data,
48                                      char *extra)
49 {
50         struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
51         return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
52 }
53 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
54
55 int
56 ieee80211softmac_wx_set_essid(struct net_device *net_dev,
57                               struct iw_request_info *info,
58                               union iwreq_data *data,
59                               char *extra)
60 {
61         struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
62         int length = 0;
63         unsigned long flags;
64         
65         spin_lock_irqsave(&sm->lock, flags);
66         
67         sm->associnfo.static_essid = 0;
68
69         if (data->essid.flags && data->essid.length && extra /*required?*/) {
70                 length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
71                 if (length) {
72                         memcpy(sm->associnfo.req_essid.data, extra, length);
73                         sm->associnfo.static_essid = 1;
74                 }
75         }
76         sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
77
78         /* set our requested ESSID length.
79          * If applicable, we have already copied the data in */
80         sm->associnfo.req_essid.len = length;
81
82         /* queue lower level code to do work (if necessary) */
83         schedule_work(&sm->associnfo.work);
84
85         spin_unlock_irqrestore(&sm->lock, flags);
86         return 0;
87 }
88 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
89
90 int
91 ieee80211softmac_wx_get_essid(struct net_device *net_dev,
92                               struct iw_request_info *info,
93                               union iwreq_data *data,
94                               char *extra)
95 {
96         struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
97         unsigned long flags;
98
99         /* avoid getting inconsistent information */
100         spin_lock_irqsave(&sm->lock, flags);
101         /* If all fails, return ANY (empty) */
102         data->essid.length = 0;
103         data->essid.flags = 0;  /* active */
104         
105         /* If we have a statically configured ESSID then return it */
106         if (sm->associnfo.static_essid) {
107                 data->essid.length = sm->associnfo.req_essid.len;
108                 data->essid.flags = 1;  /* active */
109                 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
110         }
111         
112         /* If we're associating/associated, return that */
113         if (sm->associated || sm->associnfo.associating) {
114                 data->essid.length = sm->associnfo.associate_essid.len;
115                 data->essid.flags = 1;  /* active */
116                 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
117         }
118         spin_unlock_irqrestore(&sm->lock, flags);
119         return 0;
120 }
121 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
122
123 int
124 ieee80211softmac_wx_set_rate(struct net_device *net_dev,
125                              struct iw_request_info *info,
126                              union iwreq_data *data,
127                              char *extra)
128 {
129         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
130         struct ieee80211_device *ieee = mac->ieee;
131         unsigned long flags;
132         s32 in_rate = data->bitrate.value;
133         u8 rate;
134         int is_ofdm = 0;
135         int err = -EINVAL;
136
137         if (in_rate == -1) {
138                 /* automatic detect */
139                 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
140                         in_rate = 54000000;
141                 else
142                         in_rate = 11000000;
143         }
144
145         switch (in_rate) {
146         case 1000000:
147                 rate = IEEE80211_CCK_RATE_1MB;
148                 break;
149         case 2000000:
150                 rate = IEEE80211_CCK_RATE_2MB;
151                 break;
152         case 5500000:
153                 rate = IEEE80211_CCK_RATE_5MB;
154                 break;
155         case 11000000:
156                 rate = IEEE80211_CCK_RATE_11MB;
157                 break;
158         case 6000000:
159                 rate = IEEE80211_OFDM_RATE_6MB;
160                 is_ofdm = 1;
161                 break;
162         case 9000000:
163                 rate = IEEE80211_OFDM_RATE_9MB;
164                 is_ofdm = 1;
165                 break;
166         case 12000000:
167                 rate = IEEE80211_OFDM_RATE_12MB;
168                 is_ofdm = 1;
169                 break;
170         case 18000000:
171                 rate = IEEE80211_OFDM_RATE_18MB;
172                 is_ofdm = 1;
173                 break;
174         case 24000000:
175                 rate = IEEE80211_OFDM_RATE_24MB;
176                 is_ofdm = 1;
177                 break;
178         case 36000000:
179                 rate = IEEE80211_OFDM_RATE_36MB;
180                 is_ofdm = 1;
181                 break;
182         case 48000000:
183                 rate = IEEE80211_OFDM_RATE_48MB;
184                 is_ofdm = 1;
185                 break;
186         case 54000000:
187                 rate = IEEE80211_OFDM_RATE_54MB;
188                 is_ofdm = 1;
189                 break;
190         default:
191                 goto out;
192         }
193
194         spin_lock_irqsave(&mac->lock, flags);
195
196         /* Check if correct modulation for this PHY. */
197         if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
198                 goto out_unlock;
199
200         mac->txrates.default_rate = rate;
201         mac->txrates.default_fallback = lower_rate(mac, rate);
202         err = 0;
203
204 out_unlock:     
205         spin_unlock_irqrestore(&mac->lock, flags);
206 out:
207         return err;
208 }
209 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
210
211 int
212 ieee80211softmac_wx_get_rate(struct net_device *net_dev,
213                              struct iw_request_info *info,
214                              union iwreq_data *data,
215                              char *extra)
216 {
217         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
218         unsigned long flags;
219         int err = -EINVAL;
220
221         spin_lock_irqsave(&mac->lock, flags);
222         switch (mac->txrates.default_rate) {
223         case IEEE80211_CCK_RATE_1MB:
224                 data->bitrate.value = 1000000;
225                 break;
226         case IEEE80211_CCK_RATE_2MB:
227                 data->bitrate.value = 2000000;
228                 break;
229         case IEEE80211_CCK_RATE_5MB:
230                 data->bitrate.value = 5500000;
231                 break;
232         case IEEE80211_CCK_RATE_11MB:
233                 data->bitrate.value = 11000000;
234                 break;
235         case IEEE80211_OFDM_RATE_6MB:
236                 data->bitrate.value = 6000000;
237                 break;
238         case IEEE80211_OFDM_RATE_9MB:
239                 data->bitrate.value = 9000000;
240                 break;
241         case IEEE80211_OFDM_RATE_12MB:
242                 data->bitrate.value = 12000000;
243                 break;
244         case IEEE80211_OFDM_RATE_18MB:
245                 data->bitrate.value = 18000000;
246                 break;
247         case IEEE80211_OFDM_RATE_24MB:
248                 data->bitrate.value = 24000000;
249                 break;
250         case IEEE80211_OFDM_RATE_36MB:
251                 data->bitrate.value = 36000000;
252                 break;
253         case IEEE80211_OFDM_RATE_48MB:
254                 data->bitrate.value = 48000000;
255                 break;
256         case IEEE80211_OFDM_RATE_54MB:
257                 data->bitrate.value = 54000000;
258                 break;
259         default:
260                 assert(0);
261                 goto out_unlock;
262         }
263         err = 0;
264 out_unlock:
265         spin_unlock_irqrestore(&mac->lock, flags);
266
267         return err;
268 }
269 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
270
271 int
272 ieee80211softmac_wx_get_wap(struct net_device *net_dev,
273                             struct iw_request_info *info,
274                             union iwreq_data *data,
275                             char *extra)
276 {
277         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
278         int err = 0;
279         unsigned long flags;
280
281         spin_lock_irqsave(&mac->lock, flags);
282         if (mac->associnfo.bssvalid)
283                 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
284         else
285                 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
286         data->ap_addr.sa_family = ARPHRD_ETHER;
287         spin_unlock_irqrestore(&mac->lock, flags);
288         return err;
289 }
290 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
291
292 int
293 ieee80211softmac_wx_set_wap(struct net_device *net_dev,
294                             struct iw_request_info *info,
295                             union iwreq_data *data,
296                             char *extra)
297 {
298         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
299         static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
300         static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
301         unsigned long flags;
302
303         /* sanity check */
304         if (data->ap_addr.sa_family != ARPHRD_ETHER) {
305                 return -EINVAL;
306         }
307
308         spin_lock_irqsave(&mac->lock, flags);
309         if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
310             !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
311                 schedule_work(&mac->associnfo.work);
312                 goto out;
313         } else {
314                 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
315                         if (mac->associnfo.associating || mac->associated) {
316                         /* bssid unchanged and associated or associating - just return */
317                                 goto out;
318                         }
319                 } else {
320                         /* copy new value in data->ap_addr.sa_data to bssid */
321                         memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
322                 }       
323                 /* queue associate if new bssid or (old one again and not associated) */
324                 schedule_work(&mac->associnfo.work);
325         }
326
327 out:
328         spin_unlock_irqrestore(&mac->lock, flags);
329         return 0;
330 }
331 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
332
333 int
334 ieee80211softmac_wx_set_genie(struct net_device *dev,
335                               struct iw_request_info *info,
336                               union iwreq_data *wrqu,
337                               char *extra)
338 {
339         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
340         unsigned long flags;
341         int err = 0;
342         char *buf;
343         int i;
344         
345         spin_lock_irqsave(&mac->lock, flags);
346         /* bleh. shouldn't be locked for that kmalloc... */
347
348         if (wrqu->data.length) {
349                 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
350                         /* this is an IE, so the length must be
351                          * correct. Is it possible though that
352                          * more than one IE is passed in?
353                          */
354                         err = -EINVAL;
355                         goto out;
356                 }
357                 if (mac->wpa.IEbuflen <= wrqu->data.length) {
358                         buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
359                         if (!buf) {
360                                 err = -ENOMEM;
361                                 goto out;
362                         }
363                         kfree(mac->wpa.IE);
364                         mac->wpa.IE = buf;
365                         mac->wpa.IEbuflen = wrqu->data.length;
366                 }
367                 memcpy(mac->wpa.IE, extra, wrqu->data.length);
368                 dprintk(KERN_INFO PFX "generic IE set to ");
369                 for (i=0;i<wrqu->data.length;i++)
370                         dprintk("%.2x", mac->wpa.IE[i]);
371                 dprintk("\n");
372                 mac->wpa.IElen = wrqu->data.length;
373         } else {
374                 kfree(mac->wpa.IE);
375                 mac->wpa.IE = NULL;
376                 mac->wpa.IElen = 0;
377                 mac->wpa.IEbuflen = 0;
378         }
379
380  out:   
381         spin_unlock_irqrestore(&mac->lock, flags);
382         return err;
383 }
384 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
385
386 int
387 ieee80211softmac_wx_get_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         int space = wrqu->data.length;
396         
397         spin_lock_irqsave(&mac->lock, flags);
398         
399         wrqu->data.length = 0;
400         
401         if (mac->wpa.IE && mac->wpa.IElen) {
402                 wrqu->data.length = mac->wpa.IElen;
403                 if (mac->wpa.IElen <= space)
404                         memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
405                 else
406                         err = -E2BIG;
407         }
408         spin_unlock_irqrestore(&mac->lock, flags);
409         return err;
410 }
411 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
412