aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r--net/mac80211/chan.c863
1 files changed, 718 insertions, 145 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index a310e33972de..399ad82c997f 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -63,6 +63,20 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
63 return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); 63 return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
64} 64}
65 65
66static struct ieee80211_chanctx *
67ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata)
68{
69 struct ieee80211_local *local __maybe_unused = sdata->local;
70 struct ieee80211_chanctx_conf *conf;
71
72 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
73 lockdep_is_held(&local->chanctx_mtx));
74 if (!conf)
75 return NULL;
76
77 return container_of(conf, struct ieee80211_chanctx, conf);
78}
79
66static const struct cfg80211_chan_def * 80static const struct cfg80211_chan_def *
67ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, 81ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
68 struct ieee80211_chanctx *ctx, 82 struct ieee80211_chanctx *ctx,
@@ -160,6 +174,9 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
160 return NULL; 174 return NULL;
161 175
162 list_for_each_entry(ctx, &local->chanctx_list, list) { 176 list_for_each_entry(ctx, &local->chanctx_list, list) {
177 if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
178 continue;
179
163 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) 180 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
164 continue; 181 continue;
165 182
@@ -347,6 +364,9 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
347 list_for_each_entry(ctx, &local->chanctx_list, list) { 364 list_for_each_entry(ctx, &local->chanctx_list, list) {
348 const struct cfg80211_chan_def *compat; 365 const struct cfg80211_chan_def *compat;
349 366
367 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE)
368 continue;
369
350 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) 370 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
351 continue; 371 continue;
352 372
@@ -521,6 +541,8 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
521 continue; 541 continue;
522 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) 542 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
523 continue; 543 continue;
544 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
545 continue;
524 546
525 if (!compat) 547 if (!compat)
526 compat = &sdata->vif.bss_conf.chandef; 548 compat = &sdata->vif.bss_conf.chandef;
@@ -622,6 +644,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
622 struct ieee80211_local *local = sdata->local; 644 struct ieee80211_local *local = sdata->local;
623 struct ieee80211_chanctx_conf *conf; 645 struct ieee80211_chanctx_conf *conf;
624 struct ieee80211_chanctx *ctx; 646 struct ieee80211_chanctx *ctx;
647 bool use_reserved_switch = false;
625 648
626 lockdep_assert_held(&local->chanctx_mtx); 649 lockdep_assert_held(&local->chanctx_mtx);
627 650
@@ -632,12 +655,23 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
632 655
633 ctx = container_of(conf, struct ieee80211_chanctx, conf); 656 ctx = container_of(conf, struct ieee80211_chanctx, conf);
634 657
635 if (sdata->reserved_chanctx) 658 if (sdata->reserved_chanctx) {
659 if (sdata->reserved_chanctx->replace_state ==
660 IEEE80211_CHANCTX_REPLACES_OTHER &&
661 ieee80211_chanctx_num_reserved(local,
662 sdata->reserved_chanctx) > 1)
663 use_reserved_switch = true;
664
636 ieee80211_vif_unreserve_chanctx(sdata); 665 ieee80211_vif_unreserve_chanctx(sdata);
666 }
637 667
638 ieee80211_assign_vif_chanctx(sdata, NULL); 668 ieee80211_assign_vif_chanctx(sdata, NULL);
639 if (ieee80211_chanctx_refcount(local, ctx) == 0) 669 if (ieee80211_chanctx_refcount(local, ctx) == 0)
640 ieee80211_free_chanctx(local, ctx); 670 ieee80211_free_chanctx(local, ctx);
671
672 /* Unreserving may ready an in-place reservation. */
673 if (use_reserved_switch)
674 ieee80211_vif_use_reserved_switch(local);
641} 675}
642 676
643void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, 677void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
@@ -787,70 +821,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
787 return ret; 821 return ret;
788} 822}
789 823
790static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
791 struct ieee80211_chanctx *ctx,
792 u32 *changed)
793{
794 struct ieee80211_local *local = sdata->local;
795 const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
796 u32 chanctx_changed = 0;
797
798 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
799 IEEE80211_CHAN_DISABLED))
800 return -EINVAL;
801
802 if (ieee80211_chanctx_refcount(local, ctx) != 1)
803 return -EINVAL;
804
805 if (sdata->vif.bss_conf.chandef.width != chandef->width) {
806 chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
807 *changed |= BSS_CHANGED_BANDWIDTH;
808 }
809
810 sdata->vif.bss_conf.chandef = *chandef;
811 ctx->conf.def = *chandef;
812
813 chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
814 drv_change_chanctx(local, ctx, chanctx_changed);
815
816 ieee80211_recalc_chanctx_chantype(local, ctx);
817 ieee80211_recalc_smps_chanctx(local, ctx);
818 ieee80211_recalc_radar_chanctx(local, ctx);
819 ieee80211_recalc_chanctx_min_def(local, ctx);
820
821 return 0;
822}
823
824int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
825 u32 *changed)
826{
827 struct ieee80211_local *local = sdata->local;
828 struct ieee80211_chanctx_conf *conf;
829 struct ieee80211_chanctx *ctx;
830 int ret;
831
832 lockdep_assert_held(&local->mtx);
833
834 /* should never be called if not performing a channel switch. */
835 if (WARN_ON(!sdata->vif.csa_active))
836 return -EINVAL;
837
838 mutex_lock(&local->chanctx_mtx);
839 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
840 lockdep_is_held(&local->chanctx_mtx));
841 if (!conf) {
842 ret = -EINVAL;
843 goto out;
844 }
845
846 ctx = container_of(conf, struct ieee80211_chanctx, conf);
847
848 ret = __ieee80211_vif_change_channel(sdata, ctx, changed);
849 out:
850 mutex_unlock(&local->chanctx_mtx);
851 return ret;
852}
853
854static void 824static void
855__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, 825__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
856 bool clear) 826 bool clear)
@@ -905,8 +875,25 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
905 list_del(&sdata->reserved_chanctx_list); 875 list_del(&sdata->reserved_chanctx_list);
906 sdata->reserved_chanctx = NULL; 876 sdata->reserved_chanctx = NULL;
907 877
908 if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) 878 if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
909 ieee80211_free_chanctx(sdata->local, ctx); 879 if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
880 if (WARN_ON(!ctx->replace_ctx))
881 return -EINVAL;
882
883 WARN_ON(ctx->replace_ctx->replace_state !=
884 IEEE80211_CHANCTX_WILL_BE_REPLACED);
885 WARN_ON(ctx->replace_ctx->replace_ctx != ctx);
886
887 ctx->replace_ctx->replace_ctx = NULL;
888 ctx->replace_ctx->replace_state =
889 IEEE80211_CHANCTX_REPLACE_NONE;
890
891 list_del_rcu(&ctx->list);
892 kfree_rcu(ctx, rcu_head);
893 } else {
894 ieee80211_free_chanctx(sdata->local, ctx);
895 }
896 }
910 897
911 return 0; 898 return 0;
912} 899}
@@ -917,40 +904,84 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
917 bool radar_required) 904 bool radar_required)
918{ 905{
919 struct ieee80211_local *local = sdata->local; 906 struct ieee80211_local *local = sdata->local;
920 struct ieee80211_chanctx_conf *conf; 907 struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx;
921 struct ieee80211_chanctx *new_ctx, *curr_ctx;
922 int ret = 0;
923
924 mutex_lock(&local->chanctx_mtx);
925 908
926 conf = rcu_dereference_protected(sdata->vif.chanctx_conf, 909 lockdep_assert_held(&local->chanctx_mtx);
927 lockdep_is_held(&local->chanctx_mtx));
928 if (!conf) {
929 ret = -EINVAL;
930 goto out;
931 }
932 910
933 curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); 911 curr_ctx = ieee80211_vif_get_chanctx(sdata);
912 if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx)
913 return -ENOTSUPP;
934 914
935 new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); 915 new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
936 if (!new_ctx) { 916 if (!new_ctx) {
937 if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 && 917 if (ieee80211_can_create_new_chanctx(local)) {
938 (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
939 /* if we're the only users of the chanctx and
940 * the driver supports changing a running
941 * context, reserve our current context
942 */
943 new_ctx = curr_ctx;
944 } else if (ieee80211_can_create_new_chanctx(local)) {
945 /* create a new context and reserve it */
946 new_ctx = ieee80211_new_chanctx(local, chandef, mode); 918 new_ctx = ieee80211_new_chanctx(local, chandef, mode);
947 if (IS_ERR(new_ctx)) { 919 if (IS_ERR(new_ctx))
948 ret = PTR_ERR(new_ctx); 920 return PTR_ERR(new_ctx);
949 goto out;
950 }
951 } else { 921 } else {
952 ret = -EBUSY; 922 if (!curr_ctx ||
953 goto out; 923 (curr_ctx->replace_state ==
924 IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
925 !list_empty(&curr_ctx->reserved_vifs)) {
926 /*
927 * Another vif already requested this context
928 * for a reservation. Find another one hoping
929 * all vifs assigned to it will also switch
930 * soon enough.
931 *
932 * TODO: This needs a little more work as some
933 * cases (more than 2 chanctx capable devices)
934 * may fail which could otherwise succeed
935 * provided some channel context juggling was
936 * performed.
937 *
938 * Consider ctx1..3, vif1..6, each ctx has 2
939 * vifs. vif1 and vif2 from ctx1 request new
940 * different chandefs starting 2 in-place
941 * reserations with ctx4 and ctx5 replacing
942 * ctx1 and ctx2 respectively. Next vif5 and
943 * vif6 from ctx3 reserve ctx4. If vif3 and
944 * vif4 remain on ctx2 as they are then this
945 * fails unless `replace_ctx` from ctx5 is
946 * replaced with ctx3.
947 */
948 list_for_each_entry(ctx, &local->chanctx_list,
949 list) {
950 if (ctx->replace_state !=
951 IEEE80211_CHANCTX_REPLACE_NONE)
952 continue;
953
954 if (!list_empty(&ctx->reserved_vifs))
955 continue;
956
957 curr_ctx = ctx;
958 break;
959 }
960 }
961
962 /*
963 * If that's true then all available contexts already
964 * have reservations and cannot be used.
965 */
966 if (!curr_ctx ||
967 (curr_ctx->replace_state ==
968 IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
969 !list_empty(&curr_ctx->reserved_vifs))
970 return -EBUSY;
971
972 new_ctx = ieee80211_alloc_chanctx(local, chandef, mode);
973 if (!new_ctx)
974 return -ENOMEM;
975
976 new_ctx->replace_ctx = curr_ctx;
977 new_ctx->replace_state =
978 IEEE80211_CHANCTX_REPLACES_OTHER;
979
980 curr_ctx->replace_ctx = new_ctx;
981 curr_ctx->replace_state =
982 IEEE80211_CHANCTX_WILL_BE_REPLACED;
983
984 list_add_rcu(&new_ctx->list, &local->chanctx_list);
954 } 985 }
955 } 986 }
956 987
@@ -958,82 +989,601 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
958 sdata->reserved_chanctx = new_ctx; 989 sdata->reserved_chanctx = new_ctx;
959 sdata->reserved_chandef = *chandef; 990 sdata->reserved_chandef = *chandef;
960 sdata->reserved_radar_required = radar_required; 991 sdata->reserved_radar_required = radar_required;
961out: 992 sdata->reserved_ready = false;
962 mutex_unlock(&local->chanctx_mtx); 993
963 return ret; 994 return 0;
964} 995}
965 996
966int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, 997static void
967 u32 *changed) 998ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
968{ 999{
969 struct ieee80211_local *local = sdata->local; 1000 switch (sdata->vif.type) {
970 struct ieee80211_chanctx *ctx; 1001 case NL80211_IFTYPE_ADHOC:
971 struct ieee80211_chanctx *old_ctx; 1002 case NL80211_IFTYPE_AP:
972 struct ieee80211_chanctx_conf *conf; 1003 case NL80211_IFTYPE_MESH_POINT:
973 int ret; 1004 ieee80211_queue_work(&sdata->local->hw,
974 u32 tmp_changed = *changed; 1005 &sdata->csa_finalize_work);
1006 break;
1007 case NL80211_IFTYPE_STATION:
1008 ieee80211_queue_work(&sdata->local->hw,
1009 &sdata->u.mgd.chswitch_work);
1010 break;
1011 case NL80211_IFTYPE_UNSPECIFIED:
1012 case NL80211_IFTYPE_AP_VLAN:
1013 case NL80211_IFTYPE_WDS:
1014 case NL80211_IFTYPE_MONITOR:
1015 case NL80211_IFTYPE_P2P_CLIENT:
1016 case NL80211_IFTYPE_P2P_GO:
1017 case NL80211_IFTYPE_P2P_DEVICE:
1018 case NUM_NL80211_IFTYPES:
1019 WARN_ON(1);
1020 break;
1021 }
1022}
975 1023
976 /* TODO: need to recheck if the chandef is usable etc.? */ 1024static int
1025ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
1026{
1027 struct ieee80211_local *local = sdata->local;
1028 struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
1029 struct ieee80211_chanctx *old_ctx, *new_ctx;
1030 const struct cfg80211_chan_def *chandef;
1031 u32 changed = 0;
1032 int err;
977 1033
978 lockdep_assert_held(&local->mtx); 1034 lockdep_assert_held(&local->mtx);
1035 lockdep_assert_held(&local->chanctx_mtx);
979 1036
980 mutex_lock(&local->chanctx_mtx); 1037 new_ctx = sdata->reserved_chanctx;
1038 old_ctx = ieee80211_vif_get_chanctx(sdata);
981 1039
982 ctx = sdata->reserved_chanctx; 1040 if (WARN_ON(!sdata->reserved_ready))
983 if (WARN_ON(!ctx)) { 1041 return -EBUSY;
984 ret = -EINVAL; 1042
985 goto out; 1043 if (WARN_ON(!new_ctx))
986 } 1044 return -EINVAL;
1045
1046 if (WARN_ON(!old_ctx))
1047 return -EINVAL;
1048
1049 if (WARN_ON(new_ctx->replace_state ==
1050 IEEE80211_CHANCTX_REPLACES_OTHER))
1051 return -EINVAL;
1052
1053 chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1054 &sdata->reserved_chandef);
1055 if (WARN_ON(!chandef))
1056 return -EINVAL;
1057
1058 vif_chsw[0].vif = &sdata->vif;
1059 vif_chsw[0].old_ctx = &old_ctx->conf;
1060 vif_chsw[0].new_ctx = &new_ctx->conf;
1061
1062 list_del(&sdata->reserved_chanctx_list);
1063 sdata->reserved_chanctx = NULL;
1064
1065 err = drv_switch_vif_chanctx(local, vif_chsw, 1,
1066 CHANCTX_SWMODE_REASSIGN_VIF);
1067 if (err) {
1068 if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1069 ieee80211_free_chanctx(local, new_ctx);
987 1070
988 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
989 lockdep_is_held(&local->chanctx_mtx));
990 if (!conf) {
991 ret = -EINVAL;
992 goto out; 1071 goto out;
993 } 1072 }
994 1073
995 old_ctx = container_of(conf, struct ieee80211_chanctx, conf); 1074 list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs);
1075 rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
1076
1077 if (sdata->vif.type == NL80211_IFTYPE_AP)
1078 __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
1079
1080 if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
1081 ieee80211_free_chanctx(local, old_ctx);
996 1082
997 if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) 1083 if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
998 tmp_changed |= BSS_CHANGED_BANDWIDTH; 1084 changed = BSS_CHANGED_BANDWIDTH;
999 1085
1000 sdata->vif.bss_conf.chandef = sdata->reserved_chandef; 1086 sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
1001 1087
1002 /* unref our reservation */ 1088 if (changed)
1003 sdata->reserved_chanctx = NULL; 1089 ieee80211_bss_info_change_notify(sdata, changed);
1004 sdata->radar_required = sdata->reserved_radar_required; 1090
1091out:
1092 ieee80211_vif_chanctx_reservation_complete(sdata);
1093 return err;
1094}
1095
1096static int
1097ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata)
1098{
1099 struct ieee80211_local *local = sdata->local;
1100 struct ieee80211_chanctx *old_ctx, *new_ctx;
1101 const struct cfg80211_chan_def *chandef;
1102 int err;
1103
1104 old_ctx = ieee80211_vif_get_chanctx(sdata);
1105 new_ctx = sdata->reserved_chanctx;
1106
1107 if (WARN_ON(!sdata->reserved_ready))
1108 return -EINVAL;
1109
1110 if (WARN_ON(old_ctx))
1111 return -EINVAL;
1112
1113 if (WARN_ON(!new_ctx))
1114 return -EINVAL;
1115
1116 if (WARN_ON(new_ctx->replace_state ==
1117 IEEE80211_CHANCTX_REPLACES_OTHER))
1118 return -EINVAL;
1119
1120 chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1121 &sdata->reserved_chandef);
1122 if (WARN_ON(!chandef))
1123 return -EINVAL;
1124
1005 list_del(&sdata->reserved_chanctx_list); 1125 list_del(&sdata->reserved_chanctx_list);
1126 sdata->reserved_chanctx = NULL;
1006 1127
1007 if (old_ctx == ctx) { 1128 err = ieee80211_assign_vif_chanctx(sdata, new_ctx);
1008 /* This is our own context, just change it */ 1129 if (err) {
1009 ret = __ieee80211_vif_change_channel(sdata, old_ctx, 1130 if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1010 &tmp_changed); 1131 ieee80211_free_chanctx(local, new_ctx);
1011 if (ret) 1132
1012 goto out; 1133 goto out;
1013 } else { 1134 }
1014 ret = ieee80211_assign_vif_chanctx(sdata, ctx); 1135
1015 if (ieee80211_chanctx_refcount(local, old_ctx) == 0) 1136out:
1016 ieee80211_free_chanctx(local, old_ctx); 1137 ieee80211_vif_chanctx_reservation_complete(sdata);
1017 if (ret) { 1138 return err;
1018 /* if assign fails refcount stays the same */ 1139}
1019 if (ieee80211_chanctx_refcount(local, ctx) == 0) 1140
1020 ieee80211_free_chanctx(local, ctx); 1141static bool
1142ieee80211_vif_has_in_place_reservation(struct ieee80211_sub_if_data *sdata)
1143{
1144 struct ieee80211_chanctx *old_ctx, *new_ctx;
1145
1146 lockdep_assert_held(&sdata->local->chanctx_mtx);
1147
1148 new_ctx = sdata->reserved_chanctx;
1149 old_ctx = ieee80211_vif_get_chanctx(sdata);
1150
1151 if (!old_ctx)
1152 return false;
1153
1154 if (WARN_ON(!new_ctx))
1155 return false;
1156
1157 if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1158 return false;
1159
1160 if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1161 return false;
1162
1163 return true;
1164}
1165
1166static int ieee80211_chsw_switch_hwconf(struct ieee80211_local *local,
1167 struct ieee80211_chanctx *new_ctx)
1168{
1169 const struct cfg80211_chan_def *chandef;
1170
1171 lockdep_assert_held(&local->mtx);
1172 lockdep_assert_held(&local->chanctx_mtx);
1173
1174 chandef = ieee80211_chanctx_reserved_chandef(local, new_ctx, NULL);
1175 if (WARN_ON(!chandef))
1176 return -EINVAL;
1177
1178 local->hw.conf.radar_enabled = new_ctx->conf.radar_enabled;
1179 local->_oper_chandef = *chandef;
1180 ieee80211_hw_config(local, 0);
1181
1182 return 0;
1183}
1184
1185static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
1186 int n_vifs)
1187{
1188 struct ieee80211_vif_chanctx_switch *vif_chsw;
1189 struct ieee80211_sub_if_data *sdata;
1190 struct ieee80211_chanctx *ctx, *old_ctx;
1191 int i, err;
1192
1193 lockdep_assert_held(&local->mtx);
1194 lockdep_assert_held(&local->chanctx_mtx);
1195
1196 vif_chsw = kzalloc(sizeof(vif_chsw[0]) * n_vifs, GFP_KERNEL);
1197 if (!vif_chsw)
1198 return -ENOMEM;
1199
1200 i = 0;
1201 list_for_each_entry(ctx, &local->chanctx_list, list) {
1202 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1203 continue;
1204
1205 if (WARN_ON(!ctx->replace_ctx)) {
1206 err = -EINVAL;
1021 goto out; 1207 goto out;
1022 } 1208 }
1023 1209
1024 if (sdata->vif.type == NL80211_IFTYPE_AP) 1210 list_for_each_entry(sdata, &ctx->reserved_vifs,
1025 __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); 1211 reserved_chanctx_list) {
1212 if (!ieee80211_vif_has_in_place_reservation(
1213 sdata))
1214 continue;
1215
1216 old_ctx = ieee80211_vif_get_chanctx(sdata);
1217 vif_chsw[i].vif = &sdata->vif;
1218 vif_chsw[i].old_ctx = &old_ctx->conf;
1219 vif_chsw[i].new_ctx = &ctx->conf;
1220
1221 i++;
1222 }
1026 } 1223 }
1027 1224
1028 *changed = tmp_changed; 1225 err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs,
1226 CHANCTX_SWMODE_SWAP_CONTEXTS);
1029 1227
1030 ieee80211_recalc_chanctx_chantype(local, ctx);
1031 ieee80211_recalc_smps_chanctx(local, ctx);
1032 ieee80211_recalc_radar_chanctx(local, ctx);
1033 ieee80211_recalc_chanctx_min_def(local, ctx);
1034out: 1228out:
1035 mutex_unlock(&local->chanctx_mtx); 1229 kfree(vif_chsw);
1036 return ret; 1230 return err;
1231}
1232
1233static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
1234{
1235 struct ieee80211_chanctx *ctx;
1236 int err;
1237
1238 lockdep_assert_held(&local->mtx);
1239 lockdep_assert_held(&local->chanctx_mtx);
1240
1241 list_for_each_entry(ctx, &local->chanctx_list, list) {
1242 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1243 continue;
1244
1245 if (!list_empty(&ctx->replace_ctx->assigned_vifs))
1246 continue;
1247
1248 ieee80211_del_chanctx(local, ctx->replace_ctx);
1249 err = ieee80211_add_chanctx(local, ctx);
1250 if (err)
1251 goto err;
1252 }
1253
1254 return 0;
1255
1256err:
1257 WARN_ON(ieee80211_add_chanctx(local, ctx));
1258 list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) {
1259 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1260 continue;
1261
1262 if (!list_empty(&ctx->replace_ctx->assigned_vifs))
1263 continue;
1264
1265 ieee80211_del_chanctx(local, ctx);
1266 WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx));
1267 }
1268
1269 return err;
1270}
1271
1272int
1273ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1274{
1275 struct ieee80211_sub_if_data *sdata, *sdata_tmp;
1276 struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
1277 struct ieee80211_chanctx *new_ctx = NULL;
1278 int i, err, n_assigned, n_reserved, n_ready;
1279 int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0;
1280
1281 lockdep_assert_held(&local->mtx);
1282 lockdep_assert_held(&local->chanctx_mtx);
1283
1284 /*
1285 * If there are 2 independent pairs of channel contexts performing
1286 * cross-switch of their vifs this code will still wait until both are
1287 * ready even though it could be possible to switch one before the
1288 * other is ready.
1289 *
1290 * For practical reasons and code simplicity just do a single huge
1291 * switch.
1292 */
1293
1294 /*
1295 * Verify if the reservation is still feasible.
1296 * - if it's not then disconnect
1297 * - if it is but not all vifs necessary are ready then defer
1298 */
1299
1300 list_for_each_entry(ctx, &local->chanctx_list, list) {
1301 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1302 continue;
1303
1304 if (WARN_ON(!ctx->replace_ctx)) {
1305 err = -EINVAL;
1306 goto err;
1307 }
1308
1309 if (!local->use_chanctx)
1310 new_ctx = ctx;
1311
1312 n_ctx++;
1313
1314 n_assigned = 0;
1315 n_reserved = 0;
1316 n_ready = 0;
1317
1318 list_for_each_entry(sdata, &ctx->replace_ctx->assigned_vifs,
1319 assigned_chanctx_list) {
1320 n_assigned++;
1321 if (sdata->reserved_chanctx) {
1322 n_reserved++;
1323 if (sdata->reserved_ready)
1324 n_ready++;
1325 }
1326 }
1327
1328 if (n_assigned != n_reserved) {
1329 if (n_ready == n_reserved) {
1330 wiphy_info(local->hw.wiphy,
1331 "channel context reservation cannot be finalized because some interfaces aren't switching\n");
1332 err = -EBUSY;
1333 goto err;
1334 }
1335
1336 return -EAGAIN;
1337 }
1338
1339 ctx->conf.radar_enabled = false;
1340 list_for_each_entry(sdata, &ctx->reserved_vifs,
1341 reserved_chanctx_list) {
1342 if (ieee80211_vif_has_in_place_reservation(sdata) &&
1343 !sdata->reserved_ready)
1344 return -EAGAIN;
1345
1346 old_ctx = ieee80211_vif_get_chanctx(sdata);
1347 if (old_ctx) {
1348 if (old_ctx->replace_state ==
1349 IEEE80211_CHANCTX_WILL_BE_REPLACED)
1350 n_vifs_switch++;
1351 else
1352 n_vifs_assign++;
1353 } else {
1354 n_vifs_ctxless++;
1355 }
1356
1357 if (sdata->reserved_radar_required)
1358 ctx->conf.radar_enabled = true;
1359 }
1360 }
1361
1362 if (WARN_ON(n_ctx == 0) ||
1363 WARN_ON(n_vifs_switch == 0 &&
1364 n_vifs_assign == 0 &&
1365 n_vifs_ctxless == 0) ||
1366 WARN_ON(n_ctx > 1 && !local->use_chanctx) ||
1367 WARN_ON(!new_ctx && !local->use_chanctx)) {
1368 err = -EINVAL;
1369 goto err;
1370 }
1371
1372 /*
1373 * All necessary vifs are ready. Perform the switch now depending on
1374 * reservations and driver capabilities.
1375 */
1376
1377 if (local->use_chanctx) {
1378 if (n_vifs_switch > 0) {
1379 err = ieee80211_chsw_switch_vifs(local, n_vifs_switch);
1380 if (err)
1381 goto err;
1382 }
1383
1384 if (n_vifs_assign > 0 || n_vifs_ctxless > 0) {
1385 err = ieee80211_chsw_switch_ctxs(local);
1386 if (err)
1387 goto err;
1388 }
1389 } else {
1390 err = ieee80211_chsw_switch_hwconf(local, new_ctx);
1391 if (err)
1392 goto err;
1393 }
1394
1395 /*
1396 * Update all structures, values and pointers to point to new channel
1397 * context(s).
1398 */
1399
1400 i = 0;
1401 list_for_each_entry(ctx, &local->chanctx_list, list) {
1402 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1403 continue;
1404
1405 if (WARN_ON(!ctx->replace_ctx)) {
1406 err = -EINVAL;
1407 goto err;
1408 }
1409
1410 list_for_each_entry(sdata, &ctx->reserved_vifs,
1411 reserved_chanctx_list) {
1412 u32 changed = 0;
1413
1414 if (!ieee80211_vif_has_in_place_reservation(sdata))
1415 continue;
1416
1417 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
1418
1419 if (sdata->vif.type == NL80211_IFTYPE_AP)
1420 __ieee80211_vif_copy_chanctx_to_vlans(sdata,
1421 false);
1422
1423 sdata->radar_required = sdata->reserved_radar_required;
1424
1425 if (sdata->vif.bss_conf.chandef.width !=
1426 sdata->reserved_chandef.width)
1427 changed = BSS_CHANGED_BANDWIDTH;
1428
1429 sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
1430 if (changed)
1431 ieee80211_bss_info_change_notify(sdata,
1432 changed);
1433
1434 ieee80211_recalc_txpower(sdata);
1435 }
1436
1437 ieee80211_recalc_chanctx_chantype(local, ctx);
1438 ieee80211_recalc_smps_chanctx(local, ctx);
1439 ieee80211_recalc_radar_chanctx(local, ctx);
1440 ieee80211_recalc_chanctx_min_def(local, ctx);
1441
1442 list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
1443 reserved_chanctx_list) {
1444 if (ieee80211_vif_get_chanctx(sdata) != ctx)
1445 continue;
1446
1447 list_del(&sdata->reserved_chanctx_list);
1448 list_move(&sdata->assigned_chanctx_list,
1449 &ctx->assigned_vifs);
1450 sdata->reserved_chanctx = NULL;
1451
1452 ieee80211_vif_chanctx_reservation_complete(sdata);
1453 }
1454
1455 /*
1456 * This context might have been a dependency for an already
1457 * ready re-assign reservation interface that was deferred. Do
1458 * not propagate error to the caller though. The in-place
1459 * reservation for originally requested interface has already
1460 * succeeded at this point.
1461 */
1462 list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
1463 reserved_chanctx_list) {
1464 if (WARN_ON(ieee80211_vif_has_in_place_reservation(
1465 sdata)))
1466 continue;
1467
1468 if (WARN_ON(sdata->reserved_chanctx != ctx))
1469 continue;
1470
1471 if (!sdata->reserved_ready)
1472 continue;
1473
1474 if (ieee80211_vif_get_chanctx(sdata))
1475 err = ieee80211_vif_use_reserved_reassign(
1476 sdata);
1477 else
1478 err = ieee80211_vif_use_reserved_assign(sdata);
1479
1480 if (err) {
1481 sdata_info(sdata,
1482 "failed to finalize (re-)assign reservation (err=%d)\n",
1483 err);
1484 ieee80211_vif_unreserve_chanctx(sdata);
1485 cfg80211_stop_iface(local->hw.wiphy,
1486 &sdata->wdev,
1487 GFP_KERNEL);
1488 }
1489 }
1490 }
1491
1492 /*
1493 * Finally free old contexts
1494 */
1495
1496 list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) {
1497 if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1498 continue;
1499
1500 ctx->replace_ctx->replace_ctx = NULL;
1501 ctx->replace_ctx->replace_state =
1502 IEEE80211_CHANCTX_REPLACE_NONE;
1503
1504 list_del_rcu(&ctx->list);
1505 kfree_rcu(ctx, rcu_head);
1506 }
1507
1508 return 0;
1509
1510err:
1511 list_for_each_entry(ctx, &local->chanctx_list, list) {
1512 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1513 continue;
1514
1515 list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
1516 reserved_chanctx_list) {
1517 ieee80211_vif_unreserve_chanctx(sdata);
1518 ieee80211_vif_chanctx_reservation_complete(sdata);
1519 }
1520 }
1521
1522 return err;
1523}
1524
1525int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
1526{
1527 struct ieee80211_local *local = sdata->local;
1528 struct ieee80211_chanctx *new_ctx;
1529 struct ieee80211_chanctx *old_ctx;
1530 int err;
1531
1532 lockdep_assert_held(&local->mtx);
1533 lockdep_assert_held(&local->chanctx_mtx);
1534
1535 new_ctx = sdata->reserved_chanctx;
1536 old_ctx = ieee80211_vif_get_chanctx(sdata);
1537
1538 if (WARN_ON(!new_ctx))
1539 return -EINVAL;
1540
1541 if (WARN_ON(new_ctx->replace_state ==
1542 IEEE80211_CHANCTX_WILL_BE_REPLACED))
1543 return -EINVAL;
1544
1545 if (WARN_ON(sdata->reserved_ready))
1546 return -EINVAL;
1547
1548 sdata->reserved_ready = true;
1549
1550 if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) {
1551 if (old_ctx)
1552 err = ieee80211_vif_use_reserved_reassign(sdata);
1553 else
1554 err = ieee80211_vif_use_reserved_assign(sdata);
1555
1556 if (err)
1557 return err;
1558 }
1559
1560 /*
1561 * In-place reservation may need to be finalized now either if:
1562 * a) sdata is taking part in the swapping itself and is the last one
1563 * b) sdata has switched with a re-assign reservation to an existing
1564 * context readying in-place switching of old_ctx
1565 *
1566 * In case of (b) do not propagate the error up because the requested
1567 * sdata already switched successfully. Just spill an extra warning.
1568 * The ieee80211_vif_use_reserved_switch() already stops all necessary
1569 * interfaces upon failure.
1570 */
1571 if ((old_ctx &&
1572 old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1573 new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
1574 err = ieee80211_vif_use_reserved_switch(local);
1575 if (err && err != -EAGAIN) {
1576 if (new_ctx->replace_state ==
1577 IEEE80211_CHANCTX_REPLACES_OTHER)
1578 return err;
1579
1580 wiphy_info(local->hw.wiphy,
1581 "depending in-place reservation failed (err=%d)\n",
1582 err);
1583 }
1584 }
1585
1586 return 0;
1037} 1587}
1038 1588
1039int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, 1589int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
@@ -1043,6 +1593,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
1043 struct ieee80211_local *local = sdata->local; 1593 struct ieee80211_local *local = sdata->local;
1044 struct ieee80211_chanctx_conf *conf; 1594 struct ieee80211_chanctx_conf *conf;
1045 struct ieee80211_chanctx *ctx; 1595 struct ieee80211_chanctx *ctx;
1596 const struct cfg80211_chan_def *compat;
1046 int ret; 1597 int ret;
1047 1598
1048 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, 1599 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
@@ -1069,11 +1620,33 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
1069 } 1620 }
1070 1621
1071 ctx = container_of(conf, struct ieee80211_chanctx, conf); 1622 ctx = container_of(conf, struct ieee80211_chanctx, conf);
1072 if (!cfg80211_chandef_compatible(&conf->def, chandef)) { 1623
1624 compat = cfg80211_chandef_compatible(&conf->def, chandef);
1625 if (!compat) {
1073 ret = -EINVAL; 1626 ret = -EINVAL;
1074 goto out; 1627 goto out;
1075 } 1628 }
1076 1629
1630 switch (ctx->replace_state) {
1631 case IEEE80211_CHANCTX_REPLACE_NONE:
1632 if (!ieee80211_chanctx_reserved_chandef(local, ctx, compat)) {
1633 ret = -EBUSY;
1634 goto out;
1635 }
1636 break;
1637 case IEEE80211_CHANCTX_WILL_BE_REPLACED:
1638 /* TODO: Perhaps the bandwith change could be treated as a
1639 * reservation itself? */
1640 ret = -EBUSY;
1641 goto out;
1642 case IEEE80211_CHANCTX_REPLACES_OTHER:
1643 /* channel context that is going to replace another channel
1644 * context doesn't really exist and shouldn't be assigned
1645 * anywhere yet */
1646 WARN_ON(1);
1647 break;
1648 }
1649
1077 sdata->vif.bss_conf.chandef = *chandef; 1650 sdata->vif.bss_conf.chandef = *chandef;
1078 1651
1079 ieee80211_recalc_chanctx_chantype(local, ctx); 1652 ieee80211_recalc_chanctx_chantype(local, ctx);