aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/mesh.c139
-rw-r--r--net/mac80211/spectmgmt.c6
2 files changed, 136 insertions, 9 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 6eb31d6fd8e1..896fe3bd599e 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -850,6 +850,127 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
850 ieee80211_configure_filter(local); 850 ieee80211_configure_filter(local);
851} 851}
852 852
853static bool
854ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
855 struct ieee802_11_elems *elems, bool beacon)
856{
857 struct cfg80211_csa_settings params;
858 struct ieee80211_csa_ie csa_ie;
859 struct ieee80211_chanctx_conf *chanctx_conf;
860 struct ieee80211_chanctx *chanctx;
861 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
862 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
863 int err, num_chanctx;
864 u32 sta_flags;
865
866 if (sdata->vif.csa_active)
867 return true;
868
869 if (!ifmsh->mesh_id)
870 return false;
871
872 sta_flags = IEEE80211_STA_DISABLE_VHT;
873 switch (sdata->vif.bss_conf.chandef.width) {
874 case NL80211_CHAN_WIDTH_20_NOHT:
875 sta_flags |= IEEE80211_STA_DISABLE_HT;
876 case NL80211_CHAN_WIDTH_20:
877 sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
878 break;
879 default:
880 break;
881 }
882
883 memset(&params, 0, sizeof(params));
884 memset(&csa_ie, 0, sizeof(csa_ie));
885 err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, band,
886 sta_flags, sdata->vif.addr,
887 &csa_ie);
888 if (err < 0)
889 return false;
890 if (err)
891 return false;
892
893 params.chandef = csa_ie.chandef;
894 params.count = csa_ie.count;
895
896 if (sdata->vif.bss_conf.chandef.chan->band !=
897 params.chandef.chan->band)
898 return false;
899
900 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
901 IEEE80211_CHAN_DISABLED)) {
902 sdata_info(sdata,
903 "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
904 sdata->vif.addr,
905 params.chandef.chan->center_freq,
906 params.chandef.width,
907 params.chandef.center_freq1,
908 params.chandef.center_freq2);
909 return false;
910 }
911
912 err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
913 &params.chandef);
914 if (err < 0)
915 return false;
916 if (err) {
917 params.radar_required = true;
918 /* TODO: DFS not (yet) supported */
919 return false;
920 }
921
922 rcu_read_lock();
923 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
924 if (!chanctx_conf)
925 goto failed_chswitch;
926
927 /* don't handle for multi-VIF cases */
928 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
929 if (chanctx->refcount > 1)
930 goto failed_chswitch;
931
932 num_chanctx = 0;
933 list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
934 num_chanctx++;
935
936 if (num_chanctx > 1)
937 goto failed_chswitch;
938
939 rcu_read_unlock();
940
941 mcsa_dbg(sdata,
942 "received channel switch announcement to go to channel %d MHz\n",
943 params.chandef.chan->center_freq);
944
945 params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
946 if (beacon)
947 ifmsh->chsw_ttl = csa_ie.ttl - 1;
948 else
949 ifmsh->chsw_ttl = 0;
950
951 if (ifmsh->chsw_ttl > 0)
952 if (ieee80211_mesh_csa_beacon(sdata, &params, false) < 0)
953 return false;
954
955 sdata->csa_radar_required = params.radar_required;
956
957 if (params.block_tx)
958 ieee80211_stop_queues_by_reason(&sdata->local->hw,
959 IEEE80211_MAX_QUEUE_MAP,
960 IEEE80211_QUEUE_STOP_REASON_CSA);
961
962 sdata->local->csa_chandef = params.chandef;
963 sdata->vif.csa_active = true;
964
965 ieee80211_bss_info_change_notify(sdata, err);
966 drv_channel_switch_beacon(sdata, &params.chandef);
967
968 return true;
969failed_chswitch:
970 rcu_read_unlock();
971 return false;
972}
973
853static void 974static void
854ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, 975ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
855 struct ieee80211_mgmt *mgmt, size_t len) 976 struct ieee80211_mgmt *mgmt, size_t len)
@@ -956,6 +1077,9 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
956 if (ifmsh->sync_ops) 1077 if (ifmsh->sync_ops)
957 ifmsh->sync_ops->rx_bcn_presp(sdata, 1078 ifmsh->sync_ops->rx_bcn_presp(sdata,
958 stype, mgmt, &elems, rx_status); 1079 stype, mgmt, &elems, rx_status);
1080
1081 if (!ifmsh->chsw_init)
1082 ieee80211_mesh_process_chnswitch(sdata, &elems, true);
959} 1083}
960 1084
961int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) 1085int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
@@ -1056,7 +1180,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
1056 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 1180 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1057 struct ieee802_11_elems elems; 1181 struct ieee802_11_elems elems;
1058 u16 pre_value; 1182 u16 pre_value;
1059 bool block_tx, fwd_csa = true; 1183 bool fwd_csa = true;
1060 size_t baselen; 1184 size_t baselen;
1061 u8 *pos, ttl; 1185 u8 *pos, ttl;
1062 1186
@@ -1079,19 +1203,16 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
1079 1203
1080 ifmsh->pre_value = pre_value; 1204 ifmsh->pre_value = pre_value;
1081 1205
1206 if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
1207 mcsa_dbg(sdata, "Failed to process CSA action frame");
1208 return;
1209 }
1210
1082 /* forward or re-broadcast the CSA frame */ 1211 /* forward or re-broadcast the CSA frame */
1083 if (fwd_csa) { 1212 if (fwd_csa) {
1084 if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0) 1213 if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
1085 mcsa_dbg(sdata, "Failed to forward the CSA frame"); 1214 mcsa_dbg(sdata, "Failed to forward the CSA frame");
1086 } 1215 }
1087
1088 /* block the Tx only after forwarding the CSA frame if required */
1089 block_tx = elems.mesh_chansw_params_ie->mesh_flags &
1090 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
1091 if (block_tx)
1092 ieee80211_stop_queues_by_reason(&sdata->local->hw,
1093 IEEE80211_MAX_QUEUE_MAP,
1094 IEEE80211_QUEUE_STOP_REASON_CSA);
1095} 1216}
1096 1217
1097static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, 1218static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index a298e129633b..a40da20b32e0 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -74,6 +74,12 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
74 return 1; 74 return 1;
75 } 75 }
76 76
77 /* Mesh Channel Switch Parameters Element */
78 if (elems->mesh_chansw_params_ie) {
79 csa_ie->ttl = elems->mesh_chansw_params_ie->mesh_ttl;
80 csa_ie->mode = elems->mesh_chansw_params_ie->mesh_flags;
81 }
82
77 new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); 83 new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
78 new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); 84 new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
79 if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) { 85 if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {