summaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh.c
diff options
context:
space:
mode:
authorChun-Yeow Yeoh <yeohchunyeow@cozybit.com>2013-10-17 18:55:02 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-28 10:05:30 -0400
commitb8456a14e9d2770846fcf74de18ff95b676149a3 (patch)
tree858ae69cd2d695116afc582377984070f645ff01 /net/mac80211/mesh.c
parentc6da674aff9425dc41255bcb7f7586a656843f2d (diff)
{nl,cfg,mac}80211: implement mesh channel switch userspace API
Implement the required procedures for mesh channel switching as defined in the IEEE Std 802.11-2012 section 10.9.8.4.3 and also handle the CSA and MCSP elements as followed: * Add the function for updating the beacon and probe response frames with CSA and MCSP elements during the period of switching to the new channel. Both CSA and MCSP elements must be included in beacon and probe response frames until the intended channel switch time. * The ifmsh->csa_settings is set to NULL and the CSA and MCSP elements will then be removed from the beacon or probe response frames once the new channel is switched to. Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
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);