aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorChun-Yeow Yeoh <yeohchunyeow@cozybit.com>2013-10-17 18:55:18 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-28 10:05:30 -0400
commit33a45867c56074a23d01e286890e3b61f3ff8fff (patch)
tree8ad0a2f2a4c7ee44d52322b3e837ba609b4bef8a /net/mac80211
parentb8456a14e9d2770846fcf74de18ff95b676149a3 (diff)
mac80211: process mesh channel switching using beacon
Trigger the mesh channel switching procedure if the mesh STA happens to miss the CSA action frame but able to receive the beacon containing the CSA and MCSP elements from its peer mesh STAs. Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com> [fix locking in ieee80211_mesh_process_chnswitch()] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-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) {