[PATCH] softmac: reduce default rate to 11Mbps.
[safe/jmp/linux-2.6] / 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 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                 /* FIXME: We don't correctly handle backing down to lower
139                    rates, so 801.11g devices start off at 11M for now. People
140                    can manually change it if they really need to, but 11M is
141                    more reliable. Note similar logic in
142                    ieee80211softmac_wx_set_rate() */     
143                 if (ieee->modulation & IEEE80211_CCK_MODULATION)
144                         in_rate = 11000000;
145                 else
146                         in_rate = 54000000;
147         }
148
149         switch (in_rate) {
150         case 1000000:
151                 rate = IEEE80211_CCK_RATE_1MB;
152                 break;
153         case 2000000:
154                 rate = IEEE80211_CCK_RATE_2MB;
155                 break;
156         case 5500000:
157                 rate = IEEE80211_CCK_RATE_5MB;
158                 break;
159         case 11000000:
160                 rate = IEEE80211_CCK_RATE_11MB;
161                 break;
162         case 6000000:
163                 rate = IEEE80211_OFDM_RATE_6MB;
164                 is_ofdm = 1;
165                 break;
166         case 9000000:
167                 rate = IEEE80211_OFDM_RATE_9MB;
168                 is_ofdm = 1;
169                 break;
170         case 12000000:
171                 rate = IEEE80211_OFDM_RATE_12MB;
172                 is_ofdm = 1;
173                 break;
174         case 18000000:
175                 rate = IEEE80211_OFDM_RATE_18MB;
176                 is_ofdm = 1;
177                 break;
178         case 24000000:
179                 rate = IEEE80211_OFDM_RATE_24MB;
180                 is_ofdm = 1;
181                 break;
182         case 36000000:
183                 rate = IEEE80211_OFDM_RATE_36MB;
184                 is_ofdm = 1;
185                 break;
186         case 48000000:
187                 rate = IEEE80211_OFDM_RATE_48MB;
188                 is_ofdm = 1;
189                 break;
190         case 54000000:
191                 rate = IEEE80211_OFDM_RATE_54MB;
192                 is_ofdm = 1;
193                 break;
194         default:
195                 goto out;
196         }
197
198         spin_lock_irqsave(&mac->lock, flags);
199
200         /* Check if correct modulation for this PHY. */
201         if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
202                 goto out_unlock;
203
204         mac->txrates.default_rate = rate;
205         mac->txrates.default_fallback = lower_rate(mac, rate);
206         err = 0;
207
208 out_unlock:     
209         spin_unlock_irqrestore(&mac->lock, flags);
210 out:
211         return err;
212 }
213 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
214
215 int
216 ieee80211softmac_wx_get_rate(struct net_device *net_dev,
217                              struct iw_request_info *info,
218                              union iwreq_data *data,
219                              char *extra)
220 {
221         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
222         unsigned long flags;
223         int err = -EINVAL;
224
225         spin_lock_irqsave(&mac->lock, flags);
226         switch (mac->txrates.default_rate) {
227         case IEEE80211_CCK_RATE_1MB:
228                 data->bitrate.value = 1000000;
229                 break;
230         case IEEE80211_CCK_RATE_2MB:
231                 data->bitrate.value = 2000000;
232                 break;
233         case IEEE80211_CCK_RATE_5MB:
234                 data->bitrate.value = 5500000;
235                 break;
236         case IEEE80211_CCK_RATE_11MB:
237                 data->bitrate.value = 11000000;
238                 break;
239         case IEEE80211_OFDM_RATE_6MB:
240                 data->bitrate.value = 6000000;
241                 break;
242         case IEEE80211_OFDM_RATE_9MB:
243                 data->bitrate.value = 9000000;
244                 break;
245         case IEEE80211_OFDM_RATE_12MB:
246                 data->bitrate.value = 12000000;
247                 break;
248         case IEEE80211_OFDM_RATE_18MB:
249                 data->bitrate.value = 18000000;
250                 break;
251         case IEEE80211_OFDM_RATE_24MB:
252                 data->bitrate.value = 24000000;
253                 break;
254         case IEEE80211_OFDM_RATE_36MB:
255                 data->bitrate.value = 36000000;
256                 break;
257         case IEEE80211_OFDM_RATE_48MB:
258                 data->bitrate.value = 48000000;
259                 break;
260         case IEEE80211_OFDM_RATE_54MB:
261                 data->bitrate.value = 54000000;
262                 break;
263         default:
264                 assert(0);
265                 goto out_unlock;
266         }
267         err = 0;
268 out_unlock:
269         spin_unlock_irqrestore(&mac->lock, flags);
270
271         return err;
272 }
273 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
274
275 int
276 ieee80211softmac_wx_get_wap(struct net_device *net_dev,
277                             struct iw_request_info *info,
278                             union iwreq_data *data,
279                             char *extra)
280 {
281         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
282         int err = 0;
283         unsigned long flags;
284
285         spin_lock_irqsave(&mac->lock, flags);
286         if (mac->associnfo.bssvalid)
287                 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
288         else
289                 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
290         data->ap_addr.sa_family = ARPHRD_ETHER;
291         spin_unlock_irqrestore(&mac->lock, flags);
292         return err;
293 }
294 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
295
296 int
297 ieee80211softmac_wx_set_wap(struct net_device *net_dev,
298                             struct iw_request_info *info,
299                             union iwreq_data *data,
300                             char *extra)
301 {
302         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
303         static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
304         static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
305         unsigned long flags;
306
307         /* sanity check */
308         if (data->ap_addr.sa_family != ARPHRD_ETHER) {
309                 return -EINVAL;
310         }
311
312         spin_lock_irqsave(&mac->lock, flags);
313         if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
314             !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
315                 schedule_work(&mac->associnfo.work);
316                 goto out;
317         } else {
318                 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
319                         if (mac->associnfo.associating || mac->associated) {
320                         /* bssid unchanged and associated or associating - just return */
321                                 goto out;
322                         }
323                 } else {
324                         /* copy new value in data->ap_addr.sa_data to bssid */
325                         memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
326                 }       
327                 /* queue associate if new bssid or (old one again and not associated) */
328                 schedule_work(&mac->associnfo.work);
329         }
330
331 out:
332         spin_unlock_irqrestore(&mac->lock, flags);
333         return 0;
334 }
335 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
336
337 int
338 ieee80211softmac_wx_set_genie(struct net_device *dev,
339                               struct iw_request_info *info,
340                               union iwreq_data *wrqu,
341                               char *extra)
342 {
343         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
344         unsigned long flags;
345         int err = 0;
346         char *buf;
347         int i;
348         
349         spin_lock_irqsave(&mac->lock, flags);
350         /* bleh. shouldn't be locked for that kmalloc... */
351
352         if (wrqu->data.length) {
353                 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
354                         /* this is an IE, so the length must be
355                          * correct. Is it possible though that
356                          * more than one IE is passed in?
357                          */
358                         err = -EINVAL;
359                         goto out;
360                 }
361                 if (mac->wpa.IEbuflen <= wrqu->data.length) {
362                         buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
363                         if (!buf) {
364                                 err = -ENOMEM;
365                                 goto out;
366                         }
367                         kfree(mac->wpa.IE);
368                         mac->wpa.IE = buf;
369                         mac->wpa.IEbuflen = wrqu->data.length;
370                 }
371                 memcpy(mac->wpa.IE, extra, wrqu->data.length);
372                 dprintk(KERN_INFO PFX "generic IE set to ");
373                 for (i=0;i<wrqu->data.length;i++)
374                         dprintk("%.2x", mac->wpa.IE[i]);
375                 dprintk("\n");
376                 mac->wpa.IElen = wrqu->data.length;
377         } else {
378                 kfree(mac->wpa.IE);
379                 mac->wpa.IE = NULL;
380                 mac->wpa.IElen = 0;
381                 mac->wpa.IEbuflen = 0;
382         }
383
384  out:   
385         spin_unlock_irqrestore(&mac->lock, flags);
386         return err;
387 }
388 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
389
390 int
391 ieee80211softmac_wx_get_genie(struct net_device *dev,
392                               struct iw_request_info *info,
393                               union iwreq_data *wrqu,
394                               char *extra)
395 {
396         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
397         unsigned long flags;
398         int err = 0;
399         int space = wrqu->data.length;
400         
401         spin_lock_irqsave(&mac->lock, flags);
402         
403         wrqu->data.length = 0;
404         
405         if (mac->wpa.IE && mac->wpa.IElen) {
406                 wrqu->data.length = mac->wpa.IElen;
407                 if (mac->wpa.IElen <= space)
408                         memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
409                 else
410                         err = -E2BIG;
411         }
412         spin_unlock_irqrestore(&mac->lock, flags);
413         return err;
414 }
415 EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
416