aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/Kconfig11
-rw-r--r--net/mac80211/debug.h10
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/mesh.c83
-rw-r--r--net/mac80211/util.c9
5 files changed, 114 insertions, 3 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index dc31ec3db404..97b5dcad5025 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -259,6 +259,17 @@ config MAC80211_MESH_SYNC_DEBUG
259 259
260 Do not select this option. 260 Do not select this option.
261 261
262config MAC80211_MESH_CSA_DEBUG
263 bool "Verbose mesh channel switch debugging"
264 depends on MAC80211_DEBUG_MENU
265 depends on MAC80211_MESH
266 ---help---
267 Selecting this option causes mac80211 to print out very verbose mesh
268 channel switch debugging messages (when mac80211 is taking part in a
269 mesh network).
270
271 Do not select this option.
272
262config MAC80211_MESH_PS_DEBUG 273config MAC80211_MESH_PS_DEBUG
263 bool "Verbose mesh powersave debugging" 274 bool "Verbose mesh powersave debugging"
264 depends on MAC80211_DEBUG_MENU 275 depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 4ccc5ed6237d..493d68061f0c 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -44,6 +44,12 @@
44#define MAC80211_MESH_SYNC_DEBUG 0 44#define MAC80211_MESH_SYNC_DEBUG 0
45#endif 45#endif
46 46
47#ifdef CONFIG_MAC80211_MESH_CSA_DEBUG
48#define MAC80211_MESH_CSA_DEBUG 1
49#else
50#define MAC80211_MESH_CSA_DEBUG 0
51#endif
52
47#ifdef CONFIG_MAC80211_MESH_PS_DEBUG 53#ifdef CONFIG_MAC80211_MESH_PS_DEBUG
48#define MAC80211_MESH_PS_DEBUG 1 54#define MAC80211_MESH_PS_DEBUG 1
49#else 55#else
@@ -157,6 +163,10 @@ do { \
157 _sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \ 163 _sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \
158 sdata, fmt, ##__VA_ARGS__) 164 sdata, fmt, ##__VA_ARGS__)
159 165
166#define mcsa_dbg(sdata, fmt, ...) \
167 _sdata_dbg(MAC80211_MESH_CSA_DEBUG, \
168 sdata, fmt, ##__VA_ARGS__)
169
160#define mps_dbg(sdata, fmt, ...) \ 170#define mps_dbg(sdata, fmt, ...) \
161 _sdata_dbg(MAC80211_MESH_PS_DEBUG, \ 171 _sdata_dbg(MAC80211_MESH_PS_DEBUG, \
162 sdata, fmt, ##__VA_ARGS__) 172 sdata, fmt, ##__VA_ARGS__)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index cbaea32bccf1..4ebbcc6f67e0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -603,6 +603,9 @@ struct ieee80211_if_mesh {
603 int ps_peers_light_sleep; 603 int ps_peers_light_sleep;
604 int ps_peers_deep_sleep; 604 int ps_peers_deep_sleep;
605 struct ps_data ps; 605 struct ps_data ps;
606 /* Channel Switching Support */
607 bool chsw_init;
608 u16 pre_value;
606}; 609};
607 610
608#ifdef CONFIG_MAC80211_MESH 611#ifdef CONFIG_MAC80211_MESH
@@ -1252,6 +1255,7 @@ struct ieee802_11_elems {
1252 const struct ieee80211_timeout_interval_ie *timeout_int; 1255 const struct ieee80211_timeout_interval_ie *timeout_int;
1253 const u8 *opmode_notif; 1256 const u8 *opmode_notif;
1254 const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; 1257 const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
1258 const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
1255 1259
1256 /* length of them, respectively */ 1260 /* length of them, respectively */
1257 u8 ssid_len; 1261 u8 ssid_len;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 707ac61d63e5..0a3ccaa275f9 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -920,6 +920,82 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
920 stype, mgmt, &elems, rx_status); 920 stype, mgmt, &elems, rx_status);
921} 921}
922 922
923static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
924 struct ieee80211_mgmt *mgmt, size_t len)
925{
926 struct ieee80211_mgmt *mgmt_fwd;
927 struct sk_buff *skb;
928 struct ieee80211_local *local = sdata->local;
929 u8 *pos = mgmt->u.action.u.chan_switch.variable;
930 size_t offset_ttl;
931
932 skb = dev_alloc_skb(local->tx_headroom + len);
933 if (!skb)
934 return -ENOMEM;
935 skb_reserve(skb, local->tx_headroom);
936 mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
937
938 /* offset_ttl is based on whether the secondary channel
939 * offset is available or not. Substract 1 from the mesh TTL
940 * and disable the initiator flag before forwarding.
941 */
942 offset_ttl = (len < 42) ? 7 : 10;
943 *(pos + offset_ttl) -= 1;
944 *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
945
946 memcpy(mgmt_fwd, mgmt, len);
947 eth_broadcast_addr(mgmt_fwd->da);
948 memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
949 memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
950
951 ieee80211_tx_skb(sdata, skb);
952 return 0;
953}
954
955static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
956 struct ieee80211_mgmt *mgmt, size_t len)
957{
958 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
959 struct ieee802_11_elems elems;
960 u16 pre_value;
961 bool block_tx, fwd_csa = true;
962 size_t baselen;
963 u8 *pos, ttl;
964
965 if (mgmt->u.action.u.measurement.action_code !=
966 WLAN_ACTION_SPCT_CHL_SWITCH)
967 return;
968
969 pos = mgmt->u.action.u.chan_switch.variable;
970 baselen = offsetof(struct ieee80211_mgmt,
971 u.action.u.chan_switch.variable);
972 ieee802_11_parse_elems(pos, len - baselen, false, &elems);
973
974 ttl = elems.mesh_chansw_params_ie->mesh_ttl;
975 if (!--ttl)
976 fwd_csa = false;
977
978 pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
979 if (ifmsh->pre_value >= pre_value)
980 return;
981
982 ifmsh->pre_value = pre_value;
983
984 /* forward or re-broadcast the CSA frame */
985 if (fwd_csa) {
986 if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
987 mcsa_dbg(sdata, "Failed to forward the CSA frame");
988 }
989
990 /* block the Tx only after forwarding the CSA frame if required */
991 block_tx = elems.mesh_chansw_params_ie->mesh_flags &
992 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
993 if (block_tx)
994 ieee80211_stop_queues_by_reason(&sdata->local->hw,
995 IEEE80211_MAX_QUEUE_MAP,
996 IEEE80211_QUEUE_STOP_REASON_CSA);
997}
998
923static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, 999static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
924 struct ieee80211_mgmt *mgmt, 1000 struct ieee80211_mgmt *mgmt,
925 size_t len, 1001 size_t len,
@@ -939,6 +1015,9 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
939 if (mesh_action_is_path_sel(mgmt)) 1015 if (mesh_action_is_path_sel(mgmt))
940 mesh_rx_path_sel_frame(sdata, mgmt, len); 1016 mesh_rx_path_sel_frame(sdata, mgmt, len);
941 break; 1017 break;
1018 case WLAN_CATEGORY_SPECTRUM_MGMT:
1019 mesh_rx_csa_frame(sdata, mgmt, len);
1020 break;
942 } 1021 }
943} 1022}
944 1023
@@ -1056,13 +1135,11 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
1056 (unsigned long) sdata); 1135 (unsigned long) sdata);
1057 1136
1058 ifmsh->accepting_plinks = true; 1137 ifmsh->accepting_plinks = true;
1059 ifmsh->preq_id = 0;
1060 ifmsh->sn = 0;
1061 ifmsh->num_gates = 0;
1062 atomic_set(&ifmsh->mpaths, 0); 1138 atomic_set(&ifmsh->mpaths, 0);
1063 mesh_rmc_init(sdata); 1139 mesh_rmc_init(sdata);
1064 ifmsh->last_preq = jiffies; 1140 ifmsh->last_preq = jiffies;
1065 ifmsh->next_perr = jiffies; 1141 ifmsh->next_perr = jiffies;
1142 ifmsh->chsw_init = false;
1066 /* Allocate all mesh structures when creating the first mesh interface. */ 1143 /* Allocate all mesh structures when creating the first mesh interface. */
1067 if (!mesh_allocated) 1144 if (!mesh_allocated)
1068 ieee80211s_init(); 1145 ieee80211s_init();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 65ebe0c5e835..523783cedf6e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -740,6 +740,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
740 case WLAN_EID_TIMEOUT_INTERVAL: 740 case WLAN_EID_TIMEOUT_INTERVAL:
741 case WLAN_EID_SECONDARY_CHANNEL_OFFSET: 741 case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
742 case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: 742 case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
743 case WLAN_EID_CHAN_SWITCH_PARAM:
743 /* 744 /*
744 * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible 745 * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
745 * that if the content gets bigger it might be needed more than once 746 * that if the content gets bigger it might be needed more than once
@@ -905,6 +906,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
905 } 906 }
906 elems->sec_chan_offs = (void *)pos; 907 elems->sec_chan_offs = (void *)pos;
907 break; 908 break;
909 case WLAN_EID_CHAN_SWITCH_PARAM:
910 if (elen !=
911 sizeof(*elems->mesh_chansw_params_ie)) {
912 elem_parse_failed = true;
913 break;
914 }
915 elems->mesh_chansw_params_ie = (void *)pos;
916 break;
908 case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: 917 case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
909 if (!action || 918 if (!action ||
910 elen != sizeof(*elems->wide_bw_chansw_ie)) { 919 elen != sizeof(*elems->wide_bw_chansw_ie)) {