diff options
author | Thomas Pedersen <thomas@cozybit.com> | 2013-02-14 14:20:13 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-15 03:41:40 -0500 |
commit | 2b5e19677592c167d012c2d129407f39d2bdeb8d (patch) | |
tree | db898021baebc1b462b78d00048d0cf9ef3f0aa8 /net | |
parent | 4a3cb702b05868f67c4ee3da3380461c5b90b4ca (diff) |
mac80211: cache mesh beacon
Previously, the entire mesh beacon would be generated each
time the beacon timer fired. Instead generate a beacon
head and tail (so the TIM can easily be inserted when mesh
power save is on) when starting a mesh or the MBSS
parameters change.
Also add a mutex for protecting beacon updates and
preventing leaks.
Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 9 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 154 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 5 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 4 | ||||
-rw-r--r-- | net/mac80211/tx.c | 61 |
6 files changed, 171 insertions, 65 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c3869ba42343..0800fb331ce5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1800,11 +1800,10 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1800 | conf->power_mode = nconf->power_mode; | 1800 | conf->power_mode = nconf->power_mode; |
1801 | ieee80211_mps_local_status_update(sdata); | 1801 | ieee80211_mps_local_status_update(sdata); |
1802 | } | 1802 | } |
1803 | if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) { | 1803 | if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) |
1804 | conf->dot11MeshAwakeWindowDuration = | 1804 | conf->dot11MeshAwakeWindowDuration = |
1805 | nconf->dot11MeshAwakeWindowDuration; | 1805 | nconf->dot11MeshAwakeWindowDuration; |
1806 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 1806 | ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
1807 | } | ||
1808 | return 0; | 1807 | return 0; |
1809 | } | 1808 | } |
1810 | 1809 | ||
@@ -1830,9 +1829,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | |||
1830 | if (err) | 1829 | if (err) |
1831 | return err; | 1830 | return err; |
1832 | 1831 | ||
1833 | ieee80211_start_mesh(sdata); | 1832 | return ieee80211_start_mesh(sdata); |
1834 | |||
1835 | return 0; | ||
1836 | } | 1833 | } |
1837 | 1834 | ||
1838 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | 1835 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d702f7dc321b..388580a1bada 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -580,6 +580,9 @@ struct ieee80211_if_mesh { | |||
580 | u32 mesh_seqnum; | 580 | u32 mesh_seqnum; |
581 | bool accepting_plinks; | 581 | bool accepting_plinks; |
582 | int num_gates; | 582 | int num_gates; |
583 | struct beacon_data __rcu *beacon; | ||
584 | /* just protects beacon updates for now */ | ||
585 | struct mutex mtx; | ||
583 | const u8 *ie; | 586 | const u8 *ie; |
584 | u8 ie_len; | 587 | u8 ie_len; |
585 | enum { | 588 | enum { |
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 | ||
177 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 177 | int 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 | ||
647 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | 647 | static int |
648 | ieee80211_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; | ||
737 | out_free: | ||
738 | kfree(bcn); | ||
739 | dev_kfree_skb(skb); | ||
740 | return -ENOMEM; | ||
741 | } | ||
742 | |||
743 | static int | ||
744 | ieee80211_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); | ||
762 | out: | ||
763 | mutex_unlock(&ifmsh->mtx); | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | void 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 | |||
780 | int 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 | ||
685 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 824 | void 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 | } |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index a1bad310f2e9..1a1da877b1d2 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -239,10 +239,13 @@ void ieee80211s_update_metric(struct ieee80211_local *local, | |||
239 | struct sta_info *sta, struct sk_buff *skb); | 239 | struct sta_info *sta, struct sk_buff *skb); |
240 | void ieee80211s_stop(void); | 240 | void ieee80211s_stop(void); |
241 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | 241 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); |
242 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 242 | int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
243 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 243 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
244 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); | 244 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); |
245 | const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); | 245 | const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); |
246 | /* wrapper for ieee80211_bss_info_change_notify() */ | ||
247 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||
248 | u32 changed); | ||
246 | 249 | ||
247 | /* mesh power save */ | 250 | /* mesh power save */ |
248 | u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata); | 251 | u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 7765139b24aa..f7526e509aa8 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -508,7 +508,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
508 | ieee80211_mps_frame_release(sta, elems); | 508 | ieee80211_mps_frame_release(sta, elems); |
509 | out: | 509 | out: |
510 | rcu_read_unlock(); | 510 | rcu_read_unlock(); |
511 | ieee80211_bss_info_change_notify(sdata, changed); | 511 | ieee80211_mbss_info_change_notify(sdata, changed); |
512 | } | 512 | } |
513 | 513 | ||
514 | static void mesh_plink_timer(unsigned long data) | 514 | static void mesh_plink_timer(unsigned long data) |
@@ -1090,5 +1090,5 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
1090 | rcu_read_unlock(); | 1090 | rcu_read_unlock(); |
1091 | 1091 | ||
1092 | if (changed) | 1092 | if (changed) |
1093 | ieee80211_bss_info_change_notify(sdata, changed); | 1093 | ieee80211_mbss_info_change_notify(sdata, changed); |
1094 | } | 1094 | } |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7d8c629f1e6a..fe644f91ae05 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2444,71 +2444,26 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2444 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2444 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2445 | IEEE80211_STYPE_BEACON); | 2445 | IEEE80211_STYPE_BEACON); |
2446 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2446 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
2447 | struct ieee80211_mgmt *mgmt; | ||
2448 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2447 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2449 | u8 *pos; | 2448 | struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); |
2450 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + | ||
2451 | sizeof(mgmt->u.beacon); | ||
2452 | 2449 | ||
2453 | #ifdef CONFIG_MAC80211_MESH | 2450 | if (!bcn) |
2454 | if (!sdata->u.mesh.mesh_id_len) | ||
2455 | goto out; | 2451 | goto out; |
2456 | #endif | ||
2457 | 2452 | ||
2458 | if (ifmsh->sync_ops) | 2453 | if (ifmsh->sync_ops) |
2459 | ifmsh->sync_ops->adjust_tbtt( | 2454 | ifmsh->sync_ops->adjust_tbtt( |
2460 | sdata); | 2455 | sdata); |
2461 | 2456 | ||
2462 | skb = dev_alloc_skb(local->tx_headroom + | 2457 | skb = dev_alloc_skb(local->tx_headroom + |
2463 | hdr_len + | 2458 | bcn->head_len + |
2464 | 2 + /* NULL SSID */ | ||
2465 | 2 + 8 + /* supported rates */ | ||
2466 | 2 + 3 + /* DS params */ | ||
2467 | 256 + /* TIM IE */ | 2459 | 256 + /* TIM IE */ |
2468 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | 2460 | bcn->tail_len); |
2469 | 2 + sizeof(struct ieee80211_ht_cap) + | ||
2470 | 2 + sizeof(struct ieee80211_ht_operation) + | ||
2471 | 2 + sdata->u.mesh.mesh_id_len + | ||
2472 | 2 + sizeof(struct ieee80211_meshconf_ie) + | ||
2473 | sdata->u.mesh.ie_len + | ||
2474 | 2 + sizeof(__le16)); /* awake window */ | ||
2475 | if (!skb) | 2461 | if (!skb) |
2476 | goto out; | 2462 | goto out; |
2477 | 2463 | skb_reserve(skb, local->tx_headroom); | |
2478 | skb_reserve(skb, local->hw.extra_tx_headroom); | 2464 | memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); |
2479 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 2465 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb); |
2480 | memset(mgmt, 0, hdr_len); | 2466 | memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); |
2481 | mgmt->frame_control = | ||
2482 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); | ||
2483 | eth_broadcast_addr(mgmt->da); | ||
2484 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
2485 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | ||
2486 | ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt); | ||
2487 | mgmt->u.beacon.beacon_int = | ||
2488 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); | ||
2489 | mgmt->u.beacon.capab_info |= cpu_to_le16( | ||
2490 | sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0); | ||
2491 | |||
2492 | pos = skb_put(skb, 2); | ||
2493 | *pos++ = WLAN_EID_SSID; | ||
2494 | *pos++ = 0x0; | ||
2495 | |||
2496 | band = chanctx_conf->def.chan->band; | ||
2497 | |||
2498 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | ||
2499 | mesh_add_ds_params_ie(skb, sdata) || | ||
2500 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb) || | ||
2501 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | ||
2502 | mesh_add_rsn_ie(skb, sdata) || | ||
2503 | mesh_add_ht_cap_ie(skb, sdata) || | ||
2504 | mesh_add_ht_oper_ie(skb, sdata) || | ||
2505 | mesh_add_meshid_ie(skb, sdata) || | ||
2506 | mesh_add_meshconf_ie(skb, sdata) || | ||
2507 | mesh_add_awake_window_ie(skb, sdata) || | ||
2508 | mesh_add_vendor_ies(skb, sdata)) { | ||
2509 | pr_err("o11s: couldn't add ies!\n"); | ||
2510 | goto out; | ||
2511 | } | ||
2512 | } else { | 2467 | } else { |
2513 | WARN_ON(1); | 2468 | WARN_ON(1); |
2514 | goto out; | 2469 | goto out; |