diff options
Diffstat (limited to 'net/mac80211/ieee80211_ioctl.c')
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 127 |
1 files changed, 66 insertions, 61 deletions
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 5024d3733834..54ad07aafe2d 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -129,22 +129,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, | |||
129 | struct iw_request_info *info, | 129 | struct iw_request_info *info, |
130 | char *name, char *extra) | 130 | char *name, char *extra) |
131 | { | 131 | { |
132 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 132 | 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 | 133 | ||
149 | return 0; | 134 | return 0; |
150 | } | 135 | } |
@@ -156,7 +141,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
156 | { | 141 | { |
157 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 142 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
158 | struct iw_range *range = (struct iw_range *) extra; | 143 | struct iw_range *range = (struct iw_range *) extra; |
159 | struct ieee80211_hw_mode *mode = NULL; | 144 | enum ieee80211_band band; |
160 | int c = 0; | 145 | int c = 0; |
161 | 146 | ||
162 | data->length = sizeof(struct iw_range); | 147 | data->length = sizeof(struct iw_range); |
@@ -191,24 +176,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
191 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | 176 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | |
192 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | 177 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; |
193 | 178 | ||
194 | list_for_each_entry(mode, &local->modes_list, list) { | ||
195 | int i = 0; | ||
196 | 179 | ||
197 | if (!(local->enabled_modes & (1 << mode->mode)) || | 180 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { |
198 | (local->hw_modes & local->enabled_modes & | 181 | int i; |
199 | (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) | 182 | struct ieee80211_supported_band *sband; |
183 | |||
184 | sband = local->hw.wiphy->bands[band]; | ||
185 | |||
186 | if (!sband) | ||
200 | continue; | 187 | continue; |
201 | 188 | ||
202 | while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) { | 189 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { |
203 | struct ieee80211_channel *chan = &mode->channels[i]; | 190 | struct ieee80211_channel *chan = &sband->channels[i]; |
204 | 191 | ||
205 | if (chan->flag & IEEE80211_CHAN_W_SCAN) { | 192 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { |
206 | range->freq[c].i = chan->chan; | 193 | range->freq[c].i = |
207 | range->freq[c].m = chan->freq * 100000; | 194 | ieee80211_frequency_to_channel( |
208 | range->freq[c].e = 1; | 195 | chan->center_freq); |
196 | range->freq[c].m = chan->center_freq; | ||
197 | range->freq[c].e = 6; | ||
209 | c++; | 198 | c++; |
210 | } | 199 | } |
211 | i++; | ||
212 | } | 200 | } |
213 | } | 201 | } |
214 | range->num_channels = c; | 202 | range->num_channels = c; |
@@ -294,22 +282,29 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, | |||
294 | return 0; | 282 | return 0; |
295 | } | 283 | } |
296 | 284 | ||
297 | int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq) | 285 | int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) |
298 | { | 286 | { |
299 | struct ieee80211_hw_mode *mode; | 287 | int set = 0; |
300 | int c, set = 0; | ||
301 | int ret = -EINVAL; | 288 | int ret = -EINVAL; |
289 | enum ieee80211_band band; | ||
290 | struct ieee80211_supported_band *sband; | ||
291 | int i; | ||
292 | |||
293 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { | ||
294 | sband = local->hw.wiphy->bands[band]; | ||
302 | 295 | ||
303 | list_for_each_entry(mode, &local->modes_list, list) { | 296 | if (!sband) |
304 | if (!(local->enabled_modes & (1 << mode->mode))) | ||
305 | continue; | 297 | continue; |
306 | for (c = 0; c < mode->num_channels; c++) { | 298 | |
307 | struct ieee80211_channel *chan = &mode->channels[c]; | 299 | for (i = 0; i < sband->n_channels; i++) { |
308 | if (chan->flag & IEEE80211_CHAN_W_SCAN && | 300 | struct ieee80211_channel *chan = &sband->channels[i]; |
309 | ((chan->chan == channel) || (chan->freq == freq))) { | 301 | |
310 | local->oper_channel = chan; | 302 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
311 | local->oper_hw_mode = mode; | 303 | continue; |
304 | |||
305 | if (chan->center_freq == freqMHz) { | ||
312 | set = 1; | 306 | set = 1; |
307 | local->oper_channel = chan; | ||
313 | break; | 308 | break; |
314 | } | 309 | } |
315 | } | 310 | } |
@@ -347,13 +342,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, | |||
347 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 342 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
348 | return 0; | 343 | return 0; |
349 | } else | 344 | } else |
350 | return ieee80211_set_channel(local, freq->m, -1); | 345 | return ieee80211_set_freq(local, |
346 | ieee80211_channel_to_frequency(freq->m)); | ||
351 | } else { | 347 | } else { |
352 | int i, div = 1000000; | 348 | int i, div = 1000000; |
353 | for (i = 0; i < freq->e; i++) | 349 | for (i = 0; i < freq->e; i++) |
354 | div /= 10; | 350 | div /= 10; |
355 | if (div > 0) | 351 | if (div > 0) |
356 | return ieee80211_set_channel(local, -1, freq->m / div); | 352 | return ieee80211_set_freq(local, freq->m / div); |
357 | else | 353 | else |
358 | return -EINVAL; | 354 | return -EINVAL; |
359 | } | 355 | } |
@@ -366,10 +362,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, | |||
366 | { | 362 | { |
367 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 363 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
368 | 364 | ||
369 | /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level | 365 | 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; | 366 | freq->e = 6; |
374 | 367 | ||
375 | return 0; | 368 | return 0; |
@@ -566,15 +559,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, | |||
566 | struct iw_param *rate, char *extra) | 559 | struct iw_param *rate, char *extra) |
567 | { | 560 | { |
568 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 561 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
569 | struct ieee80211_hw_mode *mode; | 562 | int i, err = -EINVAL; |
570 | int i; | ||
571 | u32 target_rate = rate->value / 100000; | 563 | u32 target_rate = rate->value / 100000; |
572 | struct ieee80211_sub_if_data *sdata; | 564 | struct ieee80211_sub_if_data *sdata; |
565 | struct ieee80211_supported_band *sband; | ||
573 | 566 | ||
574 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 567 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
575 | if (!sdata->bss) | 568 | if (!sdata->bss) |
576 | return -ENODEV; | 569 | return -ENODEV; |
577 | mode = local->oper_hw_mode; | 570 | |
571 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
572 | |||
578 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | 573 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates |
579 | * target_rate = X, rate->fixed = 1 means only rate X | 574 | * target_rate = X, rate->fixed = 1 means only rate X |
580 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | 575 | * target_rate = X, rate->fixed = 0 means all rates <= X */ |
@@ -582,18 +577,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, | |||
582 | sdata->bss->force_unicast_rateidx = -1; | 577 | sdata->bss->force_unicast_rateidx = -1; |
583 | if (rate->value < 0) | 578 | if (rate->value < 0) |
584 | return 0; | 579 | return 0; |
585 | for (i=0; i < mode->num_rates; i++) { | 580 | |
586 | struct ieee80211_rate *rates = &mode->rates[i]; | 581 | for (i=0; i< sband->n_bitrates; i++) { |
587 | int this_rate = rates->rate; | 582 | struct ieee80211_rate *brate = &sband->bitrates[i]; |
583 | int this_rate = brate->bitrate; | ||
588 | 584 | ||
589 | if (target_rate == this_rate) { | 585 | if (target_rate == this_rate) { |
590 | sdata->bss->max_ratectrl_rateidx = i; | 586 | sdata->bss->max_ratectrl_rateidx = i; |
591 | if (rate->fixed) | 587 | if (rate->fixed) |
592 | sdata->bss->force_unicast_rateidx = i; | 588 | sdata->bss->force_unicast_rateidx = i; |
593 | return 0; | 589 | err = 0; |
590 | break; | ||
594 | } | 591 | } |
595 | } | 592 | } |
596 | return -EINVAL; | 593 | return err; |
597 | } | 594 | } |
598 | 595 | ||
599 | static int ieee80211_ioctl_giwrate(struct net_device *dev, | 596 | static int ieee80211_ioctl_giwrate(struct net_device *dev, |
@@ -603,18 +600,24 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, | |||
603 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 600 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
604 | struct sta_info *sta; | 601 | struct sta_info *sta; |
605 | struct ieee80211_sub_if_data *sdata; | 602 | struct ieee80211_sub_if_data *sdata; |
603 | struct ieee80211_supported_band *sband; | ||
606 | 604 | ||
607 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 605 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
606 | |||
608 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) | 607 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) |
609 | sta = sta_info_get(local, sdata->u.sta.bssid); | 608 | sta = sta_info_get(local, sdata->u.sta.bssid); |
610 | else | 609 | else |
611 | return -EOPNOTSUPP; | 610 | return -EOPNOTSUPP; |
612 | if (!sta) | 611 | if (!sta) |
613 | return -ENODEV; | 612 | return -ENODEV; |
614 | if (sta->txrate < local->oper_hw_mode->num_rates) | 613 | |
615 | rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000; | 614 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
615 | |||
616 | if (sta->txrate_idx < sband->n_bitrates) | ||
617 | rate->value = sband->bitrates[sta->txrate_idx].bitrate; | ||
616 | else | 618 | else |
617 | rate->value = 0; | 619 | rate->value = 0; |
620 | rate->value *= 100000; | ||
618 | sta_info_put(sta); | 621 | sta_info_put(sta); |
619 | return 0; | 622 | return 0; |
620 | } | 623 | } |
@@ -625,7 +628,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, | |||
625 | { | 628 | { |
626 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 629 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
627 | bool need_reconfig = 0; | 630 | bool need_reconfig = 0; |
628 | u8 new_power_level; | 631 | int new_power_level; |
629 | 632 | ||
630 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | 633 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) |
631 | return -EINVAL; | 634 | return -EINVAL; |
@@ -635,13 +638,15 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, | |||
635 | if (data->txpower.fixed) { | 638 | if (data->txpower.fixed) { |
636 | new_power_level = data->txpower.value; | 639 | new_power_level = data->txpower.value; |
637 | } else { | 640 | } else { |
638 | /* Automatic power level. Get the px power from the current | 641 | /* |
639 | * channel. */ | 642 | * Automatic power level. Use maximum power for the current |
640 | struct ieee80211_channel* chan = local->oper_channel; | 643 | * channel. Should be part of rate control. |
644 | */ | ||
645 | struct ieee80211_channel* chan = local->hw.conf.channel; | ||
641 | if (!chan) | 646 | if (!chan) |
642 | return -EINVAL; | 647 | return -EINVAL; |
643 | 648 | ||
644 | new_power_level = chan->power_level; | 649 | new_power_level = chan->max_power; |
645 | } | 650 | } |
646 | 651 | ||
647 | if (local->hw.conf.power_level != new_power_level) { | 652 | if (local->hw.conf.power_level != new_power_level) { |