diff options
Diffstat (limited to 'net/mac80211/mesh.c')
-rw-r--r-- | net/mac80211/mesh.c | 98 |
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 | ||
16 | static int mesh_allocated; | 17 | static int mesh_allocated; |
17 | static struct kmem_cache *rm_cache; | 18 | static 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 | ||
961 | int 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 | |||
986 | int 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 | |||
923 | static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, | 1020 | static 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); |