diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 156 |
1 files changed, 89 insertions, 67 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3345401be1b3..31a8afaf7332 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -830,16 +830,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
830 | qos_info = 0; | 830 | qos_info = 0; |
831 | } | 831 | } |
832 | 832 | ||
833 | pos = skb_put(skb, 9); | 833 | pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); |
834 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
835 | *pos++ = 7; /* len */ | ||
836 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
837 | *pos++ = 0x50; | ||
838 | *pos++ = 0xf2; | ||
839 | *pos++ = 2; /* WME */ | ||
840 | *pos++ = 0; /* WME info */ | ||
841 | *pos++ = 1; /* WME ver */ | ||
842 | *pos++ = qos_info; | ||
843 | } | 834 | } |
844 | 835 | ||
845 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 836 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
@@ -940,58 +931,77 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
940 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 931 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
941 | struct ieee80211_local *local = sdata->local; | 932 | struct ieee80211_local *local = sdata->local; |
942 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 933 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
943 | u32 changed = 0; | ||
944 | int ret; | 934 | int ret; |
945 | 935 | ||
946 | if (!ieee80211_sdata_running(sdata)) | 936 | if (!ieee80211_sdata_running(sdata)) |
947 | return; | 937 | return; |
948 | 938 | ||
949 | sdata_lock(sdata); | 939 | sdata_lock(sdata); |
940 | mutex_lock(&local->mtx); | ||
941 | mutex_lock(&local->chanctx_mtx); | ||
942 | |||
950 | if (!ifmgd->associated) | 943 | if (!ifmgd->associated) |
951 | goto out; | 944 | goto out; |
952 | 945 | ||
953 | mutex_lock(&local->mtx); | 946 | if (!sdata->vif.csa_active) |
954 | ret = ieee80211_vif_change_channel(sdata, &changed); | 947 | goto out; |
955 | mutex_unlock(&local->mtx); | 948 | |
956 | if (ret) { | 949 | /* |
950 | * using reservation isn't immediate as it may be deferred until later | ||
951 | * with multi-vif. once reservation is complete it will re-schedule the | ||
952 | * work with no reserved_chanctx so verify chandef to check if it | ||
953 | * completed successfully | ||
954 | */ | ||
955 | |||
956 | if (sdata->reserved_chanctx) { | ||
957 | /* | ||
958 | * with multi-vif csa driver may call ieee80211_csa_finish() | ||
959 | * many times while waiting for other interfaces to use their | ||
960 | * reservations | ||
961 | */ | ||
962 | if (sdata->reserved_ready) | ||
963 | goto out; | ||
964 | |||
965 | ret = ieee80211_vif_use_reserved_context(sdata); | ||
966 | if (ret) { | ||
967 | sdata_info(sdata, | ||
968 | "failed to use reserved channel context, disconnecting (err=%d)\n", | ||
969 | ret); | ||
970 | ieee80211_queue_work(&sdata->local->hw, | ||
971 | &ifmgd->csa_connection_drop_work); | ||
972 | goto out; | ||
973 | } | ||
974 | |||
975 | goto out; | ||
976 | } | ||
977 | |||
978 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | ||
979 | &sdata->csa_chandef)) { | ||
957 | sdata_info(sdata, | 980 | sdata_info(sdata, |
958 | "vif channel switch failed, disconnecting\n"); | 981 | "failed to finalize channel switch, disconnecting\n"); |
959 | ieee80211_queue_work(&sdata->local->hw, | 982 | ieee80211_queue_work(&sdata->local->hw, |
960 | &ifmgd->csa_connection_drop_work); | 983 | &ifmgd->csa_connection_drop_work); |
961 | goto out; | 984 | goto out; |
962 | } | 985 | } |
963 | 986 | ||
964 | if (!local->use_chanctx) { | ||
965 | local->_oper_chandef = sdata->csa_chandef; | ||
966 | /* Call "hw_config" only if doing sw channel switch. | ||
967 | * Otherwise update the channel directly | ||
968 | */ | ||
969 | if (!local->ops->channel_switch) | ||
970 | ieee80211_hw_config(local, 0); | ||
971 | else | ||
972 | local->hw.conf.chandef = local->_oper_chandef; | ||
973 | } | ||
974 | |||
975 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 987 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
976 | ifmgd->associated->channel = sdata->csa_chandef.chan; | 988 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
977 | 989 | ||
978 | ieee80211_bss_info_change_notify(sdata, changed); | ||
979 | |||
980 | mutex_lock(&local->mtx); | ||
981 | sdata->vif.csa_active = false; | 990 | sdata->vif.csa_active = false; |
982 | /* XXX: wait for a beacon first? */ | ||
983 | if (!ieee80211_csa_needs_block_tx(local)) | ||
984 | ieee80211_wake_queues_by_reason(&local->hw, | ||
985 | IEEE80211_MAX_QUEUE_MAP, | ||
986 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
987 | mutex_unlock(&local->mtx); | ||
988 | 991 | ||
989 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 992 | /* XXX: wait for a beacon first? */ |
993 | if (sdata->csa_block_tx) { | ||
994 | ieee80211_wake_vif_queues(local, sdata, | ||
995 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
996 | sdata->csa_block_tx = false; | ||
997 | } | ||
990 | 998 | ||
991 | ieee80211_sta_reset_beacon_monitor(sdata); | 999 | ieee80211_sta_reset_beacon_monitor(sdata); |
992 | ieee80211_sta_reset_conn_monitor(sdata); | 1000 | ieee80211_sta_reset_conn_monitor(sdata); |
993 | 1001 | ||
994 | out: | 1002 | out: |
1003 | mutex_unlock(&local->chanctx_mtx); | ||
1004 | mutex_unlock(&local->mtx); | ||
995 | sdata_unlock(sdata); | 1005 | sdata_unlock(sdata); |
996 | } | 1006 | } |
997 | 1007 | ||
@@ -1028,6 +1038,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1028 | struct ieee80211_local *local = sdata->local; | 1038 | struct ieee80211_local *local = sdata->local; |
1029 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1039 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1030 | struct cfg80211_bss *cbss = ifmgd->associated; | 1040 | struct cfg80211_bss *cbss = ifmgd->associated; |
1041 | struct ieee80211_chanctx_conf *conf; | ||
1031 | struct ieee80211_chanctx *chanctx; | 1042 | struct ieee80211_chanctx *chanctx; |
1032 | enum ieee80211_band current_band; | 1043 | enum ieee80211_band current_band; |
1033 | struct ieee80211_csa_ie csa_ie; | 1044 | struct ieee80211_csa_ie csa_ie; |
@@ -1042,7 +1053,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1042 | return; | 1053 | return; |
1043 | 1054 | ||
1044 | /* disregard subsequent announcements if we are already processing */ | 1055 | /* disregard subsequent announcements if we are already processing */ |
1045 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 1056 | if (sdata->vif.csa_active) |
1046 | return; | 1057 | return; |
1047 | 1058 | ||
1048 | current_band = cbss->channel->band; | 1059 | current_band = cbss->channel->band; |
@@ -1069,9 +1080,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1069 | return; | 1080 | return; |
1070 | } | 1081 | } |
1071 | 1082 | ||
1072 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1083 | mutex_lock(&local->mtx); |
1073 | |||
1074 | mutex_lock(&local->chanctx_mtx); | 1084 | mutex_lock(&local->chanctx_mtx); |
1085 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1086 | lockdep_is_held(&local->chanctx_mtx)); | ||
1087 | if (!conf) { | ||
1088 | sdata_info(sdata, | ||
1089 | "no channel context assigned to vif?, disconnecting\n"); | ||
1090 | ieee80211_queue_work(&local->hw, | ||
1091 | &ifmgd->csa_connection_drop_work); | ||
1092 | mutex_unlock(&local->chanctx_mtx); | ||
1093 | mutex_unlock(&local->mtx); | ||
1094 | return; | ||
1095 | } | ||
1096 | |||
1097 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
1098 | |||
1075 | if (local->use_chanctx) { | 1099 | if (local->use_chanctx) { |
1076 | u32 num_chanctx = 0; | 1100 | u32 num_chanctx = 0; |
1077 | list_for_each_entry(chanctx, &local->chanctx_list, list) | 1101 | list_for_each_entry(chanctx, &local->chanctx_list, list) |
@@ -1084,38 +1108,32 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1084 | ieee80211_queue_work(&local->hw, | 1108 | ieee80211_queue_work(&local->hw, |
1085 | &ifmgd->csa_connection_drop_work); | 1109 | &ifmgd->csa_connection_drop_work); |
1086 | mutex_unlock(&local->chanctx_mtx); | 1110 | mutex_unlock(&local->chanctx_mtx); |
1111 | mutex_unlock(&local->mtx); | ||
1087 | return; | 1112 | return; |
1088 | } | 1113 | } |
1089 | } | 1114 | } |
1090 | 1115 | ||
1091 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { | 1116 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
1092 | ieee80211_queue_work(&local->hw, | 1117 | chanctx->mode, false); |
1093 | &ifmgd->csa_connection_drop_work); | 1118 | if (res) { |
1094 | mutex_unlock(&local->chanctx_mtx); | ||
1095 | return; | ||
1096 | } | ||
1097 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), | ||
1098 | struct ieee80211_chanctx, conf); | ||
1099 | if (ieee80211_chanctx_refcount(local, chanctx) > 1) { | ||
1100 | sdata_info(sdata, | 1119 | sdata_info(sdata, |
1101 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); | 1120 | "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", |
1121 | res); | ||
1102 | ieee80211_queue_work(&local->hw, | 1122 | ieee80211_queue_work(&local->hw, |
1103 | &ifmgd->csa_connection_drop_work); | 1123 | &ifmgd->csa_connection_drop_work); |
1104 | mutex_unlock(&local->chanctx_mtx); | 1124 | mutex_unlock(&local->chanctx_mtx); |
1125 | mutex_unlock(&local->mtx); | ||
1105 | return; | 1126 | return; |
1106 | } | 1127 | } |
1107 | mutex_unlock(&local->chanctx_mtx); | 1128 | mutex_unlock(&local->chanctx_mtx); |
1108 | 1129 | ||
1109 | sdata->csa_chandef = csa_ie.chandef; | ||
1110 | |||
1111 | mutex_lock(&local->mtx); | ||
1112 | sdata->vif.csa_active = true; | 1130 | sdata->vif.csa_active = true; |
1131 | sdata->csa_chandef = csa_ie.chandef; | ||
1113 | sdata->csa_block_tx = csa_ie.mode; | 1132 | sdata->csa_block_tx = csa_ie.mode; |
1114 | 1133 | ||
1115 | if (sdata->csa_block_tx) | 1134 | if (sdata->csa_block_tx) |
1116 | ieee80211_stop_queues_by_reason(&local->hw, | 1135 | ieee80211_stop_vif_queues(local, sdata, |
1117 | IEEE80211_MAX_QUEUE_MAP, | 1136 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1118 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1119 | mutex_unlock(&local->mtx); | 1137 | mutex_unlock(&local->mtx); |
1120 | 1138 | ||
1121 | if (local->ops->channel_switch) { | 1139 | if (local->ops->channel_switch) { |
@@ -1385,7 +1403,8 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | |||
1385 | 1403 | ||
1386 | ieee80211_wake_queues_by_reason(&local->hw, | 1404 | ieee80211_wake_queues_by_reason(&local->hw, |
1387 | IEEE80211_MAX_QUEUE_MAP, | 1405 | IEEE80211_MAX_QUEUE_MAP, |
1388 | IEEE80211_QUEUE_STOP_REASON_PS); | 1406 | IEEE80211_QUEUE_STOP_REASON_PS, |
1407 | false); | ||
1389 | } | 1408 | } |
1390 | 1409 | ||
1391 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | 1410 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) |
@@ -1830,10 +1849,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1830 | ieee80211_vif_release_channel(sdata); | 1849 | ieee80211_vif_release_channel(sdata); |
1831 | 1850 | ||
1832 | sdata->vif.csa_active = false; | 1851 | sdata->vif.csa_active = false; |
1833 | if (!ieee80211_csa_needs_block_tx(local)) | 1852 | if (sdata->csa_block_tx) { |
1834 | ieee80211_wake_queues_by_reason(&local->hw, | 1853 | ieee80211_wake_vif_queues(local, sdata, |
1835 | IEEE80211_MAX_QUEUE_MAP, | 1854 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1836 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1855 | sdata->csa_block_tx = false; |
1856 | } | ||
1837 | mutex_unlock(&local->mtx); | 1857 | mutex_unlock(&local->mtx); |
1838 | 1858 | ||
1839 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | 1859 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
@@ -2075,14 +2095,13 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2075 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 2095 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
2076 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 2096 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
2077 | true, frame_buf); | 2097 | true, frame_buf); |
2078 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
2079 | |||
2080 | mutex_lock(&local->mtx); | 2098 | mutex_lock(&local->mtx); |
2081 | sdata->vif.csa_active = false; | 2099 | sdata->vif.csa_active = false; |
2082 | if (!ieee80211_csa_needs_block_tx(local)) | 2100 | if (sdata->csa_block_tx) { |
2083 | ieee80211_wake_queues_by_reason(&local->hw, | 2101 | ieee80211_wake_vif_queues(local, sdata, |
2084 | IEEE80211_MAX_QUEUE_MAP, | 2102 | IEEE80211_QUEUE_STOP_REASON_CSA); |
2085 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2103 | sdata->csa_block_tx = false; |
2104 | } | ||
2086 | mutex_unlock(&local->mtx); | 2105 | mutex_unlock(&local->mtx); |
2087 | 2106 | ||
2088 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 2107 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
@@ -3688,6 +3707,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3688 | INIT_WORK(&ifmgd->csa_connection_drop_work, | 3707 | INIT_WORK(&ifmgd->csa_connection_drop_work, |
3689 | ieee80211_csa_connection_drop_work); | 3708 | ieee80211_csa_connection_drop_work); |
3690 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); | 3709 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); |
3710 | INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work, | ||
3711 | ieee80211_tdls_peer_del_work); | ||
3691 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 3712 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
3692 | (unsigned long) sdata); | 3713 | (unsigned long) sdata); |
3693 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | 3714 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, |
@@ -4551,6 +4572,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4551 | cancel_work_sync(&ifmgd->request_smps_work); | 4572 | cancel_work_sync(&ifmgd->request_smps_work); |
4552 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | 4573 | cancel_work_sync(&ifmgd->csa_connection_drop_work); |
4553 | cancel_work_sync(&ifmgd->chswitch_work); | 4574 | cancel_work_sync(&ifmgd->chswitch_work); |
4575 | cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work); | ||
4554 | 4576 | ||
4555 | sdata_lock(sdata); | 4577 | sdata_lock(sdata); |
4556 | if (ifmgd->assoc_data) { | 4578 | if (ifmgd->assoc_data) { |