diff options
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 209 |
1 files changed, 76 insertions, 133 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ae62ad40ad63..fa0cc7a1e6b4 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -41,6 +41,8 @@ | |||
41 | */ | 41 | */ |
42 | struct ieee80211_tx_status_rtap_hdr { | 42 | struct ieee80211_tx_status_rtap_hdr { |
43 | struct ieee80211_radiotap_header hdr; | 43 | struct ieee80211_radiotap_header hdr; |
44 | u8 rate; | ||
45 | u8 padding_for_rate; | ||
44 | __le16 tx_flags; | 46 | __le16 tx_flags; |
45 | u8 data_retries; | 47 | u8 data_retries; |
46 | } __attribute__ ((packed)); | 48 | } __attribute__ ((packed)); |
@@ -197,129 +199,44 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
197 | &sdata->vif, &conf); | 199 | &sdata->vif, &conf); |
198 | } | 200 | } |
199 | 201 | ||
200 | int ieee80211_hw_config(struct ieee80211_local *local) | 202 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) |
201 | { | 203 | { |
202 | struct ieee80211_channel *chan; | 204 | struct ieee80211_channel *chan; |
203 | int ret = 0; | 205 | int ret = 0; |
206 | int power; | ||
207 | |||
208 | might_sleep(); | ||
204 | 209 | ||
205 | if (local->sw_scanning) | 210 | if (local->sw_scanning) |
206 | chan = local->scan_channel; | 211 | chan = local->scan_channel; |
207 | else | 212 | else |
208 | chan = local->oper_channel; | 213 | chan = local->oper_channel; |
209 | 214 | ||
210 | local->hw.conf.channel = chan; | 215 | if (chan != local->hw.conf.channel) { |
216 | local->hw.conf.channel = chan; | ||
217 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | ||
218 | } | ||
219 | |||
211 | 220 | ||
212 | if (!local->hw.conf.power_level) | 221 | if (!local->hw.conf.power_level) |
213 | local->hw.conf.power_level = chan->max_power; | 222 | power = chan->max_power; |
214 | else | 223 | else |
215 | local->hw.conf.power_level = min(chan->max_power, | 224 | power = min(chan->max_power, local->hw.conf.power_level); |
216 | local->hw.conf.power_level); | 225 | if (local->hw.conf.power_level != power) { |
217 | 226 | changed |= IEEE80211_CONF_CHANGE_POWER; | |
218 | local->hw.conf.max_antenna_gain = chan->max_antenna_gain; | 227 | local->hw.conf.power_level = power; |
219 | |||
220 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
221 | printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n", | ||
222 | wiphy_name(local->hw.wiphy), chan->center_freq); | ||
223 | #endif | ||
224 | |||
225 | if (local->open_count) | ||
226 | ret = local->ops->config(local_to_hw(local), &local->hw.conf); | ||
227 | |||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * ieee80211_handle_ht should be used only after legacy configuration | ||
233 | * has been determined namely band, as ht configuration depends upon | ||
234 | * the hardware's HT abilities for a _specific_ band. | ||
235 | */ | ||
236 | u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, | ||
237 | struct ieee80211_ht_info *req_ht_cap, | ||
238 | struct ieee80211_ht_bss_info *req_bss_cap) | ||
239 | { | ||
240 | struct ieee80211_conf *conf = &local->hw.conf; | ||
241 | struct ieee80211_supported_band *sband; | ||
242 | struct ieee80211_ht_info ht_conf; | ||
243 | struct ieee80211_ht_bss_info ht_bss_conf; | ||
244 | u32 changed = 0; | ||
245 | int i; | ||
246 | u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS; | ||
247 | u8 tx_mcs_set_cap; | ||
248 | |||
249 | sband = local->hw.wiphy->bands[conf->channel->band]; | ||
250 | |||
251 | memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); | ||
252 | memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); | ||
253 | |||
254 | /* HT is not supported */ | ||
255 | if (!sband->ht_info.ht_supported) { | ||
256 | conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; | ||
257 | goto out; | ||
258 | } | 228 | } |
259 | 229 | ||
260 | /* disable HT */ | 230 | if (changed && local->open_count) { |
261 | if (!enable_ht) { | 231 | ret = local->ops->config(local_to_hw(local), changed); |
262 | if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) | 232 | /* |
263 | changed |= BSS_CHANGED_HT; | 233 | * HW reconfiguration should never fail, the driver has told |
264 | conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; | 234 | * us what it can support so it should live up to that promise. |
265 | conf->ht_conf.ht_supported = 0; | 235 | */ |
266 | goto out; | 236 | WARN_ON(ret); |
267 | } | 237 | } |
268 | 238 | ||
269 | 239 | return ret; | |
270 | if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) | ||
271 | changed |= BSS_CHANGED_HT; | ||
272 | |||
273 | conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; | ||
274 | ht_conf.ht_supported = 1; | ||
275 | |||
276 | ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; | ||
277 | ht_conf.cap &= ~(IEEE80211_HT_CAP_SM_PS); | ||
278 | ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_SM_PS; | ||
279 | ht_bss_conf.primary_channel = req_bss_cap->primary_channel; | ||
280 | ht_bss_conf.bss_cap = req_bss_cap->bss_cap; | ||
281 | ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; | ||
282 | |||
283 | ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; | ||
284 | ht_conf.ampdu_density = req_ht_cap->ampdu_density; | ||
285 | |||
286 | /* Bits 96-100 */ | ||
287 | tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12]; | ||
288 | |||
289 | /* configure suppoerted Tx MCS according to requested MCS | ||
290 | * (based in most cases on Rx capabilities of peer) and self | ||
291 | * Tx MCS capabilities (as defined by low level driver HW | ||
292 | * Tx capabilities) */ | ||
293 | if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED)) | ||
294 | goto check_changed; | ||
295 | |||
296 | /* Counting from 0 therfore + 1 */ | ||
297 | if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF) | ||
298 | max_tx_streams = ((tx_mcs_set_cap & | ||
299 | IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1; | ||
300 | |||
301 | for (i = 0; i < max_tx_streams; i++) | ||
302 | ht_conf.supp_mcs_set[i] = | ||
303 | sband->ht_info.supp_mcs_set[i] & | ||
304 | req_ht_cap->supp_mcs_set[i]; | ||
305 | |||
306 | if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM) | ||
307 | for (i = IEEE80211_SUPP_MCS_SET_UEQM; | ||
308 | i < IEEE80211_SUPP_MCS_SET_LEN; i++) | ||
309 | ht_conf.supp_mcs_set[i] = | ||
310 | sband->ht_info.supp_mcs_set[i] & | ||
311 | req_ht_cap->supp_mcs_set[i]; | ||
312 | |||
313 | check_changed: | ||
314 | /* if bss configuration changed store the new one */ | ||
315 | if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || | ||
316 | memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { | ||
317 | changed |= BSS_CHANGED_HT; | ||
318 | memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); | ||
319 | memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); | ||
320 | } | ||
321 | out: | ||
322 | return changed; | ||
323 | } | 240 | } |
324 | 241 | ||
325 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 242 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
@@ -336,15 +253,18 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
336 | if (local->ops->bss_info_changed) | 253 | if (local->ops->bss_info_changed) |
337 | local->ops->bss_info_changed(local_to_hw(local), | 254 | local->ops->bss_info_changed(local_to_hw(local), |
338 | &sdata->vif, | 255 | &sdata->vif, |
339 | &sdata->bss_conf, | 256 | &sdata->vif.bss_conf, |
340 | changed); | 257 | changed); |
341 | } | 258 | } |
342 | 259 | ||
343 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 260 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
344 | { | 261 | { |
345 | sdata->bss_conf.use_cts_prot = 0; | 262 | sdata->vif.bss_conf.use_cts_prot = false; |
346 | sdata->bss_conf.use_short_preamble = 0; | 263 | sdata->vif.bss_conf.use_short_preamble = false; |
347 | return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE; | 264 | sdata->vif.bss_conf.use_short_slot = false; |
265 | return BSS_CHANGED_ERP_CTS_PROT | | ||
266 | BSS_CHANGED_ERP_PREAMBLE | | ||
267 | BSS_CHANGED_ERP_SLOT; | ||
348 | } | 268 | } |
349 | 269 | ||
350 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, | 270 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, |
@@ -466,8 +386,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
466 | struct sta_info *sta, | 386 | struct sta_info *sta, |
467 | struct sk_buff *skb) | 387 | struct sk_buff *skb) |
468 | { | 388 | { |
469 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
470 | |||
471 | sta->tx_filtered_count++; | 389 | sta->tx_filtered_count++; |
472 | 390 | ||
473 | /* | 391 | /* |
@@ -514,10 +432,9 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
514 | return; | 432 | return; |
515 | } | 433 | } |
516 | 434 | ||
517 | if (!test_sta_flags(sta, WLAN_STA_PS) && | 435 | if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { |
518 | !(info->flags & IEEE80211_TX_CTL_REQUEUE)) { | ||
519 | /* Software retry the packet once */ | 436 | /* Software retry the packet once */ |
520 | info->flags |= IEEE80211_TX_CTL_REQUEUE; | 437 | skb->requeue = 1; |
521 | ieee80211_remove_tx_extra(local, sta->key, skb); | 438 | ieee80211_remove_tx_extra(local, sta->key, skb); |
522 | dev_queue_xmit(skb); | 439 | dev_queue_xmit(skb); |
523 | return; | 440 | return; |
@@ -547,13 +464,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
547 | struct ieee80211_sub_if_data *sdata; | 464 | struct ieee80211_sub_if_data *sdata; |
548 | struct net_device *prev_dev = NULL; | 465 | struct net_device *prev_dev = NULL; |
549 | struct sta_info *sta; | 466 | struct sta_info *sta; |
467 | int retry_count = -1, i; | ||
468 | |||
469 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | ||
470 | /* the HW cannot have attempted that rate */ | ||
471 | if (i >= hw->max_rates) { | ||
472 | info->status.rates[i].idx = -1; | ||
473 | info->status.rates[i].count = 0; | ||
474 | } | ||
475 | |||
476 | retry_count += info->status.rates[i].count; | ||
477 | } | ||
478 | if (retry_count < 0) | ||
479 | retry_count = 0; | ||
550 | 480 | ||
551 | rcu_read_lock(); | 481 | rcu_read_lock(); |
552 | 482 | ||
483 | sband = local->hw.wiphy->bands[info->band]; | ||
484 | |||
553 | sta = sta_info_get(local, hdr->addr1); | 485 | sta = sta_info_get(local, hdr->addr1); |
554 | 486 | ||
555 | if (sta) { | 487 | if (sta) { |
556 | if (info->status.excessive_retries && | 488 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && |
557 | test_sta_flags(sta, WLAN_STA_PS)) { | 489 | test_sta_flags(sta, WLAN_STA_PS)) { |
558 | /* | 490 | /* |
559 | * The STA is in power save mode, so assume | 491 | * The STA is in power save mode, so assume |
@@ -584,12 +516,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
584 | rcu_read_unlock(); | 516 | rcu_read_unlock(); |
585 | return; | 517 | return; |
586 | } else { | 518 | } else { |
587 | if (info->status.excessive_retries) | 519 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) |
588 | sta->tx_retry_failed++; | 520 | sta->tx_retry_failed++; |
589 | sta->tx_retry_count += info->status.retry_count; | 521 | sta->tx_retry_count += retry_count; |
590 | } | 522 | } |
591 | 523 | ||
592 | sband = local->hw.wiphy->bands[info->band]; | ||
593 | rate_control_tx_status(local, sband, sta, skb); | 524 | rate_control_tx_status(local, sband, sta, skb); |
594 | } | 525 | } |
595 | 526 | ||
@@ -610,9 +541,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
610 | local->dot11TransmittedFrameCount++; | 541 | local->dot11TransmittedFrameCount++; |
611 | if (is_multicast_ether_addr(hdr->addr1)) | 542 | if (is_multicast_ether_addr(hdr->addr1)) |
612 | local->dot11MulticastTransmittedFrameCount++; | 543 | local->dot11MulticastTransmittedFrameCount++; |
613 | if (info->status.retry_count > 0) | 544 | if (retry_count > 0) |
614 | local->dot11RetryCount++; | 545 | local->dot11RetryCount++; |
615 | if (info->status.retry_count > 1) | 546 | if (retry_count > 1) |
616 | local->dot11MultipleRetryCount++; | 547 | local->dot11MultipleRetryCount++; |
617 | } | 548 | } |
618 | 549 | ||
@@ -656,19 +587,30 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
656 | rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); | 587 | rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); |
657 | rthdr->hdr.it_present = | 588 | rthdr->hdr.it_present = |
658 | cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | | 589 | cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | |
659 | (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); | 590 | (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | |
591 | (1 << IEEE80211_RADIOTAP_RATE)); | ||
660 | 592 | ||
661 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 593 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && |
662 | !is_multicast_ether_addr(hdr->addr1)) | 594 | !is_multicast_ether_addr(hdr->addr1)) |
663 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); | 595 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); |
664 | 596 | ||
665 | if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) && | 597 | /* |
666 | (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) | 598 | * XXX: Once radiotap gets the bitmap reset thing the vendor |
599 | * extensions proposal contains, we can actually report | ||
600 | * the whole set of tries we did. | ||
601 | */ | ||
602 | if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || | ||
603 | (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) | ||
667 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); | 604 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); |
668 | else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) | 605 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) |
669 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); | 606 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); |
607 | if (info->status.rates[0].idx >= 0 && | ||
608 | !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) | ||
609 | rthdr->rate = sband->bitrates[ | ||
610 | info->status.rates[0].idx].bitrate / 5; | ||
670 | 611 | ||
671 | rthdr->data_retries = info->status.retry_count; | 612 | /* for now report the total retry_count */ |
613 | rthdr->data_retries = retry_count; | ||
672 | 614 | ||
673 | /* XXX: is this sufficient for BPF? */ | 615 | /* XXX: is this sufficient for BPF? */ |
674 | skb_set_mac_header(skb, 0); | 616 | skb_set_mac_header(skb, 0); |
@@ -753,13 +695,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
753 | BUG_ON(!ops->configure_filter); | 695 | BUG_ON(!ops->configure_filter); |
754 | local->ops = ops; | 696 | local->ops = ops; |
755 | 697 | ||
756 | local->hw.queues = 1; /* default */ | 698 | /* set up some defaults */ |
757 | 699 | local->hw.queues = 1; | |
700 | local->hw.max_rates = 1; | ||
758 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 701 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; |
759 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | 702 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; |
760 | local->short_retry_limit = 7; | 703 | local->hw.conf.long_frame_max_tx_count = 4; |
761 | local->long_retry_limit = 4; | 704 | local->hw.conf.short_frame_max_tx_count = 7; |
762 | local->hw.conf.radio_enabled = 1; | 705 | local->hw.conf.radio_enabled = true; |
763 | 706 | ||
764 | INIT_LIST_HEAD(&local->interfaces); | 707 | INIT_LIST_HEAD(&local->interfaces); |
765 | 708 | ||
@@ -1013,7 +956,7 @@ static int __init ieee80211_init(void) | |||
1013 | 956 | ||
1014 | BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); | 957 | BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); |
1015 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + | 958 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + |
1016 | IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); | 959 | IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); |
1017 | 960 | ||
1018 | ret = rc80211_minstrel_init(); | 961 | ret = rc80211_minstrel_init(); |
1019 | if (ret) | 962 | if (ret) |