aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mesh.c')
-rw-r--r--net/mac80211/mesh.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 0a3ccaa275f9..6eb31d6fd8e1 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -12,6 +12,7 @@
12#include <asm/unaligned.h> 12#include <asm/unaligned.h>
13#include "ieee80211_i.h" 13#include "ieee80211_i.h"
14#include "mesh.h" 14#include "mesh.h"
15#include "driver-ops.h"
15 16
16static int mesh_allocated; 17static int mesh_allocated;
17static struct kmem_cache *rm_cache; 18static struct kmem_cache *rm_cache;
@@ -610,6 +611,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
610 struct sk_buff *skb; 611 struct sk_buff *skb;
611 struct ieee80211_mgmt *mgmt; 612 struct ieee80211_mgmt *mgmt;
612 struct ieee80211_chanctx_conf *chanctx_conf; 613 struct ieee80211_chanctx_conf *chanctx_conf;
614 struct mesh_csa_settings *csa;
613 enum ieee80211_band band; 615 enum ieee80211_band band;
614 u8 *pos; 616 u8 *pos;
615 struct ieee80211_sub_if_data *sdata; 617 struct ieee80211_sub_if_data *sdata;
@@ -624,6 +626,10 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
624 626
625 head_len = hdr_len + 627 head_len = hdr_len +
626 2 + /* NULL SSID */ 628 2 + /* NULL SSID */
629 /* Channel Switch Announcement */
630 2 + sizeof(struct ieee80211_channel_sw_ie) +
631 /* Mesh Channel Swith Parameters */
632 2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
627 2 + 8 + /* supported rates */ 633 2 + 8 + /* supported rates */
628 2 + 3; /* DS params */ 634 2 + 3; /* DS params */
629 tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) + 635 tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
@@ -665,6 +671,38 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
665 *pos++ = WLAN_EID_SSID; 671 *pos++ = WLAN_EID_SSID;
666 *pos++ = 0x0; 672 *pos++ = 0x0;
667 673
674 rcu_read_lock();
675 csa = rcu_dereference(ifmsh->csa);
676 if (csa) {
677 __le16 pre_value;
678
679 pos = skb_put(skb, 13);
680 memset(pos, 0, 13);
681 *pos++ = WLAN_EID_CHANNEL_SWITCH;
682 *pos++ = 3;
683 *pos++ = 0x0;
684 *pos++ = ieee80211_frequency_to_channel(
685 csa->settings.chandef.chan->center_freq);
686 sdata->csa_counter_offset_beacon = hdr_len + 6;
687 *pos++ = csa->settings.count;
688 *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
689 *pos++ = 6;
690 if (ifmsh->chsw_init) {
691 *pos++ = ifmsh->mshcfg.dot11MeshTTL;
692 *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
693 } else {
694 *pos++ = ifmsh->chsw_ttl;
695 }
696 *pos++ |= csa->settings.block_tx ?
697 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
698 put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
699 pos += 2;
700 pre_value = cpu_to_le16(ifmsh->pre_value);
701 memcpy(pos, &pre_value, 2);
702 pos += 2;
703 }
704 rcu_read_unlock();
705
668 if (ieee80211_add_srates_ie(sdata, skb, true, band) || 706 if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
669 mesh_add_ds_params_ie(sdata, skb)) 707 mesh_add_ds_params_ie(sdata, skb))
670 goto out_free; 708 goto out_free;
@@ -920,6 +958,65 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
920 stype, mgmt, &elems, rx_status); 958 stype, mgmt, &elems, rx_status);
921} 959}
922 960
961int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
962{
963 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
964 struct mesh_csa_settings *tmp_csa_settings;
965 int ret = 0;
966
967 /* Reset the TTL value and Initiator flag */
968 ifmsh->chsw_init = false;
969 ifmsh->chsw_ttl = 0;
970
971 /* Remove the CSA and MCSP elements from the beacon */
972 tmp_csa_settings = rcu_dereference(ifmsh->csa);
973 rcu_assign_pointer(ifmsh->csa, NULL);
974 kfree_rcu(tmp_csa_settings, rcu_head);
975 ret = ieee80211_mesh_rebuild_beacon(sdata);
976 if (ret)
977 return -EINVAL;
978
979 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
980
981 mcsa_dbg(sdata, "complete switching to center freq %d MHz",
982 sdata->vif.bss_conf.chandef.chan->center_freq);
983 return 0;
984}
985
986int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
987 struct cfg80211_csa_settings *csa_settings,
988 bool csa_action)
989{
990 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
991 struct mesh_csa_settings *tmp_csa_settings;
992 int ret = 0;
993
994 tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
995 GFP_ATOMIC);
996 if (!tmp_csa_settings)
997 return -ENOMEM;
998
999 memcpy(&tmp_csa_settings->settings, csa_settings,
1000 sizeof(struct cfg80211_csa_settings));
1001
1002 rcu_assign_pointer(ifmsh->csa, tmp_csa_settings);
1003
1004 ret = ieee80211_mesh_rebuild_beacon(sdata);
1005 if (ret) {
1006 tmp_csa_settings = rcu_dereference(ifmsh->csa);
1007 rcu_assign_pointer(ifmsh->csa, NULL);
1008 kfree_rcu(tmp_csa_settings, rcu_head);
1009 return ret;
1010 }
1011
1012 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
1013
1014 if (csa_action)
1015 ieee80211_send_action_csa(sdata, csa_settings);
1016
1017 return 0;
1018}
1019
923static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, 1020static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
924 struct ieee80211_mgmt *mgmt, size_t len) 1021 struct ieee80211_mgmt *mgmt, size_t len)
925{ 1022{
@@ -942,6 +1039,7 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
942 offset_ttl = (len < 42) ? 7 : 10; 1039 offset_ttl = (len < 42) ? 7 : 10;
943 *(pos + offset_ttl) -= 1; 1040 *(pos + offset_ttl) -= 1;
944 *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; 1041 *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
1042 sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);
945 1043
946 memcpy(mgmt_fwd, mgmt, len); 1044 memcpy(mgmt_fwd, mgmt, len);
947 eth_broadcast_addr(mgmt_fwd->da); 1045 eth_broadcast_addr(mgmt_fwd->da);