diff options
Diffstat (limited to 'net/mac80211/ieee80211_ioctl.c')
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 232 |
1 files changed, 109 insertions, 123 deletions
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 5024d3733834..b047eebb6330 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -33,7 +33,6 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
33 | size_t key_len) | 33 | size_t key_len) |
34 | { | 34 | { |
35 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 35 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
36 | int ret = 0; | ||
37 | struct sta_info *sta; | 36 | struct sta_info *sta; |
38 | struct ieee80211_key *key; | 37 | struct ieee80211_key *key; |
39 | struct ieee80211_sub_if_data *sdata; | 38 | struct ieee80211_sub_if_data *sdata; |
@@ -46,59 +45,52 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
46 | return -EINVAL; | 45 | return -EINVAL; |
47 | } | 46 | } |
48 | 47 | ||
49 | if (is_broadcast_ether_addr(sta_addr)) { | 48 | if (remove) { |
50 | sta = NULL; | 49 | if (is_broadcast_ether_addr(sta_addr)) { |
51 | key = sdata->keys[idx]; | 50 | key = sdata->keys[idx]; |
52 | } else { | 51 | } else { |
53 | set_tx_key = 0; | 52 | sta = sta_info_get(local, sta_addr); |
54 | /* | 53 | if (!sta) |
55 | * According to the standard, the key index of a pairwise | 54 | return -ENOENT; |
56 | * key must be zero. However, some AP are broken when it | 55 | key = sta->key; |
57 | * comes to WEP key indices, so we work around this. | ||
58 | */ | ||
59 | if (idx != 0 && alg != ALG_WEP) { | ||
60 | printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for " | ||
61 | "individual key\n", dev->name); | ||
62 | return -EINVAL; | ||
63 | } | 56 | } |
64 | 57 | ||
65 | sta = sta_info_get(local, sta_addr); | 58 | ieee80211_key_free(key); |
66 | if (!sta) { | 59 | return 0; |
67 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 60 | } else { |
68 | DECLARE_MAC_BUF(mac); | 61 | key = ieee80211_key_alloc(alg, idx, key_len, _key); |
69 | printk(KERN_DEBUG "%s: set_encrypt - unknown addr " | 62 | if (!key) |
70 | "%s\n", | 63 | return -ENOMEM; |
71 | dev->name, print_mac(mac, sta_addr)); | ||
72 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
73 | 64 | ||
74 | return -ENOENT; | 65 | sta = NULL; |
75 | } | ||
76 | 66 | ||
77 | key = sta->key; | 67 | if (!is_broadcast_ether_addr(sta_addr)) { |
78 | } | 68 | set_tx_key = 0; |
69 | /* | ||
70 | * According to the standard, the key index of a | ||
71 | * pairwise key must be zero. However, some AP are | ||
72 | * broken when it comes to WEP key indices, so we | ||
73 | * work around this. | ||
74 | */ | ||
75 | if (idx != 0 && alg != ALG_WEP) { | ||
76 | ieee80211_key_free(key); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | 79 | ||
80 | if (remove) { | 80 | sta = sta_info_get(local, sta_addr); |
81 | ieee80211_key_free(key); | 81 | if (!sta) { |
82 | key = NULL; | 82 | ieee80211_key_free(key); |
83 | } else { | 83 | return -ENOENT; |
84 | /* | 84 | } |
85 | * Automatically frees any old key if present. | ||
86 | */ | ||
87 | key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key); | ||
88 | if (!key) { | ||
89 | ret = -ENOMEM; | ||
90 | goto err_out; | ||
91 | } | 85 | } |
92 | } | ||
93 | 86 | ||
94 | if (set_tx_key || (!sta && !sdata->default_key && key)) | 87 | ieee80211_key_link(key, sdata, sta); |
95 | ieee80211_set_default_key(sdata, idx); | ||
96 | 88 | ||
97 | ret = 0; | 89 | if (set_tx_key || (!sta && !sdata->default_key && key)) |
98 | err_out: | 90 | ieee80211_set_default_key(sdata, idx); |
99 | if (sta) | 91 | } |
100 | sta_info_put(sta); | 92 | |
101 | return ret; | 93 | return 0; |
102 | } | 94 | } |
103 | 95 | ||
104 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, | 96 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, |
@@ -129,22 +121,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, | |||
129 | struct iw_request_info *info, | 121 | struct iw_request_info *info, |
130 | char *name, char *extra) | 122 | char *name, char *extra) |
131 | { | 123 | { |
132 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 124 | strcpy(name, "IEEE 802.11"); |
133 | |||
134 | switch (local->hw.conf.phymode) { | ||
135 | case MODE_IEEE80211A: | ||
136 | strcpy(name, "IEEE 802.11a"); | ||
137 | break; | ||
138 | case MODE_IEEE80211B: | ||
139 | strcpy(name, "IEEE 802.11b"); | ||
140 | break; | ||
141 | case MODE_IEEE80211G: | ||
142 | strcpy(name, "IEEE 802.11g"); | ||
143 | break; | ||
144 | default: | ||
145 | strcpy(name, "IEEE 802.11"); | ||
146 | break; | ||
147 | } | ||
148 | 125 | ||
149 | return 0; | 126 | return 0; |
150 | } | 127 | } |
@@ -156,7 +133,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
156 | { | 133 | { |
157 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 134 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
158 | struct iw_range *range = (struct iw_range *) extra; | 135 | struct iw_range *range = (struct iw_range *) extra; |
159 | struct ieee80211_hw_mode *mode = NULL; | 136 | enum ieee80211_band band; |
160 | int c = 0; | 137 | int c = 0; |
161 | 138 | ||
162 | data->length = sizeof(struct iw_range); | 139 | data->length = sizeof(struct iw_range); |
@@ -191,24 +168,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
191 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | 168 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | |
192 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | 169 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; |
193 | 170 | ||
194 | list_for_each_entry(mode, &local->modes_list, list) { | ||
195 | int i = 0; | ||
196 | 171 | ||
197 | if (!(local->enabled_modes & (1 << mode->mode)) || | 172 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { |
198 | (local->hw_modes & local->enabled_modes & | 173 | int i; |
199 | (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) | 174 | struct ieee80211_supported_band *sband; |
175 | |||
176 | sband = local->hw.wiphy->bands[band]; | ||
177 | |||
178 | if (!sband) | ||
200 | continue; | 179 | continue; |
201 | 180 | ||
202 | while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) { | 181 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { |
203 | struct ieee80211_channel *chan = &mode->channels[i]; | 182 | struct ieee80211_channel *chan = &sband->channels[i]; |
204 | 183 | ||
205 | if (chan->flag & IEEE80211_CHAN_W_SCAN) { | 184 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { |
206 | range->freq[c].i = chan->chan; | 185 | range->freq[c].i = |
207 | range->freq[c].m = chan->freq * 100000; | 186 | ieee80211_frequency_to_channel( |
208 | range->freq[c].e = 1; | 187 | chan->center_freq); |
188 | range->freq[c].m = chan->center_freq; | ||
189 | range->freq[c].e = 6; | ||
209 | c++; | 190 | c++; |
210 | } | 191 | } |
211 | i++; | ||
212 | } | 192 | } |
213 | } | 193 | } |
214 | range->num_channels = c; | 194 | range->num_channels = c; |
@@ -294,31 +274,17 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, | |||
294 | return 0; | 274 | return 0; |
295 | } | 275 | } |
296 | 276 | ||
297 | int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq) | 277 | int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) |
298 | { | 278 | { |
299 | struct ieee80211_hw_mode *mode; | ||
300 | int c, set = 0; | ||
301 | int ret = -EINVAL; | 279 | int ret = -EINVAL; |
280 | struct ieee80211_channel *chan; | ||
302 | 281 | ||
303 | list_for_each_entry(mode, &local->modes_list, list) { | 282 | chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); |
304 | if (!(local->enabled_modes & (1 << mode->mode))) | 283 | |
305 | continue; | 284 | if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { |
306 | for (c = 0; c < mode->num_channels; c++) { | 285 | local->oper_channel = chan; |
307 | struct ieee80211_channel *chan = &mode->channels[c]; | ||
308 | if (chan->flag & IEEE80211_CHAN_W_SCAN && | ||
309 | ((chan->chan == channel) || (chan->freq == freq))) { | ||
310 | local->oper_channel = chan; | ||
311 | local->oper_hw_mode = mode; | ||
312 | set = 1; | ||
313 | break; | ||
314 | } | ||
315 | } | ||
316 | if (set) | ||
317 | break; | ||
318 | } | ||
319 | 286 | ||
320 | if (set) { | 287 | if (local->sta_sw_scanning || local->sta_hw_scanning) |
321 | if (local->sta_sw_scanning) | ||
322 | ret = 0; | 288 | ret = 0; |
323 | else | 289 | else |
324 | ret = ieee80211_hw_config(local); | 290 | ret = ieee80211_hw_config(local); |
@@ -347,13 +313,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, | |||
347 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 313 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
348 | return 0; | 314 | return 0; |
349 | } else | 315 | } else |
350 | return ieee80211_set_channel(local, freq->m, -1); | 316 | return ieee80211_set_freq(local, |
317 | ieee80211_channel_to_frequency(freq->m)); | ||
351 | } else { | 318 | } else { |
352 | int i, div = 1000000; | 319 | int i, div = 1000000; |
353 | for (i = 0; i < freq->e; i++) | 320 | for (i = 0; i < freq->e; i++) |
354 | div /= 10; | 321 | div /= 10; |
355 | if (div > 0) | 322 | if (div > 0) |
356 | return ieee80211_set_channel(local, -1, freq->m / div); | 323 | return ieee80211_set_freq(local, freq->m / div); |
357 | else | 324 | else |
358 | return -EINVAL; | 325 | return -EINVAL; |
359 | } | 326 | } |
@@ -366,10 +333,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, | |||
366 | { | 333 | { |
367 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 334 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
368 | 335 | ||
369 | /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level | 336 | freq->m = local->hw.conf.channel->center_freq; |
370 | * driver for the current channel with firmware-based management */ | ||
371 | |||
372 | freq->m = local->hw.conf.freq; | ||
373 | freq->e = 6; | 337 | freq->e = 6; |
374 | 338 | ||
375 | return 0; | 339 | return 0; |
@@ -480,10 +444,20 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, | |||
480 | ieee80211_sta_req_auth(dev, &sdata->u.sta); | 444 | ieee80211_sta_req_auth(dev, &sdata->u.sta); |
481 | return 0; | 445 | return 0; |
482 | } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { | 446 | } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { |
483 | if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, | 447 | /* |
484 | ETH_ALEN) == 0) | 448 | * If it is necessary to update the WDS peer address |
485 | return 0; | 449 | * while the interface is running, then we need to do |
486 | return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data); | 450 | * more work here, namely if it is running we need to |
451 | * add a new and remove the old STA entry, this is | ||
452 | * normally handled by _open() and _stop(). | ||
453 | */ | ||
454 | if (netif_running(dev)) | ||
455 | return -EBUSY; | ||
456 | |||
457 | memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, | ||
458 | ETH_ALEN); | ||
459 | |||
460 | return 0; | ||
487 | } | 461 | } |
488 | 462 | ||
489 | return -EOPNOTSUPP; | 463 | return -EOPNOTSUPP; |
@@ -526,6 +500,7 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev, | |||
526 | 500 | ||
527 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && | 501 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && |
528 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | 502 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && |
503 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT && | ||
529 | sdata->vif.type != IEEE80211_IF_TYPE_AP) | 504 | sdata->vif.type != IEEE80211_IF_TYPE_AP) |
530 | return -EOPNOTSUPP; | 505 | return -EOPNOTSUPP; |
531 | 506 | ||
@@ -566,15 +541,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, | |||
566 | struct iw_param *rate, char *extra) | 541 | struct iw_param *rate, char *extra) |
567 | { | 542 | { |
568 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 543 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
569 | struct ieee80211_hw_mode *mode; | 544 | int i, err = -EINVAL; |
570 | int i; | ||
571 | u32 target_rate = rate->value / 100000; | 545 | u32 target_rate = rate->value / 100000; |
572 | struct ieee80211_sub_if_data *sdata; | 546 | struct ieee80211_sub_if_data *sdata; |
547 | struct ieee80211_supported_band *sband; | ||
573 | 548 | ||
574 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 549 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
575 | if (!sdata->bss) | 550 | if (!sdata->bss) |
576 | return -ENODEV; | 551 | return -ENODEV; |
577 | mode = local->oper_hw_mode; | 552 | |
553 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
554 | |||
578 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | 555 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates |
579 | * target_rate = X, rate->fixed = 1 means only rate X | 556 | * target_rate = X, rate->fixed = 1 means only rate X |
580 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | 557 | * target_rate = X, rate->fixed = 0 means all rates <= X */ |
@@ -582,18 +559,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, | |||
582 | sdata->bss->force_unicast_rateidx = -1; | 559 | sdata->bss->force_unicast_rateidx = -1; |
583 | if (rate->value < 0) | 560 | if (rate->value < 0) |
584 | return 0; | 561 | return 0; |
585 | for (i=0; i < mode->num_rates; i++) { | 562 | |
586 | struct ieee80211_rate *rates = &mode->rates[i]; | 563 | for (i=0; i< sband->n_bitrates; i++) { |
587 | int this_rate = rates->rate; | 564 | struct ieee80211_rate *brate = &sband->bitrates[i]; |
565 | int this_rate = brate->bitrate; | ||
588 | 566 | ||
589 | if (target_rate == this_rate) { | 567 | if (target_rate == this_rate) { |
590 | sdata->bss->max_ratectrl_rateidx = i; | 568 | sdata->bss->max_ratectrl_rateidx = i; |
591 | if (rate->fixed) | 569 | if (rate->fixed) |
592 | sdata->bss->force_unicast_rateidx = i; | 570 | sdata->bss->force_unicast_rateidx = i; |
593 | return 0; | 571 | err = 0; |
572 | break; | ||
594 | } | 573 | } |
595 | } | 574 | } |
596 | return -EINVAL; | 575 | return err; |
597 | } | 576 | } |
598 | 577 | ||
599 | static int ieee80211_ioctl_giwrate(struct net_device *dev, | 578 | static int ieee80211_ioctl_giwrate(struct net_device *dev, |
@@ -603,19 +582,25 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, | |||
603 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 582 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
604 | struct sta_info *sta; | 583 | struct sta_info *sta; |
605 | struct ieee80211_sub_if_data *sdata; | 584 | struct ieee80211_sub_if_data *sdata; |
585 | struct ieee80211_supported_band *sband; | ||
606 | 586 | ||
607 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 587 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
588 | |||
608 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) | 589 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) |
609 | sta = sta_info_get(local, sdata->u.sta.bssid); | 590 | sta = sta_info_get(local, sdata->u.sta.bssid); |
610 | else | 591 | else |
611 | return -EOPNOTSUPP; | 592 | return -EOPNOTSUPP; |
612 | if (!sta) | 593 | if (!sta) |
613 | return -ENODEV; | 594 | return -ENODEV; |
614 | if (sta->txrate < local->oper_hw_mode->num_rates) | 595 | |
615 | rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000; | 596 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
597 | |||
598 | if (sta->txrate_idx < sband->n_bitrates) | ||
599 | rate->value = sband->bitrates[sta->txrate_idx].bitrate; | ||
616 | else | 600 | else |
617 | rate->value = 0; | 601 | rate->value = 0; |
618 | sta_info_put(sta); | 602 | rate->value *= 100000; |
603 | |||
619 | return 0; | 604 | return 0; |
620 | } | 605 | } |
621 | 606 | ||
@@ -625,7 +610,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, | |||
625 | { | 610 | { |
626 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 611 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
627 | bool need_reconfig = 0; | 612 | bool need_reconfig = 0; |
628 | u8 new_power_level; | 613 | int new_power_level; |
629 | 614 | ||
630 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | 615 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) |
631 | return -EINVAL; | 616 | return -EINVAL; |
@@ -635,13 +620,15 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, | |||
635 | if (data->txpower.fixed) { | 620 | if (data->txpower.fixed) { |
636 | new_power_level = data->txpower.value; | 621 | new_power_level = data->txpower.value; |
637 | } else { | 622 | } else { |
638 | /* Automatic power level. Get the px power from the current | 623 | /* |
639 | * channel. */ | 624 | * Automatic power level. Use maximum power for the current |
640 | struct ieee80211_channel* chan = local->oper_channel; | 625 | * channel. Should be part of rate control. |
626 | */ | ||
627 | struct ieee80211_channel* chan = local->hw.conf.channel; | ||
641 | if (!chan) | 628 | if (!chan) |
642 | return -EINVAL; | 629 | return -EINVAL; |
643 | 630 | ||
644 | new_power_level = chan->power_level; | 631 | new_power_level = chan->max_power; |
645 | } | 632 | } |
646 | 633 | ||
647 | if (local->hw.conf.power_level != new_power_level) { | 634 | if (local->hw.conf.power_level != new_power_level) { |
@@ -988,7 +975,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev | |||
988 | wstats->qual.qual = sta->last_signal; | 975 | wstats->qual.qual = sta->last_signal; |
989 | wstats->qual.noise = sta->last_noise; | 976 | wstats->qual.noise = sta->last_noise; |
990 | wstats->qual.updated = local->wstats_flags; | 977 | wstats->qual.updated = local->wstats_flags; |
991 | sta_info_put(sta); | ||
992 | } | 978 | } |
993 | return wstats; | 979 | return wstats; |
994 | } | 980 | } |