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