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.c154
1 files changed, 151 insertions, 3 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 0adec3d539d3..6ff8ee9d9ff5 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -171,7 +171,7 @@ void mesh_sta_cleanup(struct sta_info *sta)
171 } 171 }
172 172
173 if (changed) 173 if (changed)
174 ieee80211_bss_info_change_notify(sdata, changed); 174 ieee80211_mbss_info_change_notify(sdata, changed);
175} 175}
176 176
177int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) 177int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
@@ -593,7 +593,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
593 mesh_path_expire(sdata); 593 mesh_path_expire(sdata);
594 594
595 changed = mesh_accept_plinks_update(sdata); 595 changed = mesh_accept_plinks_update(sdata);
596 ieee80211_bss_info_change_notify(sdata, changed); 596 ieee80211_mbss_info_change_notify(sdata, changed);
597 597
598 mod_timer(&ifmsh->housekeeping_timer, 598 mod_timer(&ifmsh->housekeeping_timer,
599 round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); 599 round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
@@ -644,7 +644,140 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
644} 644}
645#endif 645#endif
646 646
647void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) 647static int
648ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
649{
650 struct beacon_data *bcn;
651 int head_len, tail_len;
652 struct sk_buff *skb;
653 struct ieee80211_mgmt *mgmt;
654 struct ieee80211_chanctx_conf *chanctx_conf;
655 enum ieee80211_band band;
656 u8 *pos;
657 struct ieee80211_sub_if_data *sdata;
658 int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
659 sizeof(mgmt->u.beacon);
660
661 sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
662 rcu_read_lock();
663 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
664 band = chanctx_conf->def.chan->band;
665 rcu_read_unlock();
666
667 head_len = hdr_len +
668 2 + /* NULL SSID */
669 2 + 8 + /* supported rates */
670 2 + 3; /* DS params */
671 tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
672 2 + sizeof(struct ieee80211_ht_cap) +
673 2 + sizeof(struct ieee80211_ht_operation) +
674 2 + ifmsh->mesh_id_len +
675 2 + sizeof(struct ieee80211_meshconf_ie) +
676 2 + sizeof(__le16) + /* awake window */
677 ifmsh->ie_len;
678
679 bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
680 /* need an skb for IE builders to operate on */
681 skb = dev_alloc_skb(max(head_len, tail_len));
682
683 if (!bcn || !skb)
684 goto out_free;
685
686 /*
687 * pointers go into the block we allocated,
688 * memory is | beacon_data | head | tail |
689 */
690 bcn->head = ((u8 *) bcn) + sizeof(*bcn);
691
692 /* fill in the head */
693 mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
694 memset(mgmt, 0, hdr_len);
695 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
696 IEEE80211_STYPE_BEACON);
697 eth_broadcast_addr(mgmt->da);
698 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
699 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
700 ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt);
701 mgmt->u.beacon.beacon_int =
702 cpu_to_le16(sdata->vif.bss_conf.beacon_int);
703 mgmt->u.beacon.capab_info |= cpu_to_le16(
704 sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
705
706 pos = skb_put(skb, 2);
707 *pos++ = WLAN_EID_SSID;
708 *pos++ = 0x0;
709
710 if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
711 mesh_add_ds_params_ie(skb, sdata))
712 goto out_free;
713
714 bcn->head_len = skb->len;
715 memcpy(bcn->head, skb->data, bcn->head_len);
716
717 /* now the tail */
718 skb_trim(skb, 0);
719 bcn->tail = bcn->head + bcn->head_len;
720
721 if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
722 mesh_add_rsn_ie(skb, sdata) ||
723 mesh_add_ht_cap_ie(skb, sdata) ||
724 mesh_add_ht_oper_ie(skb, sdata) ||
725 mesh_add_meshid_ie(skb, sdata) ||
726 mesh_add_meshconf_ie(skb, sdata) ||
727 mesh_add_awake_window_ie(skb, sdata) ||
728 mesh_add_vendor_ies(skb, sdata))
729 goto out_free;
730
731 bcn->tail_len = skb->len;
732 memcpy(bcn->tail, skb->data, bcn->tail_len);
733
734 dev_kfree_skb(skb);
735 rcu_assign_pointer(ifmsh->beacon, bcn);
736 return 0;
737out_free:
738 kfree(bcn);
739 dev_kfree_skb(skb);
740 return -ENOMEM;
741}
742
743static int
744ieee80211_mesh_rebuild_beacon(struct ieee80211_if_mesh *ifmsh)
745{
746 struct ieee80211_sub_if_data *sdata;
747 struct beacon_data *old_bcn;
748 int ret;
749 sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
750
751 mutex_lock(&ifmsh->mtx);
752
753 old_bcn = rcu_dereference_protected(ifmsh->beacon,
754 lockdep_is_held(&ifmsh->mtx));
755 ret = ieee80211_mesh_build_beacon(ifmsh);
756 if (ret)
757 /* just reuse old beacon */
758 goto out;
759
760 if (old_bcn)
761 kfree_rcu(old_bcn, rcu_head);
762out:
763 mutex_unlock(&ifmsh->mtx);
764 return ret;
765}
766
767void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
768 u32 changed)
769{
770 if (sdata->vif.bss_conf.enable_beacon &&
771 (changed & (BSS_CHANGED_BEACON |
772 BSS_CHANGED_HT |
773 BSS_CHANGED_BASIC_RATES |
774 BSS_CHANGED_BEACON_INT)))
775 if (ieee80211_mesh_rebuild_beacon(&sdata->u.mesh))
776 return;
777 ieee80211_bss_info_change_notify(sdata, changed);
778}
779
780int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
648{ 781{
649 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 782 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
650 struct ieee80211_local *local = sdata->local; 783 struct ieee80211_local *local = sdata->local;
@@ -677,15 +810,22 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
677 810
678 changed |= ieee80211_mps_local_status_update(sdata); 811 changed |= ieee80211_mps_local_status_update(sdata);
679 812
813 if (ieee80211_mesh_build_beacon(ifmsh)) {
814 ieee80211_stop_mesh(sdata);
815 return -ENOMEM;
816 }
817
680 ieee80211_bss_info_change_notify(sdata, changed); 818 ieee80211_bss_info_change_notify(sdata, changed);
681 819
682 netif_carrier_on(sdata->dev); 820 netif_carrier_on(sdata->dev);
821 return 0;
683} 822}
684 823
685void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) 824void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
686{ 825{
687 struct ieee80211_local *local = sdata->local; 826 struct ieee80211_local *local = sdata->local;
688 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 827 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
828 struct beacon_data *bcn;
689 829
690 netif_carrier_off(sdata->dev); 830 netif_carrier_off(sdata->dev);
691 831
@@ -694,6 +834,12 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
694 sdata->vif.bss_conf.enable_beacon = false; 834 sdata->vif.bss_conf.enable_beacon = false;
695 clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); 835 clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
696 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); 836 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
837 mutex_lock(&ifmsh->mtx);
838 bcn = rcu_dereference_protected(ifmsh->beacon,
839 lockdep_is_held(&ifmsh->mtx));
840 rcu_assign_pointer(ifmsh->beacon, NULL);
841 kfree_rcu(bcn, rcu_head);
842 mutex_unlock(&ifmsh->mtx);
697 843
698 /* flush STAs and mpaths on this iface */ 844 /* flush STAs and mpaths on this iface */
699 sta_info_flush(sdata); 845 sta_info_flush(sdata);
@@ -883,6 +1029,8 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
883 skb_queue_head_init(&ifmsh->ps.bc_buf); 1029 skb_queue_head_init(&ifmsh->ps.bc_buf);
884 spin_lock_init(&ifmsh->mesh_preq_queue_lock); 1030 spin_lock_init(&ifmsh->mesh_preq_queue_lock);
885 spin_lock_init(&ifmsh->sync_offset_lock); 1031 spin_lock_init(&ifmsh->sync_offset_lock);
1032 RCU_INIT_POINTER(ifmsh->beacon, NULL);
1033 mutex_init(&ifmsh->mtx);
886 1034
887 sdata->vif.bss_conf.bssid = zero_addr; 1035 sdata->vif.bss_conf.bssid = zero_addr;
888} 1036}