Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: fix the mesh channel switch support

Mesh STA receiving the mesh CSA action frame is not able to trigger
the mesh channel switch due to the incorrect handling and comparison
of mesh channel switch parameters element (MCSP)'s TTL. Make sure
the MCSP's TTL is updated accordingly before calling the
ieee80211_mesh_process_chnswitch. Also, we update the beacon before
forwarding the CSA action frame, so MCSP's precedence value and
initiator flag need to be updated prior to this.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Chun-Yeow Yeoh and committed by
Johannes Berg
3f718fd8 051a41fa

+24 -14
+9 -1
net/mac80211/cfg.c
··· 3119 3119 params->chandef.chan->band) 3120 3120 return -EINVAL; 3121 3121 3122 + ifmsh->chsw_init = true; 3123 + if (!ifmsh->pre_value) 3124 + ifmsh->pre_value = 1; 3125 + else 3126 + ifmsh->pre_value++; 3127 + 3122 3128 err = ieee80211_mesh_csa_beacon(sdata, params, true); 3123 - if (err < 0) 3129 + if (err < 0) { 3130 + ifmsh->chsw_init = false; 3124 3131 return err; 3132 + } 3125 3133 break; 3126 3134 #endif 3127 3135 default:
+1
net/mac80211/ieee80211_i.h
··· 1228 1228 u8 mode; 1229 1229 u8 count; 1230 1230 u8 ttl; 1231 + u16 pre_value; 1231 1232 }; 1232 1233 1233 1234 /* Parsed Information Elements */
+12 -8
net/mac80211/mesh.c
··· 943 943 params.chandef.chan->center_freq); 944 944 945 945 params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT; 946 - if (beacon) 946 + if (beacon) { 947 947 ifmsh->chsw_ttl = csa_ie.ttl - 1; 948 - else 949 - ifmsh->chsw_ttl = 0; 948 + if (ifmsh->pre_value >= csa_ie.pre_value) 949 + return false; 950 + ifmsh->pre_value = csa_ie.pre_value; 951 + } 950 952 951 - if (ifmsh->chsw_ttl > 0) 953 + if (ifmsh->chsw_ttl < ifmsh->mshcfg.dot11MeshTTL) { 952 954 if (ieee80211_mesh_csa_beacon(sdata, &params, false) < 0) 953 955 return false; 956 + } else { 957 + return false; 958 + } 954 959 955 960 sdata->csa_radar_required = params.radar_required; 956 961 ··· 1168 1163 offset_ttl = (len < 42) ? 7 : 10; 1169 1164 *(pos + offset_ttl) -= 1; 1170 1165 *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; 1171 - sdata->u.mesh.chsw_ttl = *(pos + offset_ttl); 1172 1166 1173 1167 memcpy(mgmt_fwd, mgmt, len); 1174 1168 eth_broadcast_addr(mgmt_fwd->da); ··· 1186 1182 u16 pre_value; 1187 1183 bool fwd_csa = true; 1188 1184 size_t baselen; 1189 - u8 *pos, ttl; 1185 + u8 *pos; 1190 1186 1191 1187 if (mgmt->u.action.u.measurement.action_code != 1192 1188 WLAN_ACTION_SPCT_CHL_SWITCH) ··· 1197 1193 u.action.u.chan_switch.variable); 1198 1194 ieee802_11_parse_elems(pos, len - baselen, false, &elems); 1199 1195 1200 - ttl = elems.mesh_chansw_params_ie->mesh_ttl; 1201 - if (!--ttl) 1196 + ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl; 1197 + if (!--ifmsh->chsw_ttl) 1202 1198 fwd_csa = false; 1203 1199 1204 1200 pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
+2
net/mac80211/spectmgmt.c
··· 78 78 if (elems->mesh_chansw_params_ie) { 79 79 csa_ie->ttl = elems->mesh_chansw_params_ie->mesh_ttl; 80 80 csa_ie->mode = elems->mesh_chansw_params_ie->mesh_flags; 81 + csa_ie->pre_value = le16_to_cpu( 82 + elems->mesh_chansw_params_ie->mesh_pre_value); 81 83 } 82 84 83 85 new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
-5
net/mac80211/util.c
··· 2457 2457 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; 2458 2458 put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */ 2459 2459 pos += 2; 2460 - if (!ifmsh->pre_value) 2461 - ifmsh->pre_value = 1; 2462 - else 2463 - ifmsh->pre_value++; 2464 2460 pre_value = cpu_to_le16(ifmsh->pre_value); 2465 2461 memcpy(pos, &pre_value, 2); /* Precedence Value */ 2466 2462 pos += 2; 2467 - ifmsh->chsw_init = true; 2468 2463 } 2469 2464 2470 2465 ieee80211_tx_skb(sdata, skb);