diff options
author | James Morris <james.l.morris@oracle.com> | 2014-11-19 05:32:12 -0500 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2014-11-19 05:32:12 -0500 |
commit | b10778a00d40b3d9fdaaf5891e802794781ff71c (patch) | |
tree | 6ba4cbac86eecedc3f30650e7f764ecf00c83898 /net/mac80211/cfg.c | |
parent | 594081ee7145cc30a3977cb4e218f81213b63dc5 (diff) | |
parent | bfe01a5ba2490f299e1d2d5508cbbbadd897bbe9 (diff) |
Merge commit 'v3.17' into next
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 558 |
1 files changed, 125 insertions, 433 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 592f4b152ba8..927b4ea0128b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -468,330 +468,6 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) | |||
468 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 468 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; |
469 | } | 469 | } |
470 | 470 | ||
471 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
472 | { | ||
473 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
474 | struct ieee80211_local *local = sdata->local; | ||
475 | struct rate_control_ref *ref = NULL; | ||
476 | struct timespec uptime; | ||
477 | u64 packets = 0; | ||
478 | u32 thr = 0; | ||
479 | int i, ac; | ||
480 | |||
481 | if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) | ||
482 | ref = local->rate_ctrl; | ||
483 | |||
484 | sinfo->generation = sdata->local->sta_generation; | ||
485 | |||
486 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | ||
487 | STATION_INFO_RX_BYTES64 | | ||
488 | STATION_INFO_TX_BYTES64 | | ||
489 | STATION_INFO_RX_PACKETS | | ||
490 | STATION_INFO_TX_PACKETS | | ||
491 | STATION_INFO_TX_RETRIES | | ||
492 | STATION_INFO_TX_FAILED | | ||
493 | STATION_INFO_TX_BITRATE | | ||
494 | STATION_INFO_RX_BITRATE | | ||
495 | STATION_INFO_RX_DROP_MISC | | ||
496 | STATION_INFO_BSS_PARAM | | ||
497 | STATION_INFO_CONNECTED_TIME | | ||
498 | STATION_INFO_STA_FLAGS | | ||
499 | STATION_INFO_BEACON_LOSS_COUNT; | ||
500 | |||
501 | do_posix_clock_monotonic_gettime(&uptime); | ||
502 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | ||
503 | |||
504 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | ||
505 | sinfo->tx_bytes = 0; | ||
506 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
507 | sinfo->tx_bytes += sta->tx_bytes[ac]; | ||
508 | packets += sta->tx_packets[ac]; | ||
509 | } | ||
510 | sinfo->tx_packets = packets; | ||
511 | sinfo->rx_bytes = sta->rx_bytes; | ||
512 | sinfo->rx_packets = sta->rx_packets; | ||
513 | sinfo->tx_retries = sta->tx_retry_count; | ||
514 | sinfo->tx_failed = sta->tx_retry_failed; | ||
515 | sinfo->rx_dropped_misc = sta->rx_dropped; | ||
516 | sinfo->beacon_loss_count = sta->beacon_loss_count; | ||
517 | |||
518 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | ||
519 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | ||
520 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | ||
521 | if (!local->ops->get_rssi || | ||
522 | drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) | ||
523 | sinfo->signal = (s8)sta->last_signal; | ||
524 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
525 | } | ||
526 | if (sta->chains) { | ||
527 | sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | | ||
528 | STATION_INFO_CHAIN_SIGNAL_AVG; | ||
529 | |||
530 | sinfo->chains = sta->chains; | ||
531 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { | ||
532 | sinfo->chain_signal[i] = sta->chain_signal_last[i]; | ||
533 | sinfo->chain_signal_avg[i] = | ||
534 | (s8) -ewma_read(&sta->chain_signal_avg[i]); | ||
535 | } | ||
536 | } | ||
537 | |||
538 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | ||
539 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | ||
540 | |||
541 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
542 | #ifdef CONFIG_MAC80211_MESH | ||
543 | sinfo->filled |= STATION_INFO_LLID | | ||
544 | STATION_INFO_PLID | | ||
545 | STATION_INFO_PLINK_STATE | | ||
546 | STATION_INFO_LOCAL_PM | | ||
547 | STATION_INFO_PEER_PM | | ||
548 | STATION_INFO_NONPEER_PM; | ||
549 | |||
550 | sinfo->llid = sta->llid; | ||
551 | sinfo->plid = sta->plid; | ||
552 | sinfo->plink_state = sta->plink_state; | ||
553 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
554 | sinfo->filled |= STATION_INFO_T_OFFSET; | ||
555 | sinfo->t_offset = sta->t_offset; | ||
556 | } | ||
557 | sinfo->local_pm = sta->local_pm; | ||
558 | sinfo->peer_pm = sta->peer_pm; | ||
559 | sinfo->nonpeer_pm = sta->nonpeer_pm; | ||
560 | #endif | ||
561 | } | ||
562 | |||
563 | sinfo->bss_param.flags = 0; | ||
564 | if (sdata->vif.bss_conf.use_cts_prot) | ||
565 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; | ||
566 | if (sdata->vif.bss_conf.use_short_preamble) | ||
567 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; | ||
568 | if (sdata->vif.bss_conf.use_short_slot) | ||
569 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; | ||
570 | sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; | ||
571 | sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; | ||
572 | |||
573 | sinfo->sta_flags.set = 0; | ||
574 | sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
575 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
576 | BIT(NL80211_STA_FLAG_WME) | | ||
577 | BIT(NL80211_STA_FLAG_MFP) | | ||
578 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
579 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
580 | BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
581 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
582 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
583 | if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) | ||
584 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); | ||
585 | if (test_sta_flag(sta, WLAN_STA_WME)) | ||
586 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); | ||
587 | if (test_sta_flag(sta, WLAN_STA_MFP)) | ||
588 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); | ||
589 | if (test_sta_flag(sta, WLAN_STA_AUTH)) | ||
590 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); | ||
591 | if (test_sta_flag(sta, WLAN_STA_ASSOC)) | ||
592 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
593 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
594 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
595 | |||
596 | /* check if the driver has a SW RC implementation */ | ||
597 | if (ref && ref->ops->get_expected_throughput) | ||
598 | thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); | ||
599 | else | ||
600 | thr = drv_get_expected_throughput(local, &sta->sta); | ||
601 | |||
602 | if (thr != 0) { | ||
603 | sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; | ||
604 | sinfo->expected_throughput = thr; | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { | ||
609 | "rx_packets", "rx_bytes", "wep_weak_iv_count", | ||
610 | "rx_duplicates", "rx_fragments", "rx_dropped", | ||
611 | "tx_packets", "tx_bytes", "tx_fragments", | ||
612 | "tx_filtered", "tx_retry_failed", "tx_retries", | ||
613 | "beacon_loss", "sta_state", "txrate", "rxrate", "signal", | ||
614 | "channel", "noise", "ch_time", "ch_time_busy", | ||
615 | "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" | ||
616 | }; | ||
617 | #define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) | ||
618 | |||
619 | static int ieee80211_get_et_sset_count(struct wiphy *wiphy, | ||
620 | struct net_device *dev, | ||
621 | int sset) | ||
622 | { | ||
623 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
624 | int rv = 0; | ||
625 | |||
626 | if (sset == ETH_SS_STATS) | ||
627 | rv += STA_STATS_LEN; | ||
628 | |||
629 | rv += drv_get_et_sset_count(sdata, sset); | ||
630 | |||
631 | if (rv == 0) | ||
632 | return -EOPNOTSUPP; | ||
633 | return rv; | ||
634 | } | ||
635 | |||
636 | static void ieee80211_get_et_stats(struct wiphy *wiphy, | ||
637 | struct net_device *dev, | ||
638 | struct ethtool_stats *stats, | ||
639 | u64 *data) | ||
640 | { | ||
641 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
642 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
643 | struct ieee80211_channel *channel; | ||
644 | struct sta_info *sta; | ||
645 | struct ieee80211_local *local = sdata->local; | ||
646 | struct station_info sinfo; | ||
647 | struct survey_info survey; | ||
648 | int i, q; | ||
649 | #define STA_STATS_SURVEY_LEN 7 | ||
650 | |||
651 | memset(data, 0, sizeof(u64) * STA_STATS_LEN); | ||
652 | |||
653 | #define ADD_STA_STATS(sta) \ | ||
654 | do { \ | ||
655 | data[i++] += sta->rx_packets; \ | ||
656 | data[i++] += sta->rx_bytes; \ | ||
657 | data[i++] += sta->wep_weak_iv_count; \ | ||
658 | data[i++] += sta->num_duplicates; \ | ||
659 | data[i++] += sta->rx_fragments; \ | ||
660 | data[i++] += sta->rx_dropped; \ | ||
661 | \ | ||
662 | data[i++] += sinfo.tx_packets; \ | ||
663 | data[i++] += sinfo.tx_bytes; \ | ||
664 | data[i++] += sta->tx_fragments; \ | ||
665 | data[i++] += sta->tx_filtered_count; \ | ||
666 | data[i++] += sta->tx_retry_failed; \ | ||
667 | data[i++] += sta->tx_retry_count; \ | ||
668 | data[i++] += sta->beacon_loss_count; \ | ||
669 | } while (0) | ||
670 | |||
671 | /* For Managed stations, find the single station based on BSSID | ||
672 | * and use that. For interface types, iterate through all available | ||
673 | * stations and add stats for any station that is assigned to this | ||
674 | * network device. | ||
675 | */ | ||
676 | |||
677 | mutex_lock(&local->sta_mtx); | ||
678 | |||
679 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
680 | sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); | ||
681 | |||
682 | if (!(sta && !WARN_ON(sta->sdata->dev != dev))) | ||
683 | goto do_survey; | ||
684 | |||
685 | sinfo.filled = 0; | ||
686 | sta_set_sinfo(sta, &sinfo); | ||
687 | |||
688 | i = 0; | ||
689 | ADD_STA_STATS(sta); | ||
690 | |||
691 | data[i++] = sta->sta_state; | ||
692 | |||
693 | |||
694 | if (sinfo.filled & STATION_INFO_TX_BITRATE) | ||
695 | data[i] = 100000 * | ||
696 | cfg80211_calculate_bitrate(&sinfo.txrate); | ||
697 | i++; | ||
698 | if (sinfo.filled & STATION_INFO_RX_BITRATE) | ||
699 | data[i] = 100000 * | ||
700 | cfg80211_calculate_bitrate(&sinfo.rxrate); | ||
701 | i++; | ||
702 | |||
703 | if (sinfo.filled & STATION_INFO_SIGNAL_AVG) | ||
704 | data[i] = (u8)sinfo.signal_avg; | ||
705 | i++; | ||
706 | } else { | ||
707 | list_for_each_entry(sta, &local->sta_list, list) { | ||
708 | /* Make sure this station belongs to the proper dev */ | ||
709 | if (sta->sdata->dev != dev) | ||
710 | continue; | ||
711 | |||
712 | sinfo.filled = 0; | ||
713 | sta_set_sinfo(sta, &sinfo); | ||
714 | i = 0; | ||
715 | ADD_STA_STATS(sta); | ||
716 | } | ||
717 | } | ||
718 | |||
719 | do_survey: | ||
720 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; | ||
721 | /* Get survey stats for current channel */ | ||
722 | survey.filled = 0; | ||
723 | |||
724 | rcu_read_lock(); | ||
725 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
726 | if (chanctx_conf) | ||
727 | channel = chanctx_conf->def.chan; | ||
728 | else | ||
729 | channel = NULL; | ||
730 | rcu_read_unlock(); | ||
731 | |||
732 | if (channel) { | ||
733 | q = 0; | ||
734 | do { | ||
735 | survey.filled = 0; | ||
736 | if (drv_get_survey(local, q, &survey) != 0) { | ||
737 | survey.filled = 0; | ||
738 | break; | ||
739 | } | ||
740 | q++; | ||
741 | } while (channel != survey.channel); | ||
742 | } | ||
743 | |||
744 | if (survey.filled) | ||
745 | data[i++] = survey.channel->center_freq; | ||
746 | else | ||
747 | data[i++] = 0; | ||
748 | if (survey.filled & SURVEY_INFO_NOISE_DBM) | ||
749 | data[i++] = (u8)survey.noise; | ||
750 | else | ||
751 | data[i++] = -1LL; | ||
752 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME) | ||
753 | data[i++] = survey.channel_time; | ||
754 | else | ||
755 | data[i++] = -1LL; | ||
756 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) | ||
757 | data[i++] = survey.channel_time_busy; | ||
758 | else | ||
759 | data[i++] = -1LL; | ||
760 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) | ||
761 | data[i++] = survey.channel_time_ext_busy; | ||
762 | else | ||
763 | data[i++] = -1LL; | ||
764 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) | ||
765 | data[i++] = survey.channel_time_rx; | ||
766 | else | ||
767 | data[i++] = -1LL; | ||
768 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) | ||
769 | data[i++] = survey.channel_time_tx; | ||
770 | else | ||
771 | data[i++] = -1LL; | ||
772 | |||
773 | mutex_unlock(&local->sta_mtx); | ||
774 | |||
775 | if (WARN_ON(i != STA_STATS_LEN)) | ||
776 | return; | ||
777 | |||
778 | drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); | ||
779 | } | ||
780 | |||
781 | static void ieee80211_get_et_strings(struct wiphy *wiphy, | ||
782 | struct net_device *dev, | ||
783 | u32 sset, u8 *data) | ||
784 | { | ||
785 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
786 | int sz_sta_stats = 0; | ||
787 | |||
788 | if (sset == ETH_SS_STATS) { | ||
789 | sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); | ||
790 | memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); | ||
791 | } | ||
792 | drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); | ||
793 | } | ||
794 | |||
795 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | 471 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, |
796 | int idx, u8 *mac, struct station_info *sinfo) | 472 | int idx, u8 *mac, struct station_info *sinfo) |
797 | { | 473 | { |
@@ -878,7 +554,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | |||
878 | } | 554 | } |
879 | 555 | ||
880 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | 556 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, |
881 | const u8 *resp, size_t resp_len) | 557 | const u8 *resp, size_t resp_len, |
558 | const struct ieee80211_csa_settings *csa) | ||
882 | { | 559 | { |
883 | struct probe_resp *new, *old; | 560 | struct probe_resp *new, *old; |
884 | 561 | ||
@@ -894,6 +571,11 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
894 | new->len = resp_len; | 571 | new->len = resp_len; |
895 | memcpy(new->data, resp, resp_len); | 572 | memcpy(new->data, resp, resp_len); |
896 | 573 | ||
574 | if (csa) | ||
575 | memcpy(new->csa_counter_offsets, csa->counter_offsets_presp, | ||
576 | csa->n_counter_offsets_presp * | ||
577 | sizeof(new->csa_counter_offsets[0])); | ||
578 | |||
897 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); | 579 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); |
898 | if (old) | 580 | if (old) |
899 | kfree_rcu(old, rcu_head); | 581 | kfree_rcu(old, rcu_head); |
@@ -902,7 +584,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
902 | } | 584 | } |
903 | 585 | ||
904 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | 586 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, |
905 | struct cfg80211_beacon_data *params) | 587 | struct cfg80211_beacon_data *params, |
588 | const struct ieee80211_csa_settings *csa) | ||
906 | { | 589 | { |
907 | struct beacon_data *new, *old; | 590 | struct beacon_data *new, *old; |
908 | int new_head_len, new_tail_len; | 591 | int new_head_len, new_tail_len; |
@@ -946,6 +629,13 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
946 | new->head_len = new_head_len; | 629 | new->head_len = new_head_len; |
947 | new->tail_len = new_tail_len; | 630 | new->tail_len = new_tail_len; |
948 | 631 | ||
632 | if (csa) { | ||
633 | new->csa_current_counter = csa->count; | ||
634 | memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon, | ||
635 | csa->n_counter_offsets_beacon * | ||
636 | sizeof(new->csa_counter_offsets[0])); | ||
637 | } | ||
638 | |||
949 | /* copy in head */ | 639 | /* copy in head */ |
950 | if (params->head) | 640 | if (params->head) |
951 | memcpy(new->head, params->head, new_head_len); | 641 | memcpy(new->head, params->head, new_head_len); |
@@ -960,7 +650,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
960 | memcpy(new->tail, old->tail, new_tail_len); | 650 | memcpy(new->tail, old->tail, new_tail_len); |
961 | 651 | ||
962 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, | 652 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, |
963 | params->probe_resp_len); | 653 | params->probe_resp_len, csa); |
964 | if (err < 0) | 654 | if (err < 0) |
965 | return err; | 655 | return err; |
966 | if (err == 0) | 656 | if (err == 0) |
@@ -1045,7 +735,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
1045 | sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= | 735 | sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= |
1046 | IEEE80211_P2P_OPPPS_ENABLE_BIT; | 736 | IEEE80211_P2P_OPPPS_ENABLE_BIT; |
1047 | 737 | ||
1048 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon); | 738 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); |
1049 | if (err < 0) { | 739 | if (err < 0) { |
1050 | ieee80211_vif_release_channel(sdata); | 740 | ieee80211_vif_release_channel(sdata); |
1051 | return err; | 741 | return err; |
@@ -1093,38 +783,13 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
1093 | if (!old) | 783 | if (!old) |
1094 | return -ENOENT; | 784 | return -ENOENT; |
1095 | 785 | ||
1096 | err = ieee80211_assign_beacon(sdata, params); | 786 | err = ieee80211_assign_beacon(sdata, params, NULL); |
1097 | if (err < 0) | 787 | if (err < 0) |
1098 | return err; | 788 | return err; |
1099 | ieee80211_bss_info_change_notify(sdata, err); | 789 | ieee80211_bss_info_change_notify(sdata, err); |
1100 | return 0; | 790 | return 0; |
1101 | } | 791 | } |
1102 | 792 | ||
1103 | bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local) | ||
1104 | { | ||
1105 | struct ieee80211_sub_if_data *sdata; | ||
1106 | |||
1107 | lockdep_assert_held(&local->mtx); | ||
1108 | |||
1109 | rcu_read_lock(); | ||
1110 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
1111 | if (!ieee80211_sdata_running(sdata)) | ||
1112 | continue; | ||
1113 | |||
1114 | if (!sdata->vif.csa_active) | ||
1115 | continue; | ||
1116 | |||
1117 | if (!sdata->csa_block_tx) | ||
1118 | continue; | ||
1119 | |||
1120 | rcu_read_unlock(); | ||
1121 | return true; | ||
1122 | } | ||
1123 | rcu_read_unlock(); | ||
1124 | |||
1125 | return false; | ||
1126 | } | ||
1127 | |||
1128 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | 793 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) |
1129 | { | 794 | { |
1130 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 795 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -1144,10 +809,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1144 | /* abort any running channel switch */ | 809 | /* abort any running channel switch */ |
1145 | mutex_lock(&local->mtx); | 810 | mutex_lock(&local->mtx); |
1146 | sdata->vif.csa_active = false; | 811 | sdata->vif.csa_active = false; |
1147 | if (!ieee80211_csa_needs_block_tx(local)) | 812 | if (sdata->csa_block_tx) { |
1148 | ieee80211_wake_queues_by_reason(&local->hw, | 813 | ieee80211_wake_vif_queues(local, sdata, |
1149 | IEEE80211_MAX_QUEUE_MAP, | 814 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1150 | IEEE80211_QUEUE_STOP_REASON_CSA); | 815 | sdata->csa_block_tx = false; |
816 | } | ||
817 | |||
1151 | mutex_unlock(&local->mtx); | 818 | mutex_unlock(&local->mtx); |
1152 | 819 | ||
1153 | kfree(sdata->u.ap.next_beacon); | 820 | kfree(sdata->u.ap.next_beacon); |
@@ -1330,9 +997,12 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1330 | } | 997 | } |
1331 | } | 998 | } |
1332 | 999 | ||
1333 | ret = sta_apply_auth_flags(local, sta, mask, set); | 1000 | /* auth flags will be set later for TDLS stations */ |
1334 | if (ret) | 1001 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { |
1335 | return ret; | 1002 | ret = sta_apply_auth_flags(local, sta, mask, set); |
1003 | if (ret) | ||
1004 | return ret; | ||
1005 | } | ||
1336 | 1006 | ||
1337 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { | 1007 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { |
1338 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) | 1008 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) |
@@ -1469,6 +1139,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1469 | #endif | 1139 | #endif |
1470 | } | 1140 | } |
1471 | 1141 | ||
1142 | /* set the STA state after all sta info from usermode has been set */ | ||
1143 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
1144 | ret = sta_apply_auth_flags(local, sta, mask, set); | ||
1145 | if (ret) | ||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1472 | return 0; | 1149 | return 0; |
1473 | } | 1150 | } |
1474 | 1151 | ||
@@ -3076,7 +2753,8 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
3076 | 2753 | ||
3077 | switch (sdata->vif.type) { | 2754 | switch (sdata->vif.type) { |
3078 | case NL80211_IFTYPE_AP: | 2755 | case NL80211_IFTYPE_AP: |
3079 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 2756 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, |
2757 | NULL); | ||
3080 | kfree(sdata->u.ap.next_beacon); | 2758 | kfree(sdata->u.ap.next_beacon); |
3081 | sdata->u.ap.next_beacon = NULL; | 2759 | sdata->u.ap.next_beacon = NULL; |
3082 | 2760 | ||
@@ -3114,17 +2792,35 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
3114 | 2792 | ||
3115 | sdata_assert_lock(sdata); | 2793 | sdata_assert_lock(sdata); |
3116 | lockdep_assert_held(&local->mtx); | 2794 | lockdep_assert_held(&local->mtx); |
2795 | lockdep_assert_held(&local->chanctx_mtx); | ||
3117 | 2796 | ||
3118 | sdata->radar_required = sdata->csa_radar_required; | 2797 | /* |
3119 | err = ieee80211_vif_change_channel(sdata, &changed); | 2798 | * using reservation isn't immediate as it may be deferred until later |
3120 | if (err < 0) | 2799 | * with multi-vif. once reservation is complete it will re-schedule the |
3121 | return err; | 2800 | * work with no reserved_chanctx so verify chandef to check if it |
2801 | * completed successfully | ||
2802 | */ | ||
3122 | 2803 | ||
3123 | if (!local->use_chanctx) { | 2804 | if (sdata->reserved_chanctx) { |
3124 | local->_oper_chandef = sdata->csa_chandef; | 2805 | /* |
3125 | ieee80211_hw_config(local, 0); | 2806 | * with multi-vif csa driver may call ieee80211_csa_finish() |
2807 | * many times while waiting for other interfaces to use their | ||
2808 | * reservations | ||
2809 | */ | ||
2810 | if (sdata->reserved_ready) | ||
2811 | return 0; | ||
2812 | |||
2813 | err = ieee80211_vif_use_reserved_context(sdata); | ||
2814 | if (err) | ||
2815 | return err; | ||
2816 | |||
2817 | return 0; | ||
3126 | } | 2818 | } |
3127 | 2819 | ||
2820 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | ||
2821 | &sdata->csa_chandef)) | ||
2822 | return -EINVAL; | ||
2823 | |||
3128 | sdata->vif.csa_active = false; | 2824 | sdata->vif.csa_active = false; |
3129 | 2825 | ||
3130 | err = ieee80211_set_after_csa_beacon(sdata, &changed); | 2826 | err = ieee80211_set_after_csa_beacon(sdata, &changed); |
@@ -3134,10 +2830,11 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
3134 | ieee80211_bss_info_change_notify(sdata, changed); | 2830 | ieee80211_bss_info_change_notify(sdata, changed); |
3135 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | 2831 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); |
3136 | 2832 | ||
3137 | if (!ieee80211_csa_needs_block_tx(local)) | 2833 | if (sdata->csa_block_tx) { |
3138 | ieee80211_wake_queues_by_reason(&local->hw, | 2834 | ieee80211_wake_vif_queues(local, sdata, |
3139 | IEEE80211_MAX_QUEUE_MAP, | 2835 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3140 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2836 | sdata->csa_block_tx = false; |
2837 | } | ||
3141 | 2838 | ||
3142 | return 0; | 2839 | return 0; |
3143 | } | 2840 | } |
@@ -3160,6 +2857,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
3160 | 2857 | ||
3161 | sdata_lock(sdata); | 2858 | sdata_lock(sdata); |
3162 | mutex_lock(&local->mtx); | 2859 | mutex_lock(&local->mtx); |
2860 | mutex_lock(&local->chanctx_mtx); | ||
3163 | 2861 | ||
3164 | /* AP might have been stopped while waiting for the lock. */ | 2862 | /* AP might have been stopped while waiting for the lock. */ |
3165 | if (!sdata->vif.csa_active) | 2863 | if (!sdata->vif.csa_active) |
@@ -3171,6 +2869,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
3171 | ieee80211_csa_finalize(sdata); | 2869 | ieee80211_csa_finalize(sdata); |
3172 | 2870 | ||
3173 | unlock: | 2871 | unlock: |
2872 | mutex_unlock(&local->chanctx_mtx); | ||
3174 | mutex_unlock(&local->mtx); | 2873 | mutex_unlock(&local->mtx); |
3175 | sdata_unlock(sdata); | 2874 | sdata_unlock(sdata); |
3176 | } | 2875 | } |
@@ -3179,6 +2878,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
3179 | struct cfg80211_csa_settings *params, | 2878 | struct cfg80211_csa_settings *params, |
3180 | u32 *changed) | 2879 | u32 *changed) |
3181 | { | 2880 | { |
2881 | struct ieee80211_csa_settings csa = {}; | ||
3182 | int err; | 2882 | int err; |
3183 | 2883 | ||
3184 | switch (sdata->vif.type) { | 2884 | switch (sdata->vif.type) { |
@@ -3213,20 +2913,13 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
3213 | IEEE80211_MAX_CSA_COUNTERS_NUM)) | 2913 | IEEE80211_MAX_CSA_COUNTERS_NUM)) |
3214 | return -EINVAL; | 2914 | return -EINVAL; |
3215 | 2915 | ||
3216 | /* make sure we don't have garbage in other counters */ | 2916 | csa.counter_offsets_beacon = params->counter_offsets_beacon; |
3217 | memset(sdata->csa_counter_offset_beacon, 0, | 2917 | csa.counter_offsets_presp = params->counter_offsets_presp; |
3218 | sizeof(sdata->csa_counter_offset_beacon)); | 2918 | csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon; |
3219 | memset(sdata->csa_counter_offset_presp, 0, | 2919 | csa.n_counter_offsets_presp = params->n_counter_offsets_presp; |
3220 | sizeof(sdata->csa_counter_offset_presp)); | 2920 | csa.count = params->count; |
3221 | |||
3222 | memcpy(sdata->csa_counter_offset_beacon, | ||
3223 | params->counter_offsets_beacon, | ||
3224 | params->n_counter_offsets_beacon * sizeof(u16)); | ||
3225 | memcpy(sdata->csa_counter_offset_presp, | ||
3226 | params->counter_offsets_presp, | ||
3227 | params->n_counter_offsets_presp * sizeof(u16)); | ||
3228 | 2921 | ||
3229 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | 2922 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); |
3230 | if (err < 0) { | 2923 | if (err < 0) { |
3231 | kfree(sdata->u.ap.next_beacon); | 2924 | kfree(sdata->u.ap.next_beacon); |
3232 | return err; | 2925 | return err; |
@@ -3322,7 +3015,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3322 | struct ieee80211_local *local = sdata->local; | 3015 | struct ieee80211_local *local = sdata->local; |
3323 | struct ieee80211_chanctx_conf *conf; | 3016 | struct ieee80211_chanctx_conf *conf; |
3324 | struct ieee80211_chanctx *chanctx; | 3017 | struct ieee80211_chanctx *chanctx; |
3325 | int err, num_chanctx, changed = 0; | 3018 | int err, changed = 0; |
3326 | 3019 | ||
3327 | sdata_assert_lock(sdata); | 3020 | sdata_assert_lock(sdata); |
3328 | lockdep_assert_held(&local->mtx); | 3021 | lockdep_assert_held(&local->mtx); |
@@ -3337,46 +3030,50 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3337 | &sdata->vif.bss_conf.chandef)) | 3030 | &sdata->vif.bss_conf.chandef)) |
3338 | return -EINVAL; | 3031 | return -EINVAL; |
3339 | 3032 | ||
3033 | /* don't allow another channel switch if one is already active. */ | ||
3034 | if (sdata->vif.csa_active) | ||
3035 | return -EBUSY; | ||
3036 | |||
3340 | mutex_lock(&local->chanctx_mtx); | 3037 | mutex_lock(&local->chanctx_mtx); |
3341 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | 3038 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
3342 | lockdep_is_held(&local->chanctx_mtx)); | 3039 | lockdep_is_held(&local->chanctx_mtx)); |
3343 | if (!conf) { | 3040 | if (!conf) { |
3344 | mutex_unlock(&local->chanctx_mtx); | 3041 | err = -EBUSY; |
3345 | return -EBUSY; | 3042 | goto out; |
3346 | } | 3043 | } |
3347 | 3044 | ||
3348 | /* don't handle for multi-VIF cases */ | ||
3349 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 3045 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
3350 | if (ieee80211_chanctx_refcount(local, chanctx) > 1) { | 3046 | if (!chanctx) { |
3351 | mutex_unlock(&local->chanctx_mtx); | 3047 | err = -EBUSY; |
3352 | return -EBUSY; | 3048 | goto out; |
3353 | } | 3049 | } |
3354 | num_chanctx = 0; | ||
3355 | list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) | ||
3356 | num_chanctx++; | ||
3357 | mutex_unlock(&local->chanctx_mtx); | ||
3358 | 3050 | ||
3359 | if (num_chanctx > 1) | 3051 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, |
3360 | return -EBUSY; | 3052 | chanctx->mode, |
3053 | params->radar_required); | ||
3054 | if (err) | ||
3055 | goto out; | ||
3361 | 3056 | ||
3362 | /* don't allow another channel switch if one is already active. */ | 3057 | /* if reservation is invalid then this will fail */ |
3363 | if (sdata->vif.csa_active) | 3058 | err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); |
3364 | return -EBUSY; | 3059 | if (err) { |
3060 | ieee80211_vif_unreserve_chanctx(sdata); | ||
3061 | goto out; | ||
3062 | } | ||
3365 | 3063 | ||
3366 | err = ieee80211_set_csa_beacon(sdata, params, &changed); | 3064 | err = ieee80211_set_csa_beacon(sdata, params, &changed); |
3367 | if (err) | 3065 | if (err) { |
3368 | return err; | 3066 | ieee80211_vif_unreserve_chanctx(sdata); |
3067 | goto out; | ||
3068 | } | ||
3369 | 3069 | ||
3370 | sdata->csa_radar_required = params->radar_required; | ||
3371 | sdata->csa_chandef = params->chandef; | 3070 | sdata->csa_chandef = params->chandef; |
3372 | sdata->csa_block_tx = params->block_tx; | 3071 | sdata->csa_block_tx = params->block_tx; |
3373 | sdata->csa_current_counter = params->count; | ||
3374 | sdata->vif.csa_active = true; | 3072 | sdata->vif.csa_active = true; |
3375 | 3073 | ||
3376 | if (sdata->csa_block_tx) | 3074 | if (sdata->csa_block_tx) |
3377 | ieee80211_stop_queues_by_reason(&local->hw, | 3075 | ieee80211_stop_vif_queues(local, sdata, |
3378 | IEEE80211_MAX_QUEUE_MAP, | 3076 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3379 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
3380 | 3077 | ||
3381 | if (changed) { | 3078 | if (changed) { |
3382 | ieee80211_bss_info_change_notify(sdata, changed); | 3079 | ieee80211_bss_info_change_notify(sdata, changed); |
@@ -3386,7 +3083,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3386 | ieee80211_csa_finalize(sdata); | 3083 | ieee80211_csa_finalize(sdata); |
3387 | } | 3084 | } |
3388 | 3085 | ||
3389 | return 0; | 3086 | out: |
3087 | mutex_unlock(&local->chanctx_mtx); | ||
3088 | return err; | ||
3390 | } | 3089 | } |
3391 | 3090 | ||
3392 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 3091 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |
@@ -3518,10 +3217,23 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
3518 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && | 3217 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && |
3519 | params->n_csa_offsets) { | 3218 | params->n_csa_offsets) { |
3520 | int i; | 3219 | int i; |
3521 | u8 c = sdata->csa_current_counter; | 3220 | struct beacon_data *beacon = NULL; |
3522 | 3221 | ||
3523 | for (i = 0; i < params->n_csa_offsets; i++) | 3222 | rcu_read_lock(); |
3524 | data[params->csa_offsets[i]] = c; | 3223 | |
3224 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
3225 | beacon = rcu_dereference(sdata->u.ap.beacon); | ||
3226 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
3227 | beacon = rcu_dereference(sdata->u.ibss.presp); | ||
3228 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
3229 | beacon = rcu_dereference(sdata->u.mesh.beacon); | ||
3230 | |||
3231 | if (beacon) | ||
3232 | for (i = 0; i < params->n_csa_offsets; i++) | ||
3233 | data[params->csa_offsets[i]] = | ||
3234 | beacon->csa_current_counter; | ||
3235 | |||
3236 | rcu_read_unlock(); | ||
3525 | } | 3237 | } |
3526 | 3238 | ||
3527 | IEEE80211_SKB_CB(skb)->flags = flags; | 3239 | IEEE80211_SKB_CB(skb)->flags = flags; |
@@ -3601,21 +3313,6 @@ static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) | |||
3601 | return drv_get_antenna(local, tx_ant, rx_ant); | 3313 | return drv_get_antenna(local, tx_ant, rx_ant); |
3602 | } | 3314 | } |
3603 | 3315 | ||
3604 | static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) | ||
3605 | { | ||
3606 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
3607 | |||
3608 | return drv_set_ringparam(local, tx, rx); | ||
3609 | } | ||
3610 | |||
3611 | static void ieee80211_get_ringparam(struct wiphy *wiphy, | ||
3612 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
3613 | { | ||
3614 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
3615 | |||
3616 | drv_get_ringparam(local, tx, tx_max, rx, rx_max); | ||
3617 | } | ||
3618 | |||
3619 | static int ieee80211_set_rekey_data(struct wiphy *wiphy, | 3316 | static int ieee80211_set_rekey_data(struct wiphy *wiphy, |
3620 | struct net_device *dev, | 3317 | struct net_device *dev, |
3621 | struct cfg80211_gtk_rekey_data *data) | 3318 | struct cfg80211_gtk_rekey_data *data) |
@@ -3847,8 +3544,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3847 | .mgmt_frame_register = ieee80211_mgmt_frame_register, | 3544 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
3848 | .set_antenna = ieee80211_set_antenna, | 3545 | .set_antenna = ieee80211_set_antenna, |
3849 | .get_antenna = ieee80211_get_antenna, | 3546 | .get_antenna = ieee80211_get_antenna, |
3850 | .set_ringparam = ieee80211_set_ringparam, | ||
3851 | .get_ringparam = ieee80211_get_ringparam, | ||
3852 | .set_rekey_data = ieee80211_set_rekey_data, | 3547 | .set_rekey_data = ieee80211_set_rekey_data, |
3853 | .tdls_oper = ieee80211_tdls_oper, | 3548 | .tdls_oper = ieee80211_tdls_oper, |
3854 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3549 | .tdls_mgmt = ieee80211_tdls_mgmt, |
@@ -3857,9 +3552,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3857 | #ifdef CONFIG_PM | 3552 | #ifdef CONFIG_PM |
3858 | .set_wakeup = ieee80211_set_wakeup, | 3553 | .set_wakeup = ieee80211_set_wakeup, |
3859 | #endif | 3554 | #endif |
3860 | .get_et_sset_count = ieee80211_get_et_sset_count, | ||
3861 | .get_et_stats = ieee80211_get_et_stats, | ||
3862 | .get_et_strings = ieee80211_get_et_strings, | ||
3863 | .get_channel = ieee80211_cfg_get_channel, | 3555 | .get_channel = ieee80211_cfg_get_channel, |
3864 | .start_radar_detection = ieee80211_start_radar_detection, | 3556 | .start_radar_detection = ieee80211_start_radar_detection, |
3865 | .channel_switch = ieee80211_channel_switch, | 3557 | .channel_switch = ieee80211_channel_switch, |