Root/
1 | /* |
2 | * cfg80211 - wext compat code |
3 | * |
4 | * This is temporary code until all wireless functionality is migrated |
5 | * into cfg80211, when that happens all the exports here go away and |
6 | * we directly assign the wireless handlers of wireless interfaces. |
7 | * |
8 | * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net> |
9 | */ |
10 | |
11 | #include <linux/wireless.h> |
12 | #include <linux/nl80211.h> |
13 | #include <linux/if_arp.h> |
14 | #include <linux/etherdevice.h> |
15 | #include <linux/slab.h> |
16 | #include <net/iw_handler.h> |
17 | #include <net/cfg80211.h> |
18 | #include "wext-compat.h" |
19 | #include "core.h" |
20 | |
21 | int cfg80211_wext_giwname(struct net_device *dev, |
22 | struct iw_request_info *info, |
23 | char *name, char *extra) |
24 | { |
25 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
26 | struct ieee80211_supported_band *sband; |
27 | bool is_ht = false, is_a = false, is_b = false, is_g = false; |
28 | |
29 | if (!wdev) |
30 | return -EOPNOTSUPP; |
31 | |
32 | sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; |
33 | if (sband) { |
34 | is_a = true; |
35 | is_ht |= sband->ht_cap.ht_supported; |
36 | } |
37 | |
38 | sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; |
39 | if (sband) { |
40 | int i; |
41 | /* Check for mandatory rates */ |
42 | for (i = 0; i < sband->n_bitrates; i++) { |
43 | if (sband->bitrates[i].bitrate == 10) |
44 | is_b = true; |
45 | if (sband->bitrates[i].bitrate == 60) |
46 | is_g = true; |
47 | } |
48 | is_ht |= sband->ht_cap.ht_supported; |
49 | } |
50 | |
51 | strcpy(name, "IEEE 802.11"); |
52 | if (is_a) |
53 | strcat(name, "a"); |
54 | if (is_b) |
55 | strcat(name, "b"); |
56 | if (is_g) |
57 | strcat(name, "g"); |
58 | if (is_ht) |
59 | strcat(name, "n"); |
60 | |
61 | return 0; |
62 | } |
63 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwname); |
64 | |
65 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, |
66 | u32 *mode, char *extra) |
67 | { |
68 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
69 | struct cfg80211_registered_device *rdev; |
70 | struct vif_params vifparams; |
71 | enum nl80211_iftype type; |
72 | int ret; |
73 | |
74 | rdev = wiphy_to_dev(wdev->wiphy); |
75 | |
76 | switch (*mode) { |
77 | case IW_MODE_INFRA: |
78 | type = NL80211_IFTYPE_STATION; |
79 | break; |
80 | case IW_MODE_ADHOC: |
81 | type = NL80211_IFTYPE_ADHOC; |
82 | break; |
83 | case IW_MODE_REPEAT: |
84 | type = NL80211_IFTYPE_WDS; |
85 | break; |
86 | case IW_MODE_MONITOR: |
87 | type = NL80211_IFTYPE_MONITOR; |
88 | break; |
89 | default: |
90 | return -EINVAL; |
91 | } |
92 | |
93 | if (type == wdev->iftype) |
94 | return 0; |
95 | |
96 | memset(&vifparams, 0, sizeof(vifparams)); |
97 | |
98 | cfg80211_lock_rdev(rdev); |
99 | ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); |
100 | cfg80211_unlock_rdev(rdev); |
101 | |
102 | return ret; |
103 | } |
104 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); |
105 | |
106 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, |
107 | u32 *mode, char *extra) |
108 | { |
109 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
110 | |
111 | if (!wdev) |
112 | return -EOPNOTSUPP; |
113 | |
114 | switch (wdev->iftype) { |
115 | case NL80211_IFTYPE_AP: |
116 | *mode = IW_MODE_MASTER; |
117 | break; |
118 | case NL80211_IFTYPE_STATION: |
119 | *mode = IW_MODE_INFRA; |
120 | break; |
121 | case NL80211_IFTYPE_ADHOC: |
122 | *mode = IW_MODE_ADHOC; |
123 | break; |
124 | case NL80211_IFTYPE_MONITOR: |
125 | *mode = IW_MODE_MONITOR; |
126 | break; |
127 | case NL80211_IFTYPE_WDS: |
128 | *mode = IW_MODE_REPEAT; |
129 | break; |
130 | case NL80211_IFTYPE_AP_VLAN: |
131 | *mode = IW_MODE_SECOND; /* FIXME */ |
132 | break; |
133 | default: |
134 | *mode = IW_MODE_AUTO; |
135 | break; |
136 | } |
137 | return 0; |
138 | } |
139 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode); |
140 | |
141 | |
142 | int cfg80211_wext_giwrange(struct net_device *dev, |
143 | struct iw_request_info *info, |
144 | struct iw_point *data, char *extra) |
145 | { |
146 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
147 | struct iw_range *range = (struct iw_range *) extra; |
148 | enum ieee80211_band band; |
149 | int i, c = 0; |
150 | |
151 | if (!wdev) |
152 | return -EOPNOTSUPP; |
153 | |
154 | data->length = sizeof(struct iw_range); |
155 | memset(range, 0, sizeof(struct iw_range)); |
156 | |
157 | range->we_version_compiled = WIRELESS_EXT; |
158 | range->we_version_source = 21; |
159 | range->retry_capa = IW_RETRY_LIMIT; |
160 | range->retry_flags = IW_RETRY_LIMIT; |
161 | range->min_retry = 0; |
162 | range->max_retry = 255; |
163 | range->min_rts = 0; |
164 | range->max_rts = 2347; |
165 | range->min_frag = 256; |
166 | range->max_frag = 2346; |
167 | |
168 | range->max_encoding_tokens = 4; |
169 | |
170 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; |
171 | |
172 | switch (wdev->wiphy->signal_type) { |
173 | case CFG80211_SIGNAL_TYPE_NONE: |
174 | break; |
175 | case CFG80211_SIGNAL_TYPE_MBM: |
176 | range->max_qual.level = -110; |
177 | range->max_qual.qual = 70; |
178 | range->avg_qual.qual = 35; |
179 | range->max_qual.updated |= IW_QUAL_DBM; |
180 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; |
181 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; |
182 | break; |
183 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
184 | range->max_qual.level = 100; |
185 | range->max_qual.qual = 100; |
186 | range->avg_qual.qual = 50; |
187 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; |
188 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; |
189 | break; |
190 | } |
191 | |
192 | range->avg_qual.level = range->max_qual.level / 2; |
193 | range->avg_qual.noise = range->max_qual.noise / 2; |
194 | range->avg_qual.updated = range->max_qual.updated; |
195 | |
196 | for (i = 0; i < wdev->wiphy->n_cipher_suites; i++) { |
197 | switch (wdev->wiphy->cipher_suites[i]) { |
198 | case WLAN_CIPHER_SUITE_TKIP: |
199 | range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP | |
200 | IW_ENC_CAPA_WPA); |
201 | break; |
202 | |
203 | case WLAN_CIPHER_SUITE_CCMP: |
204 | range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP | |
205 | IW_ENC_CAPA_WPA2); |
206 | break; |
207 | |
208 | case WLAN_CIPHER_SUITE_WEP40: |
209 | range->encoding_size[range->num_encoding_sizes++] = |
210 | WLAN_KEY_LEN_WEP40; |
211 | break; |
212 | |
213 | case WLAN_CIPHER_SUITE_WEP104: |
214 | range->encoding_size[range->num_encoding_sizes++] = |
215 | WLAN_KEY_LEN_WEP104; |
216 | break; |
217 | } |
218 | } |
219 | |
220 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { |
221 | struct ieee80211_supported_band *sband; |
222 | |
223 | sband = wdev->wiphy->bands[band]; |
224 | |
225 | if (!sband) |
226 | continue; |
227 | |
228 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { |
229 | struct ieee80211_channel *chan = &sband->channels[i]; |
230 | |
231 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { |
232 | range->freq[c].i = |
233 | ieee80211_frequency_to_channel( |
234 | chan->center_freq); |
235 | range->freq[c].m = chan->center_freq; |
236 | range->freq[c].e = 6; |
237 | c++; |
238 | } |
239 | } |
240 | } |
241 | range->num_channels = c; |
242 | range->num_frequency = c; |
243 | |
244 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); |
245 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); |
246 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); |
247 | |
248 | if (wdev->wiphy->max_scan_ssids > 0) |
249 | range->scan_capa |= IW_SCAN_CAPA_ESSID; |
250 | |
251 | return 0; |
252 | } |
253 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); |
254 | |
255 | |
256 | /** |
257 | * cfg80211_wext_freq - get wext frequency for non-"auto" |
258 | * @wiphy: the wiphy |
259 | * @freq: the wext freq encoding |
260 | * |
261 | * Returns a frequency, or a negative error code, or 0 for auto. |
262 | */ |
263 | int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) |
264 | { |
265 | /* |
266 | * Parse frequency - return 0 for auto and |
267 | * -EINVAL for impossible things. |
268 | */ |
269 | if (freq->e == 0) { |
270 | if (freq->m < 0) |
271 | return 0; |
272 | return ieee80211_channel_to_frequency(freq->m); |
273 | } else { |
274 | int i, div = 1000000; |
275 | for (i = 0; i < freq->e; i++) |
276 | div /= 10; |
277 | if (div <= 0) |
278 | return -EINVAL; |
279 | return freq->m / div; |
280 | } |
281 | } |
282 | |
283 | int cfg80211_wext_siwrts(struct net_device *dev, |
284 | struct iw_request_info *info, |
285 | struct iw_param *rts, char *extra) |
286 | { |
287 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
288 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
289 | u32 orts = wdev->wiphy->rts_threshold; |
290 | int err; |
291 | |
292 | if (rts->disabled || !rts->fixed) |
293 | wdev->wiphy->rts_threshold = (u32) -1; |
294 | else if (rts->value < 0) |
295 | return -EINVAL; |
296 | else |
297 | wdev->wiphy->rts_threshold = rts->value; |
298 | |
299 | err = rdev->ops->set_wiphy_params(wdev->wiphy, |
300 | WIPHY_PARAM_RTS_THRESHOLD); |
301 | if (err) |
302 | wdev->wiphy->rts_threshold = orts; |
303 | |
304 | return err; |
305 | } |
306 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts); |
307 | |
308 | int cfg80211_wext_giwrts(struct net_device *dev, |
309 | struct iw_request_info *info, |
310 | struct iw_param *rts, char *extra) |
311 | { |
312 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
313 | |
314 | rts->value = wdev->wiphy->rts_threshold; |
315 | rts->disabled = rts->value == (u32) -1; |
316 | rts->fixed = 1; |
317 | |
318 | return 0; |
319 | } |
320 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts); |
321 | |
322 | int cfg80211_wext_siwfrag(struct net_device *dev, |
323 | struct iw_request_info *info, |
324 | struct iw_param *frag, char *extra) |
325 | { |
326 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
327 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
328 | u32 ofrag = wdev->wiphy->frag_threshold; |
329 | int err; |
330 | |
331 | if (frag->disabled || !frag->fixed) |
332 | wdev->wiphy->frag_threshold = (u32) -1; |
333 | else if (frag->value < 256) |
334 | return -EINVAL; |
335 | else { |
336 | /* Fragment length must be even, so strip LSB. */ |
337 | wdev->wiphy->frag_threshold = frag->value & ~0x1; |
338 | } |
339 | |
340 | err = rdev->ops->set_wiphy_params(wdev->wiphy, |
341 | WIPHY_PARAM_FRAG_THRESHOLD); |
342 | if (err) |
343 | wdev->wiphy->frag_threshold = ofrag; |
344 | |
345 | return err; |
346 | } |
347 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag); |
348 | |
349 | int cfg80211_wext_giwfrag(struct net_device *dev, |
350 | struct iw_request_info *info, |
351 | struct iw_param *frag, char *extra) |
352 | { |
353 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
354 | |
355 | frag->value = wdev->wiphy->frag_threshold; |
356 | frag->disabled = frag->value == (u32) -1; |
357 | frag->fixed = 1; |
358 | |
359 | return 0; |
360 | } |
361 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag); |
362 | |
363 | int cfg80211_wext_siwretry(struct net_device *dev, |
364 | struct iw_request_info *info, |
365 | struct iw_param *retry, char *extra) |
366 | { |
367 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
368 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
369 | u32 changed = 0; |
370 | u8 olong = wdev->wiphy->retry_long; |
371 | u8 oshort = wdev->wiphy->retry_short; |
372 | int err; |
373 | |
374 | if (retry->disabled || |
375 | (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) |
376 | return -EINVAL; |
377 | |
378 | if (retry->flags & IW_RETRY_LONG) { |
379 | wdev->wiphy->retry_long = retry->value; |
380 | changed |= WIPHY_PARAM_RETRY_LONG; |
381 | } else if (retry->flags & IW_RETRY_SHORT) { |
382 | wdev->wiphy->retry_short = retry->value; |
383 | changed |= WIPHY_PARAM_RETRY_SHORT; |
384 | } else { |
385 | wdev->wiphy->retry_short = retry->value; |
386 | wdev->wiphy->retry_long = retry->value; |
387 | changed |= WIPHY_PARAM_RETRY_LONG; |
388 | changed |= WIPHY_PARAM_RETRY_SHORT; |
389 | } |
390 | |
391 | if (!changed) |
392 | return 0; |
393 | |
394 | err = rdev->ops->set_wiphy_params(wdev->wiphy, changed); |
395 | if (err) { |
396 | wdev->wiphy->retry_short = oshort; |
397 | wdev->wiphy->retry_long = olong; |
398 | } |
399 | |
400 | return err; |
401 | } |
402 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry); |
403 | |
404 | int cfg80211_wext_giwretry(struct net_device *dev, |
405 | struct iw_request_info *info, |
406 | struct iw_param *retry, char *extra) |
407 | { |
408 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
409 | |
410 | retry->disabled = 0; |
411 | |
412 | if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) { |
413 | /* |
414 | * First return short value, iwconfig will ask long value |
415 | * later if needed |
416 | */ |
417 | retry->flags |= IW_RETRY_LIMIT; |
418 | retry->value = wdev->wiphy->retry_short; |
419 | if (wdev->wiphy->retry_long != wdev->wiphy->retry_short) |
420 | retry->flags |= IW_RETRY_LONG; |
421 | |
422 | return 0; |
423 | } |
424 | |
425 | if (retry->flags & IW_RETRY_LONG) { |
426 | retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; |
427 | retry->value = wdev->wiphy->retry_long; |
428 | } |
429 | |
430 | return 0; |
431 | } |
432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
433 | |
434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
435 | struct net_device *dev, bool pairwise, |
436 | const u8 *addr, bool remove, bool tx_key, |
437 | int idx, struct key_params *params) |
438 | { |
439 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
440 | int err, i; |
441 | bool rejoin = false; |
442 | |
443 | if (pairwise && !addr) |
444 | return -EINVAL; |
445 | |
446 | if (!wdev->wext.keys) { |
447 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
448 | GFP_KERNEL); |
449 | if (!wdev->wext.keys) |
450 | return -ENOMEM; |
451 | for (i = 0; i < 6; i++) |
452 | wdev->wext.keys->params[i].key = |
453 | wdev->wext.keys->data[i]; |
454 | } |
455 | |
456 | if (wdev->iftype != NL80211_IFTYPE_ADHOC && |
457 | wdev->iftype != NL80211_IFTYPE_STATION) |
458 | return -EOPNOTSUPP; |
459 | |
460 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { |
461 | if (!wdev->current_bss) |
462 | return -ENOLINK; |
463 | |
464 | if (!rdev->ops->set_default_mgmt_key) |
465 | return -EOPNOTSUPP; |
466 | |
467 | if (idx < 4 || idx > 5) |
468 | return -EINVAL; |
469 | } else if (idx < 0 || idx > 3) |
470 | return -EINVAL; |
471 | |
472 | if (remove) { |
473 | err = 0; |
474 | if (wdev->current_bss) { |
475 | /* |
476 | * If removing the current TX key, we will need to |
477 | * join a new IBSS without the privacy bit clear. |
478 | */ |
479 | if (idx == wdev->wext.default_key && |
480 | wdev->iftype == NL80211_IFTYPE_ADHOC) { |
481 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
482 | rejoin = true; |
483 | } |
484 | |
485 | if (!pairwise && addr && |
486 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) |
487 | err = -ENOENT; |
488 | else |
489 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, |
490 | pairwise, addr); |
491 | } |
492 | wdev->wext.connect.privacy = false; |
493 | /* |
494 | * Applications using wireless extensions expect to be |
495 | * able to delete keys that don't exist, so allow that. |
496 | */ |
497 | if (err == -ENOENT) |
498 | err = 0; |
499 | if (!err) { |
500 | if (!addr) { |
501 | wdev->wext.keys->params[idx].key_len = 0; |
502 | wdev->wext.keys->params[idx].cipher = 0; |
503 | } |
504 | if (idx == wdev->wext.default_key) |
505 | wdev->wext.default_key = -1; |
506 | else if (idx == wdev->wext.default_mgmt_key) |
507 | wdev->wext.default_mgmt_key = -1; |
508 | } |
509 | |
510 | if (!err && rejoin) |
511 | err = cfg80211_ibss_wext_join(rdev, wdev); |
512 | |
513 | return err; |
514 | } |
515 | |
516 | if (addr) |
517 | tx_key = false; |
518 | |
519 | if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr)) |
520 | return -EINVAL; |
521 | |
522 | err = 0; |
523 | if (wdev->current_bss) |
524 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, |
525 | pairwise, addr, params); |
526 | if (err) |
527 | return err; |
528 | |
529 | if (!addr) { |
530 | wdev->wext.keys->params[idx] = *params; |
531 | memcpy(wdev->wext.keys->data[idx], |
532 | params->key, params->key_len); |
533 | wdev->wext.keys->params[idx].key = |
534 | wdev->wext.keys->data[idx]; |
535 | } |
536 | |
537 | if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || |
538 | params->cipher == WLAN_CIPHER_SUITE_WEP104) && |
539 | (tx_key || (!addr && wdev->wext.default_key == -1))) { |
540 | if (wdev->current_bss) { |
541 | /* |
542 | * If we are getting a new TX key from not having |
543 | * had one before we need to join a new IBSS with |
544 | * the privacy bit set. |
545 | */ |
546 | if (wdev->iftype == NL80211_IFTYPE_ADHOC && |
547 | wdev->wext.default_key == -1) { |
548 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
549 | rejoin = true; |
550 | } |
551 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, |
552 | idx, true, true); |
553 | } |
554 | if (!err) { |
555 | wdev->wext.default_key = idx; |
556 | if (rejoin) |
557 | err = cfg80211_ibss_wext_join(rdev, wdev); |
558 | } |
559 | return err; |
560 | } |
561 | |
562 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && |
563 | (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { |
564 | if (wdev->current_bss) |
565 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, |
566 | dev, idx); |
567 | if (!err) |
568 | wdev->wext.default_mgmt_key = idx; |
569 | return err; |
570 | } |
571 | |
572 | return 0; |
573 | } |
574 | |
575 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
576 | struct net_device *dev, bool pairwise, |
577 | const u8 *addr, bool remove, bool tx_key, |
578 | int idx, struct key_params *params) |
579 | { |
580 | int err; |
581 | |
582 | /* devlist mutex needed for possible IBSS re-join */ |
583 | mutex_lock(&rdev->devlist_mtx); |
584 | wdev_lock(dev->ieee80211_ptr); |
585 | err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, |
586 | remove, tx_key, idx, params); |
587 | wdev_unlock(dev->ieee80211_ptr); |
588 | mutex_unlock(&rdev->devlist_mtx); |
589 | |
590 | return err; |
591 | } |
592 | |
593 | int cfg80211_wext_siwencode(struct net_device *dev, |
594 | struct iw_request_info *info, |
595 | struct iw_point *erq, char *keybuf) |
596 | { |
597 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
598 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
599 | int idx, err; |
600 | bool remove = false; |
601 | struct key_params params; |
602 | |
603 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
604 | wdev->iftype != NL80211_IFTYPE_ADHOC) |
605 | return -EOPNOTSUPP; |
606 | |
607 | /* no use -- only MFP (set_default_mgmt_key) is optional */ |
608 | if (!rdev->ops->del_key || |
609 | !rdev->ops->add_key || |
610 | !rdev->ops->set_default_key) |
611 | return -EOPNOTSUPP; |
612 | |
613 | idx = erq->flags & IW_ENCODE_INDEX; |
614 | if (idx == 0) { |
615 | idx = wdev->wext.default_key; |
616 | if (idx < 0) |
617 | idx = 0; |
618 | } else if (idx < 1 || idx > 4) |
619 | return -EINVAL; |
620 | else |
621 | idx--; |
622 | |
623 | if (erq->flags & IW_ENCODE_DISABLED) |
624 | remove = true; |
625 | else if (erq->length == 0) { |
626 | /* No key data - just set the default TX key index */ |
627 | err = 0; |
628 | wdev_lock(wdev); |
629 | if (wdev->current_bss) |
630 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, |
631 | idx, true, true); |
632 | if (!err) |
633 | wdev->wext.default_key = idx; |
634 | wdev_unlock(wdev); |
635 | return err; |
636 | } |
637 | |
638 | memset(¶ms, 0, sizeof(params)); |
639 | params.key = keybuf; |
640 | params.key_len = erq->length; |
641 | if (erq->length == 5) |
642 | params.cipher = WLAN_CIPHER_SUITE_WEP40; |
643 | else if (erq->length == 13) |
644 | params.cipher = WLAN_CIPHER_SUITE_WEP104; |
645 | else if (!remove) |
646 | return -EINVAL; |
647 | |
648 | return cfg80211_set_encryption(rdev, dev, false, NULL, remove, |
649 | wdev->wext.default_key == -1, |
650 | idx, ¶ms); |
651 | } |
652 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode); |
653 | |
654 | int cfg80211_wext_siwencodeext(struct net_device *dev, |
655 | struct iw_request_info *info, |
656 | struct iw_point *erq, char *extra) |
657 | { |
658 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
659 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
660 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; |
661 | const u8 *addr; |
662 | int idx; |
663 | bool remove = false; |
664 | struct key_params params; |
665 | u32 cipher; |
666 | |
667 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
668 | wdev->iftype != NL80211_IFTYPE_ADHOC) |
669 | return -EOPNOTSUPP; |
670 | |
671 | /* no use -- only MFP (set_default_mgmt_key) is optional */ |
672 | if (!rdev->ops->del_key || |
673 | !rdev->ops->add_key || |
674 | !rdev->ops->set_default_key) |
675 | return -EOPNOTSUPP; |
676 | |
677 | switch (ext->alg) { |
678 | case IW_ENCODE_ALG_NONE: |
679 | remove = true; |
680 | cipher = 0; |
681 | break; |
682 | case IW_ENCODE_ALG_WEP: |
683 | if (ext->key_len == 5) |
684 | cipher = WLAN_CIPHER_SUITE_WEP40; |
685 | else if (ext->key_len == 13) |
686 | cipher = WLAN_CIPHER_SUITE_WEP104; |
687 | else |
688 | return -EINVAL; |
689 | break; |
690 | case IW_ENCODE_ALG_TKIP: |
691 | cipher = WLAN_CIPHER_SUITE_TKIP; |
692 | break; |
693 | case IW_ENCODE_ALG_CCMP: |
694 | cipher = WLAN_CIPHER_SUITE_CCMP; |
695 | break; |
696 | case IW_ENCODE_ALG_AES_CMAC: |
697 | cipher = WLAN_CIPHER_SUITE_AES_CMAC; |
698 | break; |
699 | default: |
700 | return -EOPNOTSUPP; |
701 | } |
702 | |
703 | if (erq->flags & IW_ENCODE_DISABLED) |
704 | remove = true; |
705 | |
706 | idx = erq->flags & IW_ENCODE_INDEX; |
707 | if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) { |
708 | if (idx < 4 || idx > 5) { |
709 | idx = wdev->wext.default_mgmt_key; |
710 | if (idx < 0) |
711 | return -EINVAL; |
712 | } else |
713 | idx--; |
714 | } else { |
715 | if (idx < 1 || idx > 4) { |
716 | idx = wdev->wext.default_key; |
717 | if (idx < 0) |
718 | return -EINVAL; |
719 | } else |
720 | idx--; |
721 | } |
722 | |
723 | addr = ext->addr.sa_data; |
724 | if (is_broadcast_ether_addr(addr)) |
725 | addr = NULL; |
726 | |
727 | memset(¶ms, 0, sizeof(params)); |
728 | params.key = ext->key; |
729 | params.key_len = ext->key_len; |
730 | params.cipher = cipher; |
731 | |
732 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { |
733 | params.seq = ext->rx_seq; |
734 | params.seq_len = 6; |
735 | } |
736 | |
737 | return cfg80211_set_encryption( |
738 | rdev, dev, |
739 | !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), |
740 | addr, remove, |
741 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, |
742 | idx, ¶ms); |
743 | } |
744 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); |
745 | |
746 | int cfg80211_wext_giwencode(struct net_device *dev, |
747 | struct iw_request_info *info, |
748 | struct iw_point *erq, char *keybuf) |
749 | { |
750 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
751 | int idx; |
752 | |
753 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
754 | wdev->iftype != NL80211_IFTYPE_ADHOC) |
755 | return -EOPNOTSUPP; |
756 | |
757 | idx = erq->flags & IW_ENCODE_INDEX; |
758 | if (idx == 0) { |
759 | idx = wdev->wext.default_key; |
760 | if (idx < 0) |
761 | idx = 0; |
762 | } else if (idx < 1 || idx > 4) |
763 | return -EINVAL; |
764 | else |
765 | idx--; |
766 | |
767 | erq->flags = idx + 1; |
768 | |
769 | if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) { |
770 | erq->flags |= IW_ENCODE_DISABLED; |
771 | erq->length = 0; |
772 | return 0; |
773 | } |
774 | |
775 | erq->length = min_t(size_t, erq->length, |
776 | wdev->wext.keys->params[idx].key_len); |
777 | memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length); |
778 | erq->flags |= IW_ENCODE_ENABLED; |
779 | |
780 | return 0; |
781 | } |
782 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); |
783 | |
784 | int cfg80211_wext_siwfreq(struct net_device *dev, |
785 | struct iw_request_info *info, |
786 | struct iw_freq *wextfreq, char *extra) |
787 | { |
788 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
789 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
790 | int freq, err; |
791 | |
792 | switch (wdev->iftype) { |
793 | case NL80211_IFTYPE_STATION: |
794 | return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra); |
795 | case NL80211_IFTYPE_ADHOC: |
796 | return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); |
797 | case NL80211_IFTYPE_MONITOR: |
798 | case NL80211_IFTYPE_WDS: |
799 | case NL80211_IFTYPE_MESH_POINT: |
800 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
801 | if (freq < 0) |
802 | return freq; |
803 | if (freq == 0) |
804 | return -EINVAL; |
805 | mutex_lock(&rdev->devlist_mtx); |
806 | wdev_lock(wdev); |
807 | err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); |
808 | wdev_unlock(wdev); |
809 | mutex_unlock(&rdev->devlist_mtx); |
810 | return err; |
811 | default: |
812 | return -EOPNOTSUPP; |
813 | } |
814 | } |
815 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); |
816 | |
817 | int cfg80211_wext_giwfreq(struct net_device *dev, |
818 | struct iw_request_info *info, |
819 | struct iw_freq *freq, char *extra) |
820 | { |
821 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
822 | |
823 | switch (wdev->iftype) { |
824 | case NL80211_IFTYPE_STATION: |
825 | return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); |
826 | case NL80211_IFTYPE_ADHOC: |
827 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); |
828 | default: |
829 | if (!wdev->channel) |
830 | return -EINVAL; |
831 | freq->m = wdev->channel->center_freq; |
832 | freq->e = 6; |
833 | return 0; |
834 | } |
835 | } |
836 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq); |
837 | |
838 | int cfg80211_wext_siwtxpower(struct net_device *dev, |
839 | struct iw_request_info *info, |
840 | union iwreq_data *data, char *extra) |
841 | { |
842 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
843 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
844 | enum nl80211_tx_power_setting type; |
845 | int dbm = 0; |
846 | |
847 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) |
848 | return -EINVAL; |
849 | if (data->txpower.flags & IW_TXPOW_RANGE) |
850 | return -EINVAL; |
851 | |
852 | if (!rdev->ops->set_tx_power) |
853 | return -EOPNOTSUPP; |
854 | |
855 | /* only change when not disabling */ |
856 | if (!data->txpower.disabled) { |
857 | rfkill_set_sw_state(rdev->rfkill, false); |
858 | |
859 | if (data->txpower.fixed) { |
860 | /* |
861 | * wext doesn't support negative values, see |
862 | * below where it's for automatic |
863 | */ |
864 | if (data->txpower.value < 0) |
865 | return -EINVAL; |
866 | dbm = data->txpower.value; |
867 | type = NL80211_TX_POWER_FIXED; |
868 | /* TODO: do regulatory check! */ |
869 | } else { |
870 | /* |
871 | * Automatic power level setting, max being the value |
872 | * passed in from userland. |
873 | */ |
874 | if (data->txpower.value < 0) { |
875 | type = NL80211_TX_POWER_AUTOMATIC; |
876 | } else { |
877 | dbm = data->txpower.value; |
878 | type = NL80211_TX_POWER_LIMITED; |
879 | } |
880 | } |
881 | } else { |
882 | rfkill_set_sw_state(rdev->rfkill, true); |
883 | schedule_work(&rdev->rfkill_sync); |
884 | return 0; |
885 | } |
886 | |
887 | return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm)); |
888 | } |
889 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); |
890 | |
891 | int cfg80211_wext_giwtxpower(struct net_device *dev, |
892 | struct iw_request_info *info, |
893 | union iwreq_data *data, char *extra) |
894 | { |
895 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
896 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
897 | int err, val; |
898 | |
899 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) |
900 | return -EINVAL; |
901 | if (data->txpower.flags & IW_TXPOW_RANGE) |
902 | return -EINVAL; |
903 | |
904 | if (!rdev->ops->get_tx_power) |
905 | return -EOPNOTSUPP; |
906 | |
907 | err = rdev->ops->get_tx_power(wdev->wiphy, &val); |
908 | if (err) |
909 | return err; |
910 | |
911 | /* well... oh well */ |
912 | data->txpower.fixed = 1; |
913 | data->txpower.disabled = rfkill_blocked(rdev->rfkill); |
914 | data->txpower.value = val; |
915 | data->txpower.flags = IW_TXPOW_DBM; |
916 | |
917 | return 0; |
918 | } |
919 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); |
920 | |
921 | static int cfg80211_set_auth_alg(struct wireless_dev *wdev, |
922 | s32 auth_alg) |
923 | { |
924 | int nr_alg = 0; |
925 | |
926 | if (!auth_alg) |
927 | return -EINVAL; |
928 | |
929 | if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM | |
930 | IW_AUTH_ALG_SHARED_KEY | |
931 | IW_AUTH_ALG_LEAP)) |
932 | return -EINVAL; |
933 | |
934 | if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) { |
935 | nr_alg++; |
936 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; |
937 | } |
938 | |
939 | if (auth_alg & IW_AUTH_ALG_SHARED_KEY) { |
940 | nr_alg++; |
941 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY; |
942 | } |
943 | |
944 | if (auth_alg & IW_AUTH_ALG_LEAP) { |
945 | nr_alg++; |
946 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP; |
947 | } |
948 | |
949 | if (nr_alg > 1) |
950 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
951 | |
952 | return 0; |
953 | } |
954 | |
955 | static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) |
956 | { |
957 | if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | |
958 | IW_AUTH_WPA_VERSION_WPA2| |
959 | IW_AUTH_WPA_VERSION_DISABLED)) |
960 | return -EINVAL; |
961 | |
962 | if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) && |
963 | (wpa_versions & (IW_AUTH_WPA_VERSION_WPA| |
964 | IW_AUTH_WPA_VERSION_WPA2))) |
965 | return -EINVAL; |
966 | |
967 | if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) |
968 | wdev->wext.connect.crypto.wpa_versions &= |
969 | ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2); |
970 | |
971 | if (wpa_versions & IW_AUTH_WPA_VERSION_WPA) |
972 | wdev->wext.connect.crypto.wpa_versions |= |
973 | NL80211_WPA_VERSION_1; |
974 | |
975 | if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2) |
976 | wdev->wext.connect.crypto.wpa_versions |= |
977 | NL80211_WPA_VERSION_2; |
978 | |
979 | return 0; |
980 | } |
981 | |
982 | static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) |
983 | { |
984 | if (cipher & IW_AUTH_CIPHER_WEP40) |
985 | wdev->wext.connect.crypto.cipher_group = |
986 | WLAN_CIPHER_SUITE_WEP40; |
987 | else if (cipher & IW_AUTH_CIPHER_WEP104) |
988 | wdev->wext.connect.crypto.cipher_group = |
989 | WLAN_CIPHER_SUITE_WEP104; |
990 | else if (cipher & IW_AUTH_CIPHER_TKIP) |
991 | wdev->wext.connect.crypto.cipher_group = |
992 | WLAN_CIPHER_SUITE_TKIP; |
993 | else if (cipher & IW_AUTH_CIPHER_CCMP) |
994 | wdev->wext.connect.crypto.cipher_group = |
995 | WLAN_CIPHER_SUITE_CCMP; |
996 | else if (cipher & IW_AUTH_CIPHER_AES_CMAC) |
997 | wdev->wext.connect.crypto.cipher_group = |
998 | WLAN_CIPHER_SUITE_AES_CMAC; |
999 | else if (cipher & IW_AUTH_CIPHER_NONE) |
1000 | wdev->wext.connect.crypto.cipher_group = 0; |
1001 | else |
1002 | return -EINVAL; |
1003 | |
1004 | return 0; |
1005 | } |
1006 | |
1007 | static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) |
1008 | { |
1009 | int nr_ciphers = 0; |
1010 | u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise; |
1011 | |
1012 | if (cipher & IW_AUTH_CIPHER_WEP40) { |
1013 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40; |
1014 | nr_ciphers++; |
1015 | } |
1016 | |
1017 | if (cipher & IW_AUTH_CIPHER_WEP104) { |
1018 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104; |
1019 | nr_ciphers++; |
1020 | } |
1021 | |
1022 | if (cipher & IW_AUTH_CIPHER_TKIP) { |
1023 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP; |
1024 | nr_ciphers++; |
1025 | } |
1026 | |
1027 | if (cipher & IW_AUTH_CIPHER_CCMP) { |
1028 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP; |
1029 | nr_ciphers++; |
1030 | } |
1031 | |
1032 | if (cipher & IW_AUTH_CIPHER_AES_CMAC) { |
1033 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC; |
1034 | nr_ciphers++; |
1035 | } |
1036 | |
1037 | BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5); |
1038 | |
1039 | wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers; |
1040 | |
1041 | return 0; |
1042 | } |
1043 | |
1044 | |
1045 | static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) |
1046 | { |
1047 | int nr_akm_suites = 0; |
1048 | |
1049 | if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X | |
1050 | IW_AUTH_KEY_MGMT_PSK)) |
1051 | return -EINVAL; |
1052 | |
1053 | if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) { |
1054 | wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = |
1055 | WLAN_AKM_SUITE_8021X; |
1056 | nr_akm_suites++; |
1057 | } |
1058 | |
1059 | if (key_mgt & IW_AUTH_KEY_MGMT_PSK) { |
1060 | wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = |
1061 | WLAN_AKM_SUITE_PSK; |
1062 | nr_akm_suites++; |
1063 | } |
1064 | |
1065 | wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites; |
1066 | |
1067 | return 0; |
1068 | } |
1069 | |
1070 | int cfg80211_wext_siwauth(struct net_device *dev, |
1071 | struct iw_request_info *info, |
1072 | struct iw_param *data, char *extra) |
1073 | { |
1074 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1075 | |
1076 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
1077 | return -EOPNOTSUPP; |
1078 | |
1079 | switch (data->flags & IW_AUTH_INDEX) { |
1080 | case IW_AUTH_PRIVACY_INVOKED: |
1081 | wdev->wext.connect.privacy = data->value; |
1082 | return 0; |
1083 | case IW_AUTH_WPA_VERSION: |
1084 | return cfg80211_set_wpa_version(wdev, data->value); |
1085 | case IW_AUTH_CIPHER_GROUP: |
1086 | return cfg80211_set_cipher_group(wdev, data->value); |
1087 | case IW_AUTH_KEY_MGMT: |
1088 | return cfg80211_set_key_mgt(wdev, data->value); |
1089 | case IW_AUTH_CIPHER_PAIRWISE: |
1090 | return cfg80211_set_cipher_pairwise(wdev, data->value); |
1091 | case IW_AUTH_80211_AUTH_ALG: |
1092 | return cfg80211_set_auth_alg(wdev, data->value); |
1093 | case IW_AUTH_WPA_ENABLED: |
1094 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: |
1095 | case IW_AUTH_DROP_UNENCRYPTED: |
1096 | case IW_AUTH_MFP: |
1097 | return 0; |
1098 | default: |
1099 | return -EOPNOTSUPP; |
1100 | } |
1101 | } |
1102 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth); |
1103 | |
1104 | int cfg80211_wext_giwauth(struct net_device *dev, |
1105 | struct iw_request_info *info, |
1106 | struct iw_param *data, char *extra) |
1107 | { |
1108 | /* XXX: what do we need? */ |
1109 | |
1110 | return -EOPNOTSUPP; |
1111 | } |
1112 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth); |
1113 | |
1114 | int cfg80211_wext_siwpower(struct net_device *dev, |
1115 | struct iw_request_info *info, |
1116 | struct iw_param *wrq, char *extra) |
1117 | { |
1118 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1119 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1120 | bool ps = wdev->ps; |
1121 | int timeout = wdev->ps_timeout; |
1122 | int err; |
1123 | |
1124 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
1125 | return -EINVAL; |
1126 | |
1127 | if (!rdev->ops->set_power_mgmt) |
1128 | return -EOPNOTSUPP; |
1129 | |
1130 | if (wrq->disabled) { |
1131 | ps = false; |
1132 | } else { |
1133 | switch (wrq->flags & IW_POWER_MODE) { |
1134 | case IW_POWER_ON: /* If not specified */ |
1135 | case IW_POWER_MODE: /* If set all mask */ |
1136 | case IW_POWER_ALL_R: /* If explicitely state all */ |
1137 | ps = true; |
1138 | break; |
1139 | default: /* Otherwise we ignore */ |
1140 | return -EINVAL; |
1141 | } |
1142 | |
1143 | if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT)) |
1144 | return -EINVAL; |
1145 | |
1146 | if (wrq->flags & IW_POWER_TIMEOUT) |
1147 | timeout = wrq->value / 1000; |
1148 | } |
1149 | |
1150 | err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout); |
1151 | if (err) |
1152 | return err; |
1153 | |
1154 | wdev->ps = ps; |
1155 | wdev->ps_timeout = timeout; |
1156 | |
1157 | return 0; |
1158 | |
1159 | } |
1160 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwpower); |
1161 | |
1162 | int cfg80211_wext_giwpower(struct net_device *dev, |
1163 | struct iw_request_info *info, |
1164 | struct iw_param *wrq, char *extra) |
1165 | { |
1166 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1167 | |
1168 | wrq->disabled = !wdev->ps; |
1169 | |
1170 | return 0; |
1171 | } |
1172 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower); |
1173 | |
1174 | static int cfg80211_wds_wext_siwap(struct net_device *dev, |
1175 | struct iw_request_info *info, |
1176 | struct sockaddr *addr, char *extra) |
1177 | { |
1178 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1179 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1180 | int err; |
1181 | |
1182 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) |
1183 | return -EINVAL; |
1184 | |
1185 | if (addr->sa_family != ARPHRD_ETHER) |
1186 | return -EINVAL; |
1187 | |
1188 | if (netif_running(dev)) |
1189 | return -EBUSY; |
1190 | |
1191 | if (!rdev->ops->set_wds_peer) |
1192 | return -EOPNOTSUPP; |
1193 | |
1194 | err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data); |
1195 | if (err) |
1196 | return err; |
1197 | |
1198 | memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN); |
1199 | |
1200 | return 0; |
1201 | } |
1202 | |
1203 | static int cfg80211_wds_wext_giwap(struct net_device *dev, |
1204 | struct iw_request_info *info, |
1205 | struct sockaddr *addr, char *extra) |
1206 | { |
1207 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1208 | |
1209 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) |
1210 | return -EINVAL; |
1211 | |
1212 | addr->sa_family = ARPHRD_ETHER; |
1213 | memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN); |
1214 | |
1215 | return 0; |
1216 | } |
1217 | |
1218 | int cfg80211_wext_siwrate(struct net_device *dev, |
1219 | struct iw_request_info *info, |
1220 | struct iw_param *rate, char *extra) |
1221 | { |
1222 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1223 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1224 | struct cfg80211_bitrate_mask mask; |
1225 | u32 fixed, maxrate; |
1226 | struct ieee80211_supported_band *sband; |
1227 | int band, ridx; |
1228 | bool match = false; |
1229 | |
1230 | if (!rdev->ops->set_bitrate_mask) |
1231 | return -EOPNOTSUPP; |
1232 | |
1233 | memset(&mask, 0, sizeof(mask)); |
1234 | fixed = 0; |
1235 | maxrate = (u32)-1; |
1236 | |
1237 | if (rate->value < 0) { |
1238 | /* nothing */ |
1239 | } else if (rate->fixed) { |
1240 | fixed = rate->value / 100000; |
1241 | } else { |
1242 | maxrate = rate->value / 100000; |
1243 | } |
1244 | |
1245 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1246 | sband = wdev->wiphy->bands[band]; |
1247 | if (sband == NULL) |
1248 | continue; |
1249 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { |
1250 | struct ieee80211_rate *srate = &sband->bitrates[ridx]; |
1251 | if (fixed == srate->bitrate) { |
1252 | mask.control[band].legacy = 1 << ridx; |
1253 | match = true; |
1254 | break; |
1255 | } |
1256 | if (srate->bitrate <= maxrate) { |
1257 | mask.control[band].legacy |= 1 << ridx; |
1258 | match = true; |
1259 | } |
1260 | } |
1261 | } |
1262 | |
1263 | if (!match) |
1264 | return -EINVAL; |
1265 | |
1266 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); |
1267 | } |
1268 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); |
1269 | |
1270 | int cfg80211_wext_giwrate(struct net_device *dev, |
1271 | struct iw_request_info *info, |
1272 | struct iw_param *rate, char *extra) |
1273 | { |
1274 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1275 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1276 | /* we are under RTNL - globally locked - so can use a static struct */ |
1277 | static struct station_info sinfo; |
1278 | u8 addr[ETH_ALEN]; |
1279 | int err; |
1280 | |
1281 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
1282 | return -EOPNOTSUPP; |
1283 | |
1284 | if (!rdev->ops->get_station) |
1285 | return -EOPNOTSUPP; |
1286 | |
1287 | err = 0; |
1288 | wdev_lock(wdev); |
1289 | if (wdev->current_bss) |
1290 | memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN); |
1291 | else |
1292 | err = -EOPNOTSUPP; |
1293 | wdev_unlock(wdev); |
1294 | if (err) |
1295 | return err; |
1296 | |
1297 | err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); |
1298 | if (err) |
1299 | return err; |
1300 | |
1301 | if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) |
1302 | return -EOPNOTSUPP; |
1303 | |
1304 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); |
1305 | |
1306 | return 0; |
1307 | } |
1308 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate); |
1309 | |
1310 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ |
1311 | struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) |
1312 | { |
1313 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1314 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1315 | /* we are under RTNL - globally locked - so can use static structs */ |
1316 | static struct iw_statistics wstats; |
1317 | static struct station_info sinfo; |
1318 | u8 bssid[ETH_ALEN]; |
1319 | |
1320 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) |
1321 | return NULL; |
1322 | |
1323 | if (!rdev->ops->get_station) |
1324 | return NULL; |
1325 | |
1326 | /* Grab BSSID of current BSS, if any */ |
1327 | wdev_lock(wdev); |
1328 | if (!wdev->current_bss) { |
1329 | wdev_unlock(wdev); |
1330 | return NULL; |
1331 | } |
1332 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); |
1333 | wdev_unlock(wdev); |
1334 | |
1335 | if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo)) |
1336 | return NULL; |
1337 | |
1338 | memset(&wstats, 0, sizeof(wstats)); |
1339 | |
1340 | switch (rdev->wiphy.signal_type) { |
1341 | case CFG80211_SIGNAL_TYPE_MBM: |
1342 | if (sinfo.filled & STATION_INFO_SIGNAL) { |
1343 | int sig = sinfo.signal; |
1344 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
1345 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
1346 | wstats.qual.updated |= IW_QUAL_DBM; |
1347 | wstats.qual.level = sig; |
1348 | if (sig < -110) |
1349 | sig = -110; |
1350 | else if (sig > -40) |
1351 | sig = -40; |
1352 | wstats.qual.qual = sig + 110; |
1353 | break; |
1354 | } |
1355 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
1356 | if (sinfo.filled & STATION_INFO_SIGNAL) { |
1357 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
1358 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
1359 | wstats.qual.level = sinfo.signal; |
1360 | wstats.qual.qual = sinfo.signal; |
1361 | break; |
1362 | } |
1363 | default: |
1364 | wstats.qual.updated |= IW_QUAL_LEVEL_INVALID; |
1365 | wstats.qual.updated |= IW_QUAL_QUAL_INVALID; |
1366 | } |
1367 | |
1368 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; |
1369 | if (sinfo.filled & STATION_INFO_RX_DROP_MISC) |
1370 | wstats.discard.misc = sinfo.rx_dropped_misc; |
1371 | if (sinfo.filled & STATION_INFO_TX_FAILED) |
1372 | wstats.discard.retries = sinfo.tx_failed; |
1373 | |
1374 | return &wstats; |
1375 | } |
1376 | EXPORT_SYMBOL_GPL(cfg80211_wireless_stats); |
1377 | |
1378 | int cfg80211_wext_siwap(struct net_device *dev, |
1379 | struct iw_request_info *info, |
1380 | struct sockaddr *ap_addr, char *extra) |
1381 | { |
1382 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1383 | |
1384 | switch (wdev->iftype) { |
1385 | case NL80211_IFTYPE_ADHOC: |
1386 | return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); |
1387 | case NL80211_IFTYPE_STATION: |
1388 | return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); |
1389 | case NL80211_IFTYPE_WDS: |
1390 | return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); |
1391 | default: |
1392 | return -EOPNOTSUPP; |
1393 | } |
1394 | } |
1395 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwap); |
1396 | |
1397 | int cfg80211_wext_giwap(struct net_device *dev, |
1398 | struct iw_request_info *info, |
1399 | struct sockaddr *ap_addr, char *extra) |
1400 | { |
1401 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1402 | |
1403 | switch (wdev->iftype) { |
1404 | case NL80211_IFTYPE_ADHOC: |
1405 | return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); |
1406 | case NL80211_IFTYPE_STATION: |
1407 | return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); |
1408 | case NL80211_IFTYPE_WDS: |
1409 | return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); |
1410 | default: |
1411 | return -EOPNOTSUPP; |
1412 | } |
1413 | } |
1414 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwap); |
1415 | |
1416 | int cfg80211_wext_siwessid(struct net_device *dev, |
1417 | struct iw_request_info *info, |
1418 | struct iw_point *data, char *ssid) |
1419 | { |
1420 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1421 | |
1422 | switch (wdev->iftype) { |
1423 | case NL80211_IFTYPE_ADHOC: |
1424 | return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); |
1425 | case NL80211_IFTYPE_STATION: |
1426 | return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); |
1427 | default: |
1428 | return -EOPNOTSUPP; |
1429 | } |
1430 | } |
1431 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid); |
1432 | |
1433 | int cfg80211_wext_giwessid(struct net_device *dev, |
1434 | struct iw_request_info *info, |
1435 | struct iw_point *data, char *ssid) |
1436 | { |
1437 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1438 | |
1439 | data->flags = 0; |
1440 | data->length = 0; |
1441 | |
1442 | switch (wdev->iftype) { |
1443 | case NL80211_IFTYPE_ADHOC: |
1444 | return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); |
1445 | case NL80211_IFTYPE_STATION: |
1446 | return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); |
1447 | default: |
1448 | return -EOPNOTSUPP; |
1449 | } |
1450 | } |
1451 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); |
1452 | |
1453 | int cfg80211_wext_siwpmksa(struct net_device *dev, |
1454 | struct iw_request_info *info, |
1455 | struct iw_point *data, char *extra) |
1456 | { |
1457 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1458 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1459 | struct cfg80211_pmksa cfg_pmksa; |
1460 | struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; |
1461 | |
1462 | memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa)); |
1463 | |
1464 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
1465 | return -EINVAL; |
1466 | |
1467 | cfg_pmksa.bssid = pmksa->bssid.sa_data; |
1468 | cfg_pmksa.pmkid = pmksa->pmkid; |
1469 | |
1470 | switch (pmksa->cmd) { |
1471 | case IW_PMKSA_ADD: |
1472 | if (!rdev->ops->set_pmksa) |
1473 | return -EOPNOTSUPP; |
1474 | |
1475 | return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa); |
1476 | |
1477 | case IW_PMKSA_REMOVE: |
1478 | if (!rdev->ops->del_pmksa) |
1479 | return -EOPNOTSUPP; |
1480 | |
1481 | return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa); |
1482 | |
1483 | case IW_PMKSA_FLUSH: |
1484 | if (!rdev->ops->flush_pmksa) |
1485 | return -EOPNOTSUPP; |
1486 | |
1487 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); |
1488 | |
1489 | default: |
1490 | return -EOPNOTSUPP; |
1491 | } |
1492 | } |
1493 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwpmksa); |
1494 | |
1495 | static const iw_handler cfg80211_handlers[] = { |
1496 | [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, |
1497 | [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, |
1498 | [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, |
1499 | [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, |
1500 | [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, |
1501 | [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, |
1502 | [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, |
1503 | [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, |
1504 | [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, |
1505 | [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, |
1506 | [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, |
1507 | [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, |
1508 | [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, |
1509 | [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, |
1510 | [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, |
1511 | [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, |
1512 | [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, |
1513 | [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, |
1514 | [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, |
1515 | [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, |
1516 | [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, |
1517 | [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, |
1518 | [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, |
1519 | [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, |
1520 | [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, |
1521 | [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, |
1522 | [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, |
1523 | [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, |
1524 | [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, |
1525 | [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, |
1526 | [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, |
1527 | [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa, |
1528 | }; |
1529 | |
1530 | const struct iw_handler_def cfg80211_wext_handler = { |
1531 | .num_standard = ARRAY_SIZE(cfg80211_handlers), |
1532 | .standard = cfg80211_handlers, |
1533 | .get_wireless_stats = cfg80211_wireless_stats, |
1534 | }; |
1535 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9