diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 281 |
1 files changed, 235 insertions, 46 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 93af0f1c9d99..0d166e766dad 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -775,11 +775,30 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
775 | WLAN_EID_QOS_CAPA, | 775 | WLAN_EID_QOS_CAPA, |
776 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | 776 | WLAN_EID_RRM_ENABLED_CAPABILITIES, |
777 | WLAN_EID_MOBILITY_DOMAIN, | 777 | WLAN_EID_MOBILITY_DOMAIN, |
778 | WLAN_EID_FAST_BSS_TRANSITION, /* reassoc only */ | ||
779 | WLAN_EID_RIC_DATA, /* reassoc only */ | ||
778 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | 780 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, |
779 | }; | 781 | }; |
780 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | 782 | static const u8 after_ric[] = { |
781 | before_ht, ARRAY_SIZE(before_ht), | 783 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, |
782 | offset); | 784 | WLAN_EID_HT_CAPABILITY, |
785 | WLAN_EID_BSS_COEX_2040, | ||
786 | WLAN_EID_EXT_CAPABILITY, | ||
787 | WLAN_EID_QOS_TRAFFIC_CAPA, | ||
788 | WLAN_EID_TIM_BCAST_REQ, | ||
789 | WLAN_EID_INTERWORKING, | ||
790 | /* 60GHz doesn't happen right now */ | ||
791 | WLAN_EID_VHT_CAPABILITY, | ||
792 | WLAN_EID_OPMODE_NOTIF, | ||
793 | }; | ||
794 | |||
795 | noffset = ieee80211_ie_split_ric(assoc_data->ie, | ||
796 | assoc_data->ie_len, | ||
797 | before_ht, | ||
798 | ARRAY_SIZE(before_ht), | ||
799 | after_ric, | ||
800 | ARRAY_SIZE(after_ric), | ||
801 | offset); | ||
783 | pos = skb_put(skb, noffset - offset); | 802 | pos = skb_put(skb, noffset - offset); |
784 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 803 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
785 | offset = noffset; | 804 | offset = noffset; |
@@ -813,6 +832,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
813 | WLAN_EID_TIM_BCAST_REQ, | 832 | WLAN_EID_TIM_BCAST_REQ, |
814 | WLAN_EID_INTERWORKING, | 833 | WLAN_EID_INTERWORKING, |
815 | }; | 834 | }; |
835 | |||
836 | /* RIC already taken above, so no need to handle here anymore */ | ||
816 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | 837 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, |
817 | before_vht, ARRAY_SIZE(before_vht), | 838 | before_vht, ARRAY_SIZE(before_vht), |
818 | offset); | 839 | offset); |
@@ -1001,14 +1022,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1001 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 1022 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
1002 | ifmgd->associated->channel = sdata->csa_chandef.chan; | 1023 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
1003 | 1024 | ||
1004 | sdata->vif.csa_active = false; | 1025 | ifmgd->csa_waiting_bcn = true; |
1005 | |||
1006 | /* XXX: wait for a beacon first? */ | ||
1007 | if (sdata->csa_block_tx) { | ||
1008 | ieee80211_wake_vif_queues(local, sdata, | ||
1009 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1010 | sdata->csa_block_tx = false; | ||
1011 | } | ||
1012 | 1026 | ||
1013 | ieee80211_sta_reset_beacon_monitor(sdata); | 1027 | ieee80211_sta_reset_beacon_monitor(sdata); |
1014 | ieee80211_sta_reset_conn_monitor(sdata); | 1028 | ieee80211_sta_reset_conn_monitor(sdata); |
@@ -1019,6 +1033,35 @@ out: | |||
1019 | sdata_unlock(sdata); | 1033 | sdata_unlock(sdata); |
1020 | } | 1034 | } |
1021 | 1035 | ||
1036 | static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) | ||
1037 | { | ||
1038 | struct ieee80211_local *local = sdata->local; | ||
1039 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1040 | int ret; | ||
1041 | |||
1042 | sdata_assert_lock(sdata); | ||
1043 | |||
1044 | WARN_ON(!sdata->vif.csa_active); | ||
1045 | |||
1046 | if (sdata->csa_block_tx) { | ||
1047 | ieee80211_wake_vif_queues(local, sdata, | ||
1048 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1049 | sdata->csa_block_tx = false; | ||
1050 | } | ||
1051 | |||
1052 | sdata->vif.csa_active = false; | ||
1053 | ifmgd->csa_waiting_bcn = false; | ||
1054 | |||
1055 | ret = drv_post_channel_switch(sdata); | ||
1056 | if (ret) { | ||
1057 | sdata_info(sdata, | ||
1058 | "driver post channel switch failed, disconnecting\n"); | ||
1059 | ieee80211_queue_work(&local->hw, | ||
1060 | &ifmgd->csa_connection_drop_work); | ||
1061 | return; | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1022 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | 1065 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) |
1023 | { | 1066 | { |
1024 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1067 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
@@ -1046,7 +1089,8 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
1046 | 1089 | ||
1047 | static void | 1090 | static void |
1048 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1091 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1049 | u64 timestamp, struct ieee802_11_elems *elems, | 1092 | u64 timestamp, u32 device_timestamp, |
1093 | struct ieee802_11_elems *elems, | ||
1050 | bool beacon) | 1094 | bool beacon) |
1051 | { | 1095 | { |
1052 | struct ieee80211_local *local = sdata->local; | 1096 | struct ieee80211_local *local = sdata->local; |
@@ -1056,6 +1100,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1056 | struct ieee80211_chanctx *chanctx; | 1100 | struct ieee80211_chanctx *chanctx; |
1057 | enum ieee80211_band current_band; | 1101 | enum ieee80211_band current_band; |
1058 | struct ieee80211_csa_ie csa_ie; | 1102 | struct ieee80211_csa_ie csa_ie; |
1103 | struct ieee80211_channel_switch ch_switch; | ||
1059 | int res; | 1104 | int res; |
1060 | 1105 | ||
1061 | sdata_assert_lock(sdata); | 1106 | sdata_assert_lock(sdata); |
@@ -1110,21 +1155,31 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1110 | 1155 | ||
1111 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 1156 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
1112 | 1157 | ||
1113 | if (local->use_chanctx) { | 1158 | if (local->use_chanctx && |
1114 | u32 num_chanctx = 0; | 1159 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { |
1115 | list_for_each_entry(chanctx, &local->chanctx_list, list) | 1160 | sdata_info(sdata, |
1116 | num_chanctx++; | 1161 | "driver doesn't support chan-switch with channel contexts\n"); |
1162 | ieee80211_queue_work(&local->hw, | ||
1163 | &ifmgd->csa_connection_drop_work); | ||
1164 | mutex_unlock(&local->chanctx_mtx); | ||
1165 | mutex_unlock(&local->mtx); | ||
1166 | return; | ||
1167 | } | ||
1117 | 1168 | ||
1118 | if (num_chanctx > 1 || | 1169 | ch_switch.timestamp = timestamp; |
1119 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { | 1170 | ch_switch.device_timestamp = device_timestamp; |
1120 | sdata_info(sdata, | 1171 | ch_switch.block_tx = csa_ie.mode; |
1121 | "not handling chan-switch with channel contexts\n"); | 1172 | ch_switch.chandef = csa_ie.chandef; |
1122 | ieee80211_queue_work(&local->hw, | 1173 | ch_switch.count = csa_ie.count; |
1123 | &ifmgd->csa_connection_drop_work); | 1174 | |
1124 | mutex_unlock(&local->chanctx_mtx); | 1175 | if (drv_pre_channel_switch(sdata, &ch_switch)) { |
1125 | mutex_unlock(&local->mtx); | 1176 | sdata_info(sdata, |
1126 | return; | 1177 | "preparing for channel switch failed, disconnecting\n"); |
1127 | } | 1178 | ieee80211_queue_work(&local->hw, |
1179 | &ifmgd->csa_connection_drop_work); | ||
1180 | mutex_unlock(&local->chanctx_mtx); | ||
1181 | mutex_unlock(&local->mtx); | ||
1182 | return; | ||
1128 | } | 1183 | } |
1129 | 1184 | ||
1130 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, | 1185 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
@@ -1152,14 +1207,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1152 | 1207 | ||
1153 | if (local->ops->channel_switch) { | 1208 | if (local->ops->channel_switch) { |
1154 | /* use driver's channel switch callback */ | 1209 | /* use driver's channel switch callback */ |
1155 | struct ieee80211_channel_switch ch_switch = { | 1210 | drv_channel_switch(local, sdata, &ch_switch); |
1156 | .timestamp = timestamp, | ||
1157 | .block_tx = csa_ie.mode, | ||
1158 | .chandef = csa_ie.chandef, | ||
1159 | .count = csa_ie.count, | ||
1160 | }; | ||
1161 | |||
1162 | drv_channel_switch(local, &ch_switch); | ||
1163 | return; | 1211 | return; |
1164 | } | 1212 | } |
1165 | 1213 | ||
@@ -1580,6 +1628,95 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) | |||
1580 | mutex_unlock(&sdata->local->mtx); | 1628 | mutex_unlock(&sdata->local->mtx); |
1581 | } | 1629 | } |
1582 | 1630 | ||
1631 | static bool | ||
1632 | __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | ||
1633 | { | ||
1634 | struct ieee80211_local *local = sdata->local; | ||
1635 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1636 | bool ret; | ||
1637 | int ac; | ||
1638 | |||
1639 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
1640 | return false; | ||
1641 | |||
1642 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
1643 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
1644 | int non_acm_ac; | ||
1645 | unsigned long now = jiffies; | ||
1646 | |||
1647 | if (tx_tspec->action == TX_TSPEC_ACTION_NONE && | ||
1648 | tx_tspec->admitted_time && | ||
1649 | time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
1650 | tx_tspec->consumed_tx_time = 0; | ||
1651 | tx_tspec->time_slice_start = now; | ||
1652 | |||
1653 | if (tx_tspec->downgraded) | ||
1654 | tx_tspec->action = | ||
1655 | TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
1656 | } | ||
1657 | |||
1658 | switch (tx_tspec->action) { | ||
1659 | case TX_TSPEC_ACTION_STOP_DOWNGRADE: | ||
1660 | /* take the original parameters */ | ||
1661 | if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac])) | ||
1662 | sdata_err(sdata, | ||
1663 | "failed to set TX queue parameters for queue %d\n", | ||
1664 | ac); | ||
1665 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1666 | tx_tspec->downgraded = false; | ||
1667 | ret = true; | ||
1668 | break; | ||
1669 | case TX_TSPEC_ACTION_DOWNGRADE: | ||
1670 | if (time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
1671 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1672 | ret = true; | ||
1673 | break; | ||
1674 | } | ||
1675 | /* downgrade next lower non-ACM AC */ | ||
1676 | for (non_acm_ac = ac + 1; | ||
1677 | non_acm_ac < IEEE80211_NUM_ACS; | ||
1678 | non_acm_ac++) | ||
1679 | if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac))) | ||
1680 | break; | ||
1681 | /* The loop will result in using BK even if it requires | ||
1682 | * admission control, such configuration makes no sense | ||
1683 | * and we have to transmit somehow - the AC selection | ||
1684 | * does the same thing. | ||
1685 | */ | ||
1686 | if (drv_conf_tx(local, sdata, ac, | ||
1687 | &sdata->tx_conf[non_acm_ac])) | ||
1688 | sdata_err(sdata, | ||
1689 | "failed to set TX queue parameters for queue %d\n", | ||
1690 | ac); | ||
1691 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1692 | ret = true; | ||
1693 | schedule_delayed_work(&ifmgd->tx_tspec_wk, | ||
1694 | tx_tspec->time_slice_start + HZ - now + 1); | ||
1695 | break; | ||
1696 | case TX_TSPEC_ACTION_NONE: | ||
1697 | /* nothing now */ | ||
1698 | break; | ||
1699 | } | ||
1700 | } | ||
1701 | |||
1702 | return ret; | ||
1703 | } | ||
1704 | |||
1705 | void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | ||
1706 | { | ||
1707 | if (__ieee80211_sta_handle_tspec_ac_params(sdata)) | ||
1708 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); | ||
1709 | } | ||
1710 | |||
1711 | static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work) | ||
1712 | { | ||
1713 | struct ieee80211_sub_if_data *sdata; | ||
1714 | |||
1715 | sdata = container_of(work, struct ieee80211_sub_if_data, | ||
1716 | u.mgd.tx_tspec_wk.work); | ||
1717 | ieee80211_sta_handle_tspec_ac_params(sdata); | ||
1718 | } | ||
1719 | |||
1583 | /* MLME */ | 1720 | /* MLME */ |
1584 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | 1721 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, |
1585 | struct ieee80211_sub_if_data *sdata, | 1722 | struct ieee80211_sub_if_data *sdata, |
@@ -1664,12 +1801,14 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
1664 | params.uapsd = uapsd; | 1801 | params.uapsd = uapsd; |
1665 | 1802 | ||
1666 | mlme_dbg(sdata, | 1803 | mlme_dbg(sdata, |
1667 | "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", | 1804 | "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n", |
1668 | queue, aci, acm, | 1805 | queue, aci, acm, |
1669 | params.aifs, params.cw_min, params.cw_max, | 1806 | params.aifs, params.cw_min, params.cw_max, |
1670 | params.txop, params.uapsd); | 1807 | params.txop, params.uapsd, |
1808 | ifmgd->tx_tspec[queue].downgraded); | ||
1671 | sdata->tx_conf[queue] = params; | 1809 | sdata->tx_conf[queue] = params; |
1672 | if (drv_conf_tx(local, sdata, queue, ¶ms)) | 1810 | if (!ifmgd->tx_tspec[queue].downgraded && |
1811 | drv_conf_tx(local, sdata, queue, ¶ms)) | ||
1673 | sdata_err(sdata, | 1812 | sdata_err(sdata, |
1674 | "failed to set TX queue parameters for queue %d\n", | 1813 | "failed to set TX queue parameters for queue %d\n", |
1675 | queue); | 1814 | queue); |
@@ -1924,6 +2063,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1924 | ieee80211_vif_release_channel(sdata); | 2063 | ieee80211_vif_release_channel(sdata); |
1925 | 2064 | ||
1926 | sdata->vif.csa_active = false; | 2065 | sdata->vif.csa_active = false; |
2066 | ifmgd->csa_waiting_bcn = false; | ||
1927 | if (sdata->csa_block_tx) { | 2067 | if (sdata->csa_block_tx) { |
1928 | ieee80211_wake_vif_queues(local, sdata, | 2068 | ieee80211_wake_vif_queues(local, sdata, |
1929 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2069 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -1931,6 +2071,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1931 | } | 2071 | } |
1932 | mutex_unlock(&local->mtx); | 2072 | mutex_unlock(&local->mtx); |
1933 | 2073 | ||
2074 | /* existing TX TSPEC sessions no longer exist */ | ||
2075 | memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec)); | ||
2076 | cancel_delayed_work_sync(&ifmgd->tx_tspec_wk); | ||
2077 | |||
1934 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | 2078 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
1935 | } | 2079 | } |
1936 | 2080 | ||
@@ -1983,9 +2127,46 @@ out: | |||
1983 | mutex_unlock(&local->mtx); | 2127 | mutex_unlock(&local->mtx); |
1984 | } | 2128 | } |
1985 | 2129 | ||
2130 | static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata, | ||
2131 | struct ieee80211_hdr *hdr, | ||
2132 | u16 tx_time) | ||
2133 | { | ||
2134 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2135 | u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | ||
2136 | int ac = ieee80211_ac_from_tid(tid); | ||
2137 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
2138 | unsigned long now = jiffies; | ||
2139 | |||
2140 | if (likely(!tx_tspec->admitted_time)) | ||
2141 | return; | ||
2142 | |||
2143 | if (time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
2144 | tx_tspec->consumed_tx_time = 0; | ||
2145 | tx_tspec->time_slice_start = now; | ||
2146 | |||
2147 | if (tx_tspec->downgraded) { | ||
2148 | tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
2149 | schedule_delayed_work(&ifmgd->tx_tspec_wk, 0); | ||
2150 | } | ||
2151 | } | ||
2152 | |||
2153 | if (tx_tspec->downgraded) | ||
2154 | return; | ||
2155 | |||
2156 | tx_tspec->consumed_tx_time += tx_time; | ||
2157 | |||
2158 | if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) { | ||
2159 | tx_tspec->downgraded = true; | ||
2160 | tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE; | ||
2161 | schedule_delayed_work(&ifmgd->tx_tspec_wk, 0); | ||
2162 | } | ||
2163 | } | ||
2164 | |||
1986 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 2165 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1987 | struct ieee80211_hdr *hdr, bool ack) | 2166 | struct ieee80211_hdr *hdr, bool ack, u16 tx_time) |
1988 | { | 2167 | { |
2168 | ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time); | ||
2169 | |||
1989 | if (!ieee80211_is_data(hdr->frame_control)) | 2170 | if (!ieee80211_is_data(hdr->frame_control)) |
1990 | return; | 2171 | return; |
1991 | 2172 | ||
@@ -2048,8 +2229,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2048 | 2229 | ||
2049 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 2230 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
2050 | run_again(sdata, ifmgd->probe_timeout); | 2231 | run_again(sdata, ifmgd->probe_timeout); |
2051 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
2052 | ieee80211_flush_queues(sdata->local, sdata); | ||
2053 | } | 2232 | } |
2054 | 2233 | ||
2055 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | 2234 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, |
@@ -2172,6 +2351,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2172 | true, frame_buf); | 2351 | true, frame_buf); |
2173 | mutex_lock(&local->mtx); | 2352 | mutex_lock(&local->mtx); |
2174 | sdata->vif.csa_active = false; | 2353 | sdata->vif.csa_active = false; |
2354 | ifmgd->csa_waiting_bcn = false; | ||
2175 | if (sdata->csa_block_tx) { | 2355 | if (sdata->csa_block_tx) { |
2176 | ieee80211_wake_vif_queues(local, sdata, | 2356 | ieee80211_wake_vif_queues(local, sdata, |
2177 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2357 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -3196,6 +3376,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3196 | } | 3376 | } |
3197 | } | 3377 | } |
3198 | 3378 | ||
3379 | if (ifmgd->csa_waiting_bcn) | ||
3380 | ieee80211_chswitch_post_beacon(sdata); | ||
3381 | |||
3199 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 3382 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
3200 | return; | 3383 | return; |
3201 | ifmgd->beacon_crc = ncrc; | 3384 | ifmgd->beacon_crc = ncrc; |
@@ -3204,6 +3387,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3204 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 3387 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
3205 | 3388 | ||
3206 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, | 3389 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, |
3390 | rx_status->device_timestamp, | ||
3207 | &elems, true); | 3391 | &elems, true); |
3208 | 3392 | ||
3209 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && | 3393 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && |
@@ -3335,8 +3519,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3335 | break; | 3519 | break; |
3336 | 3520 | ||
3337 | ieee80211_sta_process_chanswitch(sdata, | 3521 | ieee80211_sta_process_chanswitch(sdata, |
3338 | rx_status->mactime, | 3522 | rx_status->mactime, |
3339 | &elems, false); | 3523 | rx_status->device_timestamp, |
3524 | &elems, false); | ||
3340 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | 3525 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { |
3341 | ies_len = skb->len - | 3526 | ies_len = skb->len - |
3342 | offsetof(struct ieee80211_mgmt, | 3527 | offsetof(struct ieee80211_mgmt, |
@@ -3357,8 +3542,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3357 | &mgmt->u.action.u.ext_chan_switch.data; | 3542 | &mgmt->u.action.u.ext_chan_switch.data; |
3358 | 3543 | ||
3359 | ieee80211_sta_process_chanswitch(sdata, | 3544 | ieee80211_sta_process_chanswitch(sdata, |
3360 | rx_status->mactime, | 3545 | rx_status->mactime, |
3361 | &elems, false); | 3546 | rx_status->device_timestamp, |
3547 | &elems, false); | ||
3362 | } | 3548 | } |
3363 | break; | 3549 | break; |
3364 | } | 3550 | } |
@@ -3665,11 +3851,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
3665 | struct ieee80211_sub_if_data *sdata = | 3851 | struct ieee80211_sub_if_data *sdata = |
3666 | (struct ieee80211_sub_if_data *) data; | 3852 | (struct ieee80211_sub_if_data *) data; |
3667 | struct ieee80211_local *local = sdata->local; | 3853 | struct ieee80211_local *local = sdata->local; |
3854 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3668 | 3855 | ||
3669 | if (local->quiescing) | 3856 | if (local->quiescing) |
3670 | return; | 3857 | return; |
3671 | 3858 | ||
3672 | if (sdata->vif.csa_active) | 3859 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3673 | return; | 3860 | return; |
3674 | 3861 | ||
3675 | sdata->u.mgd.connection_loss = false; | 3862 | sdata->u.mgd.connection_loss = false; |
@@ -3687,7 +3874,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) | |||
3687 | if (local->quiescing) | 3874 | if (local->quiescing) |
3688 | return; | 3875 | return; |
3689 | 3876 | ||
3690 | if (sdata->vif.csa_active) | 3877 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3691 | return; | 3878 | return; |
3692 | 3879 | ||
3693 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); | 3880 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); |
@@ -3799,6 +3986,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3799 | (unsigned long) sdata); | 3986 | (unsigned long) sdata); |
3800 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 3987 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
3801 | (unsigned long) sdata); | 3988 | (unsigned long) sdata); |
3989 | INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk, | ||
3990 | ieee80211_sta_handle_tspec_ac_params_wk); | ||
3802 | 3991 | ||
3803 | ifmgd->flags = 0; | 3992 | ifmgd->flags = 0; |
3804 | ifmgd->powersave = sdata->wdev.ps; | 3993 | ifmgd->powersave = sdata->wdev.ps; |