Commit | Line | Data |
---|---|---|
370121e5 JB |
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 |