diff options
Diffstat (limited to 'net/mac80211/wext.c')
-rw-r--r-- | net/mac80211/wext.c | 637 |
1 files changed, 52 insertions, 585 deletions
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 959aa8379ccf..d2d81b103341 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -27,100 +27,6 @@ | |||
27 | #include "aes_ccm.h" | 27 | #include "aes_ccm.h" |
28 | 28 | ||
29 | 29 | ||
30 | static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta_addr, | ||
31 | int idx, int alg, int remove, | ||
32 | int set_tx_key, const u8 *_key, | ||
33 | size_t key_len) | ||
34 | { | ||
35 | struct ieee80211_local *local = sdata->local; | ||
36 | struct sta_info *sta; | ||
37 | struct ieee80211_key *key; | ||
38 | int err; | ||
39 | |||
40 | if (alg == ALG_AES_CMAC) { | ||
41 | if (idx < NUM_DEFAULT_KEYS || | ||
42 | idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { | ||
43 | printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d " | ||
44 | "(BIP)\n", sdata->dev->name, idx); | ||
45 | return -EINVAL; | ||
46 | } | ||
47 | } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { | ||
48 | printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", | ||
49 | sdata->dev->name, idx); | ||
50 | return -EINVAL; | ||
51 | } | ||
52 | |||
53 | if (remove) { | ||
54 | rcu_read_lock(); | ||
55 | |||
56 | err = 0; | ||
57 | |||
58 | if (is_broadcast_ether_addr(sta_addr)) { | ||
59 | key = sdata->keys[idx]; | ||
60 | } else { | ||
61 | sta = sta_info_get(local, sta_addr); | ||
62 | if (!sta) { | ||
63 | err = -ENOENT; | ||
64 | goto out_unlock; | ||
65 | } | ||
66 | key = sta->key; | ||
67 | } | ||
68 | |||
69 | ieee80211_key_free(key); | ||
70 | } else { | ||
71 | key = ieee80211_key_alloc(alg, idx, key_len, _key); | ||
72 | if (!key) | ||
73 | return -ENOMEM; | ||
74 | |||
75 | sta = NULL; | ||
76 | err = 0; | ||
77 | |||
78 | rcu_read_lock(); | ||
79 | |||
80 | if (!is_broadcast_ether_addr(sta_addr)) { | ||
81 | set_tx_key = 0; | ||
82 | /* | ||
83 | * According to the standard, the key index of a | ||
84 | * pairwise key must be zero. However, some AP are | ||
85 | * broken when it comes to WEP key indices, so we | ||
86 | * work around this. | ||
87 | */ | ||
88 | if (idx != 0 && alg != ALG_WEP) { | ||
89 | ieee80211_key_free(key); | ||
90 | err = -EINVAL; | ||
91 | goto out_unlock; | ||
92 | } | ||
93 | |||
94 | sta = sta_info_get(local, sta_addr); | ||
95 | if (!sta) { | ||
96 | ieee80211_key_free(key); | ||
97 | err = -ENOENT; | ||
98 | goto out_unlock; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | if (alg == ALG_WEP && | ||
103 | key_len != LEN_WEP40 && key_len != LEN_WEP104) { | ||
104 | ieee80211_key_free(key); | ||
105 | err = -EINVAL; | ||
106 | goto out_unlock; | ||
107 | } | ||
108 | |||
109 | ieee80211_key_link(key, sdata, sta); | ||
110 | |||
111 | if (set_tx_key || (!sta && !sdata->default_key && key)) | ||
112 | ieee80211_set_default_key(sdata, idx); | ||
113 | if (alg == ALG_AES_CMAC && | ||
114 | (set_tx_key || (!sta && !sdata->default_mgmt_key && key))) | ||
115 | ieee80211_set_default_mgmt_key(sdata, idx); | ||
116 | } | ||
117 | |||
118 | out_unlock: | ||
119 | rcu_read_unlock(); | ||
120 | |||
121 | return err; | ||
122 | } | ||
123 | |||
124 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, | 30 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, |
125 | struct iw_request_info *info, | 31 | struct iw_request_info *info, |
126 | struct iw_point *data, char *extra) | 32 | struct iw_point *data, char *extra) |
@@ -131,11 +37,13 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, | |||
131 | 37 | ||
132 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 38 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
133 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); | 39 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); |
134 | if (ret) | 40 | if (ret && ret != -EALREADY) |
135 | return ret; | 41 | return ret; |
136 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 42 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; |
137 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; | 43 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; |
138 | ieee80211_sta_req_auth(sdata); | 44 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; |
45 | if (ret != -EALREADY) | ||
46 | ieee80211_sta_req_auth(sdata); | ||
139 | return 0; | 47 | return 0; |
140 | } | 48 | } |
141 | 49 | ||
@@ -149,17 +57,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, | |||
149 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 57 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
150 | 58 | ||
151 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 59 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
152 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL; | 60 | return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); |
153 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | 61 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
154 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; | 62 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; |
155 | 63 | ||
156 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ | 64 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ |
157 | if (freq->e == 0) { | 65 | if (freq->e == 0) { |
158 | if (freq->m < 0) { | 66 | if (freq->m < 0) { |
159 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 67 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
160 | sdata->u.ibss.flags |= | ||
161 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; | ||
162 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
163 | sdata->u.mgd.flags |= | 68 | sdata->u.mgd.flags |= |
164 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 69 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
165 | return 0; | 70 | return 0; |
@@ -183,8 +88,12 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, | |||
183 | struct iw_freq *freq, char *extra) | 88 | struct iw_freq *freq, char *extra) |
184 | { | 89 | { |
185 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 90 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
91 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
186 | 92 | ||
187 | freq->m = local->hw.conf.channel->center_freq; | 93 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
94 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); | ||
95 | |||
96 | freq->m = local->oper_channel->center_freq; | ||
188 | freq->e = 6; | 97 | freq->e = 6; |
189 | 98 | ||
190 | return 0; | 99 | return 0; |
@@ -195,15 +104,17 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, | |||
195 | struct iw_request_info *info, | 104 | struct iw_request_info *info, |
196 | struct iw_point *data, char *ssid) | 105 | struct iw_point *data, char *ssid) |
197 | { | 106 | { |
198 | struct ieee80211_sub_if_data *sdata; | 107 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
199 | size_t len = data->length; | 108 | size_t len = data->length; |
200 | int ret; | 109 | int ret; |
201 | 110 | ||
111 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
112 | return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); | ||
113 | |||
202 | /* iwconfig uses nul termination in SSID.. */ | 114 | /* iwconfig uses nul termination in SSID.. */ |
203 | if (len > 0 && ssid[len - 1] == '\0') | 115 | if (len > 0 && ssid[len - 1] == '\0') |
204 | len--; | 116 | len--; |
205 | 117 | ||
206 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
207 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 118 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
208 | if (data->flags) | 119 | if (data->flags) |
209 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | 120 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; |
@@ -215,10 +126,10 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, | |||
215 | return ret; | 126 | return ret; |
216 | 127 | ||
217 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; | 128 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; |
129 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; | ||
218 | ieee80211_sta_req_auth(sdata); | 130 | ieee80211_sta_req_auth(sdata); |
219 | return 0; | 131 | return 0; |
220 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 132 | } |
221 | return ieee80211_ibss_set_ssid(sdata, ssid, len); | ||
222 | 133 | ||
223 | return -EOPNOTSUPP; | 134 | return -EOPNOTSUPP; |
224 | } | 135 | } |
@@ -229,9 +140,13 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, | |||
229 | struct iw_point *data, char *ssid) | 140 | struct iw_point *data, char *ssid) |
230 | { | 141 | { |
231 | size_t len; | 142 | size_t len; |
232 | |||
233 | struct ieee80211_sub_if_data *sdata; | 143 | struct ieee80211_sub_if_data *sdata; |
144 | |||
234 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 145 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
146 | |||
147 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
148 | return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); | ||
149 | |||
235 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 150 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
236 | int res = ieee80211_sta_get_ssid(sdata, ssid, &len); | 151 | int res = ieee80211_sta_get_ssid(sdata, ssid, &len); |
237 | if (res == 0) { | 152 | if (res == 0) { |
@@ -240,14 +155,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, | |||
240 | } else | 155 | } else |
241 | data->flags = 0; | 156 | data->flags = 0; |
242 | return res; | 157 | return res; |
243 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
244 | int res = ieee80211_ibss_get_ssid(sdata, ssid, &len); | ||
245 | if (res == 0) { | ||
246 | data->length = len; | ||
247 | data->flags = 1; | ||
248 | } else | ||
249 | data->flags = 0; | ||
250 | return res; | ||
251 | } | 158 | } |
252 | 159 | ||
253 | return -EOPNOTSUPP; | 160 | return -EOPNOTSUPP; |
@@ -258,9 +165,11 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, | |||
258 | struct iw_request_info *info, | 165 | struct iw_request_info *info, |
259 | struct sockaddr *ap_addr, char *extra) | 166 | struct sockaddr *ap_addr, char *extra) |
260 | { | 167 | { |
261 | struct ieee80211_sub_if_data *sdata; | 168 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
169 | |||
170 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
171 | return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); | ||
262 | 172 | ||
263 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
264 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 173 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
265 | int ret; | 174 | int ret; |
266 | 175 | ||
@@ -275,18 +184,9 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, | |||
275 | if (ret) | 184 | if (ret) |
276 | return ret; | 185 | return ret; |
277 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; | 186 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; |
187 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; | ||
278 | ieee80211_sta_req_auth(sdata); | 188 | ieee80211_sta_req_auth(sdata); |
279 | return 0; | 189 | return 0; |
280 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
281 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) | ||
282 | sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | | ||
283 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; | ||
284 | else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) | ||
285 | sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL; | ||
286 | else | ||
287 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL; | ||
288 | |||
289 | return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data); | ||
290 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 190 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
291 | /* | 191 | /* |
292 | * If it is necessary to update the WDS peer address | 192 | * If it is necessary to update the WDS peer address |
@@ -312,9 +212,11 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, | |||
312 | struct iw_request_info *info, | 212 | struct iw_request_info *info, |
313 | struct sockaddr *ap_addr, char *extra) | 213 | struct sockaddr *ap_addr, char *extra) |
314 | { | 214 | { |
315 | struct ieee80211_sub_if_data *sdata; | 215 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
216 | |||
217 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
218 | return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); | ||
316 | 219 | ||
317 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
318 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 220 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
319 | if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { | 221 | if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { |
320 | ap_addr->sa_family = ARPHRD_ETHER; | 222 | ap_addr->sa_family = ARPHRD_ETHER; |
@@ -322,13 +224,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, | |||
322 | } else | 224 | } else |
323 | memset(&ap_addr->sa_data, 0, ETH_ALEN); | 225 | memset(&ap_addr->sa_data, 0, ETH_ALEN); |
324 | return 0; | 226 | return 0; |
325 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
326 | if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) { | ||
327 | ap_addr->sa_family = ARPHRD_ETHER; | ||
328 | memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN); | ||
329 | } else | ||
330 | memset(&ap_addr->sa_data, 0, ETH_ALEN); | ||
331 | return 0; | ||
332 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 227 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
333 | ap_addr->sa_family = ARPHRD_ETHER; | 228 | ap_addr->sa_family = ARPHRD_ETHER; |
334 | memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); | 229 | memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); |
@@ -411,334 +306,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, | |||
411 | return 0; | 306 | return 0; |
412 | } | 307 | } |
413 | 308 | ||
414 | static int ieee80211_ioctl_siwtxpower(struct net_device *dev, | ||
415 | struct iw_request_info *info, | ||
416 | union iwreq_data *data, char *extra) | ||
417 | { | ||
418 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
419 | struct ieee80211_channel* chan = local->hw.conf.channel; | ||
420 | bool reconf = false; | ||
421 | u32 reconf_flags = 0; | ||
422 | int new_power_level; | ||
423 | |||
424 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | ||
425 | return -EINVAL; | ||
426 | if (data->txpower.flags & IW_TXPOW_RANGE) | ||
427 | return -EINVAL; | ||
428 | if (!chan) | ||
429 | return -EINVAL; | ||
430 | |||
431 | /* only change when not disabling */ | ||
432 | if (!data->txpower.disabled) { | ||
433 | if (data->txpower.fixed) { | ||
434 | if (data->txpower.value < 0) | ||
435 | return -EINVAL; | ||
436 | new_power_level = data->txpower.value; | ||
437 | /* | ||
438 | * Debatable, but we cannot do a fixed power | ||
439 | * level above the regulatory constraint. | ||
440 | * Use "iwconfig wlan0 txpower 15dBm" instead. | ||
441 | */ | ||
442 | if (new_power_level > chan->max_power) | ||
443 | return -EINVAL; | ||
444 | } else { | ||
445 | /* | ||
446 | * Automatic power level setting, max being the value | ||
447 | * passed in from userland. | ||
448 | */ | ||
449 | if (data->txpower.value < 0) | ||
450 | new_power_level = -1; | ||
451 | else | ||
452 | new_power_level = data->txpower.value; | ||
453 | } | ||
454 | |||
455 | reconf = true; | ||
456 | |||
457 | /* | ||
458 | * ieee80211_hw_config() will limit to the channel's | ||
459 | * max power and possibly power constraint from AP. | ||
460 | */ | ||
461 | local->user_power_level = new_power_level; | ||
462 | } | ||
463 | |||
464 | if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { | ||
465 | local->hw.conf.radio_enabled = !(data->txpower.disabled); | ||
466 | reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; | ||
467 | ieee80211_led_radio(local, local->hw.conf.radio_enabled); | ||
468 | } | ||
469 | |||
470 | if (reconf || reconf_flags) | ||
471 | ieee80211_hw_config(local, reconf_flags); | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int ieee80211_ioctl_giwtxpower(struct net_device *dev, | ||
477 | struct iw_request_info *info, | ||
478 | union iwreq_data *data, char *extra) | ||
479 | { | ||
480 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
481 | |||
482 | data->txpower.fixed = 1; | ||
483 | data->txpower.disabled = !(local->hw.conf.radio_enabled); | ||
484 | data->txpower.value = local->hw.conf.power_level; | ||
485 | data->txpower.flags = IW_TXPOW_DBM; | ||
486 | |||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static int ieee80211_ioctl_siwrts(struct net_device *dev, | ||
491 | struct iw_request_info *info, | ||
492 | struct iw_param *rts, char *extra) | ||
493 | { | ||
494 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
495 | |||
496 | if (rts->disabled) | ||
497 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | ||
498 | else if (!rts->fixed) | ||
499 | /* if the rts value is not fixed, then take default */ | ||
500 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | ||
501 | else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) | ||
502 | return -EINVAL; | ||
503 | else | ||
504 | local->rts_threshold = rts->value; | ||
505 | |||
506 | /* If the wlan card performs RTS/CTS in hardware/firmware, | ||
507 | * configure it here */ | ||
508 | |||
509 | if (local->ops->set_rts_threshold) | ||
510 | local->ops->set_rts_threshold(local_to_hw(local), | ||
511 | local->rts_threshold); | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int ieee80211_ioctl_giwrts(struct net_device *dev, | ||
517 | struct iw_request_info *info, | ||
518 | struct iw_param *rts, char *extra) | ||
519 | { | ||
520 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
521 | |||
522 | rts->value = local->rts_threshold; | ||
523 | rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD); | ||
524 | rts->fixed = 1; | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | |||
530 | static int ieee80211_ioctl_siwfrag(struct net_device *dev, | ||
531 | struct iw_request_info *info, | ||
532 | struct iw_param *frag, char *extra) | ||
533 | { | ||
534 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
535 | |||
536 | if (frag->disabled) | ||
537 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | ||
538 | else if (!frag->fixed) | ||
539 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | ||
540 | else if (frag->value < 256 || | ||
541 | frag->value > IEEE80211_MAX_FRAG_THRESHOLD) | ||
542 | return -EINVAL; | ||
543 | else { | ||
544 | /* Fragment length must be even, so strip LSB. */ | ||
545 | local->fragmentation_threshold = frag->value & ~0x1; | ||
546 | } | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int ieee80211_ioctl_giwfrag(struct net_device *dev, | ||
552 | struct iw_request_info *info, | ||
553 | struct iw_param *frag, char *extra) | ||
554 | { | ||
555 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
556 | |||
557 | frag->value = local->fragmentation_threshold; | ||
558 | frag->disabled = (frag->value >= IEEE80211_MAX_FRAG_THRESHOLD); | ||
559 | frag->fixed = 1; | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | |||
565 | static int ieee80211_ioctl_siwretry(struct net_device *dev, | ||
566 | struct iw_request_info *info, | ||
567 | struct iw_param *retry, char *extra) | ||
568 | { | ||
569 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
570 | |||
571 | if (retry->disabled || | ||
572 | (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) | ||
573 | return -EINVAL; | ||
574 | |||
575 | if (retry->flags & IW_RETRY_MAX) { | ||
576 | local->hw.conf.long_frame_max_tx_count = retry->value; | ||
577 | } else if (retry->flags & IW_RETRY_MIN) { | ||
578 | local->hw.conf.short_frame_max_tx_count = retry->value; | ||
579 | } else { | ||
580 | local->hw.conf.long_frame_max_tx_count = retry->value; | ||
581 | local->hw.conf.short_frame_max_tx_count = retry->value; | ||
582 | } | ||
583 | |||
584 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | |||
590 | static int ieee80211_ioctl_giwretry(struct net_device *dev, | ||
591 | struct iw_request_info *info, | ||
592 | struct iw_param *retry, char *extra) | ||
593 | { | ||
594 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
595 | |||
596 | retry->disabled = 0; | ||
597 | if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) { | ||
598 | /* first return min value, iwconfig will ask max value | ||
599 | * later if needed */ | ||
600 | retry->flags |= IW_RETRY_LIMIT; | ||
601 | retry->value = local->hw.conf.short_frame_max_tx_count; | ||
602 | if (local->hw.conf.long_frame_max_tx_count != | ||
603 | local->hw.conf.short_frame_max_tx_count) | ||
604 | retry->flags |= IW_RETRY_MIN; | ||
605 | return 0; | ||
606 | } | ||
607 | if (retry->flags & IW_RETRY_MAX) { | ||
608 | retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
609 | retry->value = local->hw.conf.long_frame_max_tx_count; | ||
610 | } | ||
611 | |||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | static int ieee80211_ioctl_siwmlme(struct net_device *dev, | ||
616 | struct iw_request_info *info, | ||
617 | struct iw_point *data, char *extra) | ||
618 | { | ||
619 | struct ieee80211_sub_if_data *sdata; | ||
620 | struct iw_mlme *mlme = (struct iw_mlme *) extra; | ||
621 | |||
622 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
623 | if (!(sdata->vif.type == NL80211_IFTYPE_STATION)) | ||
624 | return -EINVAL; | ||
625 | |||
626 | switch (mlme->cmd) { | ||
627 | case IW_MLME_DEAUTH: | ||
628 | /* TODO: mlme->addr.sa_data */ | ||
629 | return ieee80211_sta_deauthenticate(sdata, mlme->reason_code); | ||
630 | case IW_MLME_DISASSOC: | ||
631 | /* TODO: mlme->addr.sa_data */ | ||
632 | return ieee80211_sta_disassociate(sdata, mlme->reason_code); | ||
633 | default: | ||
634 | return -EOPNOTSUPP; | ||
635 | } | ||
636 | } | ||
637 | |||
638 | |||
639 | static int ieee80211_ioctl_siwencode(struct net_device *dev, | ||
640 | struct iw_request_info *info, | ||
641 | struct iw_point *erq, char *keybuf) | ||
642 | { | ||
643 | struct ieee80211_sub_if_data *sdata; | ||
644 | int idx, i, alg = ALG_WEP; | ||
645 | u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
646 | int remove = 0, ret; | ||
647 | |||
648 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
649 | |||
650 | idx = erq->flags & IW_ENCODE_INDEX; | ||
651 | if (idx == 0) { | ||
652 | if (sdata->default_key) | ||
653 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
654 | if (sdata->default_key == sdata->keys[i]) { | ||
655 | idx = i; | ||
656 | break; | ||
657 | } | ||
658 | } | ||
659 | } else if (idx < 1 || idx > 4) | ||
660 | return -EINVAL; | ||
661 | else | ||
662 | idx--; | ||
663 | |||
664 | if (erq->flags & IW_ENCODE_DISABLED) | ||
665 | remove = 1; | ||
666 | else if (erq->length == 0) { | ||
667 | /* No key data - just set the default TX key index */ | ||
668 | ieee80211_set_default_key(sdata, idx); | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | ret = ieee80211_set_encryption( | ||
673 | sdata, bcaddr, | ||
674 | idx, alg, remove, | ||
675 | !sdata->default_key, | ||
676 | keybuf, erq->length); | ||
677 | |||
678 | if (!ret) { | ||
679 | if (remove) | ||
680 | sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; | ||
681 | else | ||
682 | sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; | ||
683 | } | ||
684 | |||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | |||
689 | static int ieee80211_ioctl_giwencode(struct net_device *dev, | ||
690 | struct iw_request_info *info, | ||
691 | struct iw_point *erq, char *key) | ||
692 | { | ||
693 | struct ieee80211_sub_if_data *sdata; | ||
694 | int idx, i; | ||
695 | |||
696 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
697 | |||
698 | idx = erq->flags & IW_ENCODE_INDEX; | ||
699 | if (idx < 1 || idx > 4) { | ||
700 | idx = -1; | ||
701 | if (!sdata->default_key) | ||
702 | idx = 0; | ||
703 | else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
704 | if (sdata->default_key == sdata->keys[i]) { | ||
705 | idx = i; | ||
706 | break; | ||
707 | } | ||
708 | } | ||
709 | if (idx < 0) | ||
710 | return -EINVAL; | ||
711 | } else | ||
712 | idx--; | ||
713 | |||
714 | erq->flags = idx + 1; | ||
715 | |||
716 | if (!sdata->keys[idx]) { | ||
717 | erq->length = 0; | ||
718 | erq->flags |= IW_ENCODE_DISABLED; | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | memcpy(key, sdata->keys[idx]->conf.key, | ||
723 | min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); | ||
724 | erq->length = sdata->keys[idx]->conf.keylen; | ||
725 | erq->flags |= IW_ENCODE_ENABLED; | ||
726 | |||
727 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
728 | switch (sdata->u.mgd.auth_alg) { | ||
729 | case WLAN_AUTH_OPEN: | ||
730 | case WLAN_AUTH_LEAP: | ||
731 | erq->flags |= IW_ENCODE_OPEN; | ||
732 | break; | ||
733 | case WLAN_AUTH_SHARED_KEY: | ||
734 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static int ieee80211_ioctl_siwpower(struct net_device *dev, | 309 | static int ieee80211_ioctl_siwpower(struct net_device *dev, |
743 | struct iw_request_info *info, | 310 | struct iw_request_info *info, |
744 | struct iw_param *wrq, | 311 | struct iw_param *wrq, |
@@ -747,7 +314,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
747 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 314 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
748 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 315 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
749 | struct ieee80211_conf *conf = &local->hw.conf; | 316 | struct ieee80211_conf *conf = &local->hw.conf; |
750 | int ret = 0, timeout = 0; | 317 | int timeout = 0; |
751 | bool ps; | 318 | bool ps; |
752 | 319 | ||
753 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | 320 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) |
@@ -779,42 +346,18 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
779 | timeout = wrq->value / 1000; | 346 | timeout = wrq->value / 1000; |
780 | 347 | ||
781 | set: | 348 | set: |
782 | if (ps == local->powersave && timeout == conf->dynamic_ps_timeout) | 349 | if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout) |
783 | return ret; | 350 | return 0; |
784 | 351 | ||
785 | local->powersave = ps; | 352 | sdata->u.mgd.powersave = ps; |
786 | conf->dynamic_ps_timeout = timeout; | 353 | conf->dynamic_ps_timeout = timeout; |
787 | 354 | ||
788 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 355 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
789 | ret = ieee80211_hw_config(local, | 356 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
790 | IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); | ||
791 | |||
792 | if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) | ||
793 | return ret; | ||
794 | 357 | ||
795 | if (conf->dynamic_ps_timeout > 0 && | 358 | ieee80211_recalc_ps(local, -1); |
796 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { | ||
797 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
798 | msecs_to_jiffies(conf->dynamic_ps_timeout)); | ||
799 | } else { | ||
800 | if (local->powersave) { | ||
801 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
802 | ieee80211_send_nullfunc(local, sdata, 1); | ||
803 | conf->flags |= IEEE80211_CONF_PS; | ||
804 | ret = ieee80211_hw_config(local, | ||
805 | IEEE80211_CONF_CHANGE_PS); | ||
806 | } else { | ||
807 | conf->flags &= ~IEEE80211_CONF_PS; | ||
808 | ret = ieee80211_hw_config(local, | ||
809 | IEEE80211_CONF_CHANGE_PS); | ||
810 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
811 | ieee80211_send_nullfunc(local, sdata, 0); | ||
812 | del_timer_sync(&local->dynamic_ps_timer); | ||
813 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
814 | } | ||
815 | } | ||
816 | 359 | ||
817 | return ret; | 360 | return 0; |
818 | } | 361 | } |
819 | 362 | ||
820 | static int ieee80211_ioctl_giwpower(struct net_device *dev, | 363 | static int ieee80211_ioctl_giwpower(struct net_device *dev, |
@@ -822,9 +365,9 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev, | |||
822 | union iwreq_data *wrqu, | 365 | union iwreq_data *wrqu, |
823 | char *extra) | 366 | char *extra) |
824 | { | 367 | { |
825 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 368 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
826 | 369 | ||
827 | wrqu->power.disabled = !local->powersave; | 370 | wrqu->power.disabled = !sdata->u.mgd.powersave; |
828 | 371 | ||
829 | return 0; | 372 | return 0; |
830 | } | 373 | } |
@@ -997,82 +540,6 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev, | |||
997 | } | 540 | } |
998 | 541 | ||
999 | 542 | ||
1000 | static int ieee80211_ioctl_siwencodeext(struct net_device *dev, | ||
1001 | struct iw_request_info *info, | ||
1002 | struct iw_point *erq, char *extra) | ||
1003 | { | ||
1004 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1005 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
1006 | int uninitialized_var(alg), idx, i, remove = 0; | ||
1007 | |||
1008 | switch (ext->alg) { | ||
1009 | case IW_ENCODE_ALG_NONE: | ||
1010 | remove = 1; | ||
1011 | break; | ||
1012 | case IW_ENCODE_ALG_WEP: | ||
1013 | alg = ALG_WEP; | ||
1014 | break; | ||
1015 | case IW_ENCODE_ALG_TKIP: | ||
1016 | alg = ALG_TKIP; | ||
1017 | break; | ||
1018 | case IW_ENCODE_ALG_CCMP: | ||
1019 | alg = ALG_CCMP; | ||
1020 | break; | ||
1021 | case IW_ENCODE_ALG_AES_CMAC: | ||
1022 | alg = ALG_AES_CMAC; | ||
1023 | break; | ||
1024 | default: | ||
1025 | return -EOPNOTSUPP; | ||
1026 | } | ||
1027 | |||
1028 | if (erq->flags & IW_ENCODE_DISABLED) | ||
1029 | remove = 1; | ||
1030 | |||
1031 | idx = erq->flags & IW_ENCODE_INDEX; | ||
1032 | if (alg == ALG_AES_CMAC) { | ||
1033 | if (idx < NUM_DEFAULT_KEYS + 1 || | ||
1034 | idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { | ||
1035 | idx = -1; | ||
1036 | if (!sdata->default_mgmt_key) | ||
1037 | idx = 0; | ||
1038 | else for (i = NUM_DEFAULT_KEYS; | ||
1039 | i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS; | ||
1040 | i++) { | ||
1041 | if (sdata->default_mgmt_key == sdata->keys[i]) | ||
1042 | { | ||
1043 | idx = i; | ||
1044 | break; | ||
1045 | } | ||
1046 | } | ||
1047 | if (idx < 0) | ||
1048 | return -EINVAL; | ||
1049 | } else | ||
1050 | idx--; | ||
1051 | } else { | ||
1052 | if (idx < 1 || idx > 4) { | ||
1053 | idx = -1; | ||
1054 | if (!sdata->default_key) | ||
1055 | idx = 0; | ||
1056 | else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
1057 | if (sdata->default_key == sdata->keys[i]) { | ||
1058 | idx = i; | ||
1059 | break; | ||
1060 | } | ||
1061 | } | ||
1062 | if (idx < 0) | ||
1063 | return -EINVAL; | ||
1064 | } else | ||
1065 | idx--; | ||
1066 | } | ||
1067 | |||
1068 | return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg, | ||
1069 | remove, | ||
1070 | ext->ext_flags & | ||
1071 | IW_ENCODE_EXT_SET_TX_KEY, | ||
1072 | ext->key, ext->key_len); | ||
1073 | } | ||
1074 | |||
1075 | |||
1076 | /* Structures to export the Wireless Handlers */ | 543 | /* Structures to export the Wireless Handlers */ |
1077 | 544 | ||
1078 | static const iw_handler ieee80211_handler[] = | 545 | static const iw_handler ieee80211_handler[] = |
@@ -1099,7 +566,7 @@ static const iw_handler ieee80211_handler[] = | |||
1099 | (iw_handler) NULL, /* SIOCGIWTHRSPY */ | 566 | (iw_handler) NULL, /* SIOCGIWTHRSPY */ |
1100 | (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ | 567 | (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ |
1101 | (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ | 568 | (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ |
1102 | (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ | 569 | (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */ |
1103 | (iw_handler) NULL, /* SIOCGIWAPLIST */ | 570 | (iw_handler) NULL, /* SIOCGIWAPLIST */ |
1104 | (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ | 571 | (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ |
1105 | (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ | 572 | (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ |
@@ -1111,16 +578,16 @@ static const iw_handler ieee80211_handler[] = | |||
1111 | (iw_handler) NULL, /* -- hole -- */ | 578 | (iw_handler) NULL, /* -- hole -- */ |
1112 | (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ | 579 | (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ |
1113 | (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ | 580 | (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ |
1114 | (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */ | 581 | (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ |
1115 | (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ | 582 | (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ |
1116 | (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ | 583 | (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ |
1117 | (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ | 584 | (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ |
1118 | (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ | 585 | (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ |
1119 | (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ | 586 | (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ |
1120 | (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ | 587 | (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ |
1121 | (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ | 588 | (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ |
1122 | (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ | 589 | (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ |
1123 | (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ | 590 | (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ |
1124 | (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ | 591 | (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ |
1125 | (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ | 592 | (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ |
1126 | (iw_handler) NULL, /* -- hole -- */ | 593 | (iw_handler) NULL, /* -- hole -- */ |
@@ -1129,7 +596,7 @@ static const iw_handler ieee80211_handler[] = | |||
1129 | (iw_handler) NULL, /* SIOCGIWGENIE */ | 596 | (iw_handler) NULL, /* SIOCGIWGENIE */ |
1130 | (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ | 597 | (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ |
1131 | (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ | 598 | (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ |
1132 | (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ | 599 | (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ |
1133 | (iw_handler) NULL, /* SIOCGIWENCODEEXT */ | 600 | (iw_handler) NULL, /* SIOCGIWENCODEEXT */ |
1134 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | 601 | (iw_handler) NULL, /* SIOCSIWPMKSA */ |
1135 | (iw_handler) NULL, /* -- hole -- */ | 602 | (iw_handler) NULL, /* -- hole -- */ |