mesh.c revision 33a45867c56074a23d01e286890e3b61f3ff8fff
12e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/*
2264d9b7d8a629620c8de84c614910c3164e935f8Rui Paulo * Copyright (c) 2008, 2009 open80211s Ltd.
32e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Authors:    Luis Carlos Cobo <luisca@cozybit.com>
42e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * 	       Javier Cardona <javier@cozybit.com>
52e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
62e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * This program is free software; you can redistribute it and/or modify
72e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * it under the terms of the GNU General Public License version 2 as
82e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * published by the Free Software Foundation.
92e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
115a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
1251ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo#include <asm/unaligned.h>
132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo#include "ieee80211_i.h"
142e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo#include "mesh.h"
15b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh#include "driver-ops.h"
162e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
17bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic int mesh_allocated;
182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic struct kmem_cache *rm_cache;
192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2025d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersenbool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
2125d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen{
2225d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen	return (mgmt->u.action.u.mesh_action.action_code ==
2325d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen			WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
2425d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen}
2525d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen
262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid ieee80211s_init(void)
272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_pathtbl_init();
292e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_allocated = 1;
302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo				     0, 0, NULL);
322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid ieee80211s_stop(void)
352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
36bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	if (!mesh_allocated)
37bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return;
382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_pathtbl_unregister();
392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	kmem_cache_destroy(rm_cache);
402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
42472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_housekeeping_timer(unsigned long data)
43472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
44472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_sub_if_data *sdata = (void *) data;
45472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
46472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
47472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
486b9ac4425d6ec871faf54540e0f1c5ff420a8f29Rui Paulo	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
495bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
5064592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg	ieee80211_queue_work(&local->hw, &sdata->work);
51472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
52472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
532e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
542e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_matches_local - check if the config of a mesh point matches ours
552e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
56f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene * @sdata: local mesh subif
57f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen * @ie: information elements of a management frame from the mesh peer
582e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
592e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * This function checks if the mesh configuration of a mesh point matches the
602e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * local mesh configuration, i.e. if both nodes belong to the same mesh network.
612e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
62f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersenbool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
63f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen			struct ieee802_11_elems *ie)
642e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
65472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
66f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen	u32 basic_rates = 0;
674bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	struct cfg80211_chan_def sta_chan_def;
682e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/*
702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * As support for each feature is added, check for matching
712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * - On mesh config capabilities
722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Power Save Support En
732e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support enabled
742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support active
752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support required from peer
762e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - MDA enabled
772e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * - Power management control on fc
782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 */
79739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
80739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	     memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
81739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	     (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
82739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	     (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
83739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	     (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
84739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	     (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
85739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	     (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
86bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return false;
87739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen
882103dec14792be2c2194a454630b01120d30e5cbSimon Wunderlich	ieee80211_sta_get_rates(sdata, ie, ieee80211_get_sdata_band(sdata),
89f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen				&basic_rates);
90f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen
91fe40cb6274988852aa5a84440d8f81c00cea4028Ashok Nagarajan	if (sdata->vif.bss_conf.basic_rates != basic_rates)
92bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return false;
93fe40cb6274988852aa5a84440d8f81c00cea4028Ashok Nagarajan
944bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
954bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg				     ie->ht_operation, &sta_chan_def);
964bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg
974bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
984bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg					 &sta_chan_def))
99bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return false;
1002e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
101739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	return true;
1022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1032e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1042e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
1052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links
1062e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
1072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @ie: information elements of a management frame from the mesh peer
1082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
109f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenebool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
1102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
111136cfa28615ccce0f9374811480e0b81c4191ea5Rui Paulo	return (ie->mesh_config->meshconf_cap &
112bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
1132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1142e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1152e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
1162c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings * mesh_accept_plinks_update - update accepting_plink in local mesh beacons
1172e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
118d0709a65181beb787ef3f58cfe45536a2bb254c8Johannes Berg * @sdata: mesh interface in which mesh beacons are going to be updated
119df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch *
120df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch * Returns: beacon changed flag if the beacon content changed.
1212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
122df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porschu32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
1232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1242e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	bool free_plinks;
125df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	u32 changed = 0;
1262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
1282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * the mesh interface might be able to establish plinks with peers that
129b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * are already on the table but are not on PLINK_ESTAB state. However,
130b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * in general the mesh interface is not accepting peer link requests
131b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * from new peers, and that must be reflected in the beacon
1322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 */
1332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	free_plinks = mesh_plink_availables(sdata);
1342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
135df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	if (free_plinks != sdata->u.mesh.accepting_plinks) {
136df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch		sdata->u.mesh.accepting_plinks = free_plinks;
137df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch		changed = BSS_CHANGED_BEACON;
138df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	}
139df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch
140df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	return changed;
1412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
14345b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen/*
14445b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen * mesh_sta_cleanup - clean up any mesh sta state
14545b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen *
14645b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen * @sta: mesh sta to clean up.
14745b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen */
14845b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersenvoid mesh_sta_cleanup(struct sta_info *sta)
14945b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen{
15045b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	struct ieee80211_sub_if_data *sdata = sta->sdata;
15145b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	u32 changed;
15245b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen
15345b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	/*
15445b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	 * maybe userspace handles peer allocation and peering, but in either
15545b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	 * case the beacon is still generated by the kernel and we might need
15645b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	 * an update.
15745b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	 */
15845b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	changed = mesh_accept_plinks_update(sdata);
159a6dad6a26e15f2f9269eea41b756c8cf0971b2bcThomas Pedersen	if (!sdata->u.mesh.user_mpm) {
16045b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen		changed |= mesh_plink_deactivate(sta);
16145b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen		del_timer_sync(&sta->plink_timer);
16245b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	}
16345b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen
164f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	if (changed)
1652b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		ieee80211_mbss_info_change_notify(sdata, changed);
16645b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen}
16745b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen
168f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greeneint mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
1692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
1712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
172472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
173472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!sdata->u.mesh.rmc)
1742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return -ENOMEM;
175472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
1762e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i < RMC_BUCKETS; i++)
177b7cfcd113ac2a1e6b02afc7d283295729fc178a9Thomas Pedersen		INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i]);
1782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return 0;
1792e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1802e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
181f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenevoid mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
1822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
183472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
1842e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct rmc_entry *p, *n;
1852e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
1862e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
187472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!sdata->u.mesh.rmc)
1882e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return;
1892e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
190bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	for (i = 0; i < RMC_BUCKETS; i++) {
191b7cfcd113ac2a1e6b02afc7d283295729fc178a9Thomas Pedersen		list_for_each_entry_safe(p, n, &rmc->bucket[i], list) {
1922e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			list_del(&p->list);
1932e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			kmem_cache_free(rm_cache, p);
1942e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		}
195bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	}
1962e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1972e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	kfree(rmc);
198472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc = NULL;
1992e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2002e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2012e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
2022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
2032e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
204bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg * @sdata:	interface
2052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @sa:		source address
2062e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @mesh_hdr:	mesh_header
2072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
2082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Returns: 0 if the frame is not in the cache, nonzero otherwise.
2092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
2102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Checks using the source address and the mesh sequence number if we have
2112e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * received this frame lately. If the frame is not in the cache, it is added to
2122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * it.
2132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
214bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
215bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		   const u8 *sa, struct ieee80211s_hdr *mesh_hdr)
2162e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
217472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
2182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u32 seqnum = 0;
2192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int entries = 0;
2202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u8 idx;
2212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct rmc_entry *p, *n;
2222e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Don't care about endianness since only match matters */
22451ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
22551ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
226b7cfcd113ac2a1e6b02afc7d283295729fc178a9Thomas Pedersen	list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
2272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		++entries;
2282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		if (time_after(jiffies, p->exp_time) ||
229bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		    entries == RMC_QUEUE_MAX_LEN) {
2302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			list_del(&p->list);
2312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			kmem_cache_free(rm_cache, p);
2322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			--entries;
233bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		} else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa))
2342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			return -1;
2352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
238d15b84590a1d2ec021ada00a0e67ee5851a0ea2bJoe Perches	if (!p)
2392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return 0;
240d15b84590a1d2ec021ada00a0e67ee5851a0ea2bJoe Perches
2412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p->seqnum = seqnum;
2422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p->exp_time = jiffies + RMC_TIMEOUT;
2432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(p->sa, sa, ETH_ALEN);
244b7cfcd113ac2a1e6b02afc7d283295729fc178a9Thomas Pedersen	list_add(&p->list, &rmc->bucket[idx]);
2452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return 0;
2462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2472e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
248bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
249bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			 struct sk_buff *skb)
250082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
251082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
252082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 *pos, neighbors;
253082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
254082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
255082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (skb_tailroom(skb) < 2 + meshconf_len)
256082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return -ENOMEM;
257082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
258082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	pos = skb_put(skb, 2 + meshconf_len);
259082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = WLAN_EID_MESH_CONFIG;
260082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = meshconf_len;
261082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
262082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Active path selection protocol ID */
263082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_pp_id;
264082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Active path selection metric ID   */
265082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_pm_id;
266082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Congestion control mode identifier */
267082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_cc_id;
268082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Synchronization protocol identifier */
269082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_sp_id;
270082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Authentication Protocol identifier */
271082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_auth_id;
272082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Mesh Formation Info - number of neighbors */
2731258d97616fdca9abc0c21f2edeb1d5b21dcb128Ashok Nagarajan	neighbors = atomic_read(&ifmsh->estab_plinks);
274e05ecccdf752122a439b03c3190458d2c8f0bac6Jacob Minshall	neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS);
275082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = neighbors << 1;
276082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Mesh capability */
277b60e527a729cbb9c88b49cc10738a13328cd1ed2Chun-Yeow Yeoh	*pos = 0x00;
278b60e527a729cbb9c88b49cc10738a13328cd1ed2Chun-Yeow Yeoh	*pos |= ifmsh->mshcfg.dot11MeshForwarding ?
279b60e527a729cbb9c88b49cc10738a13328cd1ed2Chun-Yeow Yeoh			IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00;
280dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	*pos |= ifmsh->accepting_plinks ?
281bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
2823f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
2833f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos |= ifmsh->ps_peers_deep_sleep ?
284bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
285dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	*pos++ |= ifmsh->adjusting_tbtt ?
286bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
287082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = 0x00;
288082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
289082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
290082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
291082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
292bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
293082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
294082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
295082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 *pos;
296082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
297082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
298082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return -ENOMEM;
299082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
300082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
301082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = WLAN_EID_MESH_ID;
302082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_id_len;
303082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (ifmsh->mesh_id_len)
304082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
305082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
306082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
307082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
308082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
309bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata,
310bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				    struct sk_buff *skb)
3113f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch{
3123f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
3133f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	u8 *pos;
3143f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3153f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* see IEEE802.11-2012 13.14.6 */
3163f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	if (ifmsh->ps_peers_light_sleep == 0 &&
3173f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	    ifmsh->ps_peers_deep_sleep == 0 &&
3183f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	    ifmsh->nonpeer_pm == NL80211_MESH_POWER_ACTIVE)
3193f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch		return 0;
3203f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3213f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	if (skb_tailroom(skb) < 4)
3223f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch		return -ENOMEM;
3233f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3243f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	pos = skb_put(skb, 2 + 2);
3253f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos++ = WLAN_EID_MESH_AWAKE_WINDOW;
3263f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos++ = 2;
3273f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	put_unaligned_le16(ifmsh->mshcfg.dot11MeshAwakeWindowDuration, pos);
3283f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3293f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	return 0;
3303f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch}
3313f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
332bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
333bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			struct sk_buff *skb)
334082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
335082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
336082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 offset, len;
337082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	const u8 *data;
338082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
339082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (!ifmsh->ie || !ifmsh->ie_len)
340082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return 0;
341082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
342082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* fast-forward to vendor IEs */
343082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
344082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
345082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (offset) {
346082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		len = ifmsh->ie_len - offset;
347082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		data = ifmsh->ie + offset;
348082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (skb_tailroom(skb) < len)
349082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			return -ENOMEM;
350082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(skb_put(skb, len), data, len);
351082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
352082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
353082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
354082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
355082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
356bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
357082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
358082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
359082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 len = 0;
360082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	const u8 *data;
361082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
362082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (!ifmsh->ie || !ifmsh->ie_len)
363082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return 0;
364082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
365082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* find RSN IE */
366082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	data = ifmsh->ie;
367082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	while (data < ifmsh->ie + ifmsh->ie_len) {
368082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (*data == WLAN_EID_RSN) {
369082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			len = data[1] + 2;
370082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			break;
371082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		}
372082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		data++;
373082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
374082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
375082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (len) {
376082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (skb_tailroom(skb) < len)
377082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			return -ENOMEM;
378082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(skb_put(skb, len), data, len);
379082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
380082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
381082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
382082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
383082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
384bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata,
385bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				 struct sk_buff *skb)
386082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
38755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_chanctx_conf *chanctx_conf;
38855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_channel *chan;
389082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 *pos;
3902e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
391082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (skb_tailroom(skb) < 3)
392082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return -ENOMEM;
393082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
39455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_lock();
39555de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
39655de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	if (WARN_ON(!chanctx_conf)) {
39755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		rcu_read_unlock();
39855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		return -EINVAL;
39955de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	}
4004bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	chan = chanctx_conf->def.chan;
40155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_unlock();
40255de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
403601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	pos = skb_put(skb, 2 + 1);
404601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = WLAN_EID_DS_PARAMS;
405601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = 1;
406601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
407be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo
408082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
4092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
4102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
411bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
412bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		       struct sk_buff *skb)
413176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen{
414176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_local *local = sdata->local;
41555de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
416176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_supported_band *sband;
417176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	u8 *pos;
418176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
41955de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	sband = local->hw.wiphy->bands[band];
420176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (!sband->ht_cap.ht_supported ||
4210418a445838749c51cf1e31a9c7ace6685ae87cdSimon Wunderlich	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
4220418a445838749c51cf1e31a9c7ace6685ae87cdSimon Wunderlich	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
4230418a445838749c51cf1e31a9c7ace6685ae87cdSimon Wunderlich	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
424176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return 0;
425176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
426176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
427176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return -ENOMEM;
428176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
429176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
430ef96a84202ccfb48a4569256ffba45e32308f7eeBen Greear	ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
431176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
432176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	return 0;
433176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen}
434176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
435bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
436bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			struct sk_buff *skb)
437176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen{
438176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_local *local = sdata->local;
43955de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_chanctx_conf *chanctx_conf;
44055de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_channel *channel;
441466f310d100ff54f346c1be481af9935c42467b3Johannes Berg	enum nl80211_channel_type channel_type =
4424bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg		cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef);
44355de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_supported_band *sband;
44455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_sta_ht_cap *ht_cap;
445176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	u8 *pos;
446176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
44755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_lock();
44855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
44955de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	if (WARN_ON(!chanctx_conf)) {
45055de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		rcu_read_unlock();
45155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		return -EINVAL;
45255de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	}
4534bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	channel = chanctx_conf->def.chan;
45455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_unlock();
45555de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
45655de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	sband = local->hw.wiphy->bands[channel->band];
45755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	ht_cap = &sband->ht_cap;
45855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
459176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
460176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return 0;
461176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
462074d46d1d23f27488a3f314e29cae2453541f17dJohannes Berg	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
463176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return -ENOMEM;
464176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
465074d46d1d23f27488a3f314e29cae2453541f17dJohannes Berg	pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
4664bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
467431e31542383b71bc5f2642572a1e6ef07f1bb87Ashok Nagarajan				   sdata->vif.bss_conf.ht_operation_mode);
468176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
469176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	return 0;
470176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen}
471bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
4722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic void ieee80211_mesh_path_timer(unsigned long data)
4732e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
4742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_sub_if_data *sdata =
4752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		(struct ieee80211_sub_if_data *) data;
4765bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
477690205f18fd069898c70d743f498ba42798e5c4eStanislaw Gruszka	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
4782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
4792e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
480e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulostatic void ieee80211_mesh_path_root_timer(unsigned long data)
481e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo{
482e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_sub_if_data *sdata =
483e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		(struct ieee80211_sub_if_data *) data;
484e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
485e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
486e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
487e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
488690205f18fd069898c70d743f498ba42798e5c4eStanislaw Gruszka	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
489e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo}
490e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
49163c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulovoid ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
49263c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo{
493dbb912cd4ce64e763c5610b49a85529d2634e9d8Chun-Yeow Yeoh	if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)
49463c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
49563c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	else {
49663c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
49763c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		/* stop running timer */
49863c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		del_timer_sync(&ifmsh->mesh_path_root_timer);
49963c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	}
50063c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo}
50163c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo
502902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg/**
5033c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
504bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg * @hdr:	802.11 frame header
5053c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @fc:		frame control field
5063c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @meshda:	destination address in the mesh
5073c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @meshsa:	source address address in the mesh.  Same as TA, as frame is
5083c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *              locally originated.
5093c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *
5103c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * Return the length of the 802.11 (does not include a mesh control header)
5113c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona */
51215ff63653e507ec928a4a4386405a82446e096b1Johannes Bergint ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
51315ff63653e507ec928a4a4386405a82446e096b1Johannes Berg				  const u8 *meshda, const u8 *meshsa)
51415ff63653e507ec928a4a4386405a82446e096b1Johannes Berg{
5153c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	if (is_multicast_ether_addr(meshda)) {
5163c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
5173c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		/* DA TA SA */
5183c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr1, meshda, ETH_ALEN);
5193c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr2, meshsa, ETH_ALEN);
5203c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr3, meshsa, ETH_ALEN);
5213c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		return 24;
5223c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	} else {
5232154c81c32fa44364f83218a10d8dbec4e76d4f5Javier Cardona		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
5243c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		/* RA TA DA SA */
5253c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memset(hdr->addr1, 0, ETH_ALEN);   /* RA is resolved later */
5263c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr2, meshsa, ETH_ALEN);
5273c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr3, meshda, ETH_ALEN);
5283c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr4, meshsa, ETH_ALEN);
5293c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		return 30;
5303c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
5313c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona}
5323c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona
5333c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona/**
534902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * ieee80211_new_mesh_header - create a new mesh header
535902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * @sdata:	mesh interface to be used
536bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg * @meshhdr:    uninitialized mesh header
53761ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona * @addr4or5:   1st address in the ae header, which may correspond to address 4
53861ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              (if addr6 is NULL) or address 5 (if addr6 is present). It may
53961ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              be NULL.
54061ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona * @addr6:	2nd address in the ae header, which corresponds to addr6 of the
54161ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              mesh frame
542902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg *
543902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * Return the header length.
544902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg */
545bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
546bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			      struct ieee80211s_hdr *meshhdr,
547bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			      const char *addr4or5, const char *addr6)
548902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
549bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	if (WARN_ON(!addr4or5 && addr6))
550bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 0;
551bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
5520c3cee72a403e3b4992a5478c9c33d668c246c22Julia Lawall	memset(meshhdr, 0, sizeof(*meshhdr));
553bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
554472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
555bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
556bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	/* FIXME: racy -- TX on multiple queues can be concurrent */
557472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
558472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.mesh_seqnum++;
559bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
56061ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona	if (addr4or5 && !addr6) {
5613c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		meshhdr->flags |= MESH_FLAGS_AE_A4;
56261ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
563bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 2 * ETH_ALEN;
56461ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona	} else if (addr4or5 && addr6) {
5653c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
56661ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
56761ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
568bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 3 * ETH_ALEN;
5693c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
570bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
571bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	return ETH_ALEN;
572902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg}
573902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg
574bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
575472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
576bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
577df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	u32 changed;
578472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
57966de671374f003467b5ef7c65ecbe1930480c8c9Colleen Twitty	ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
580472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mesh_path_expire(sdata);
581472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
582df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	changed = mesh_accept_plinks_update(sdata);
5832b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	ieee80211_mbss_info_change_notify(sdata, changed);
584472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
585472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mod_timer(&ifmsh->housekeeping_timer,
586bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		  round_jiffies(jiffies +
587bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
588472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
589472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
590e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulostatic void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
591e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo{
592e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
593a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	u32 interval;
594e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
595e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	mesh_path_tx_root_frame(sdata);
596a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh
597a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN)
598a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
599a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	else
600a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		interval = ifmsh->mshcfg.dot11MeshHWMProotInterval;
601a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh
602e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	mod_timer(&ifmsh->mesh_path_root_timer,
603a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		  round_jiffies(TU_TO_EXP_TIME(interval)));
604e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo}
605e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
6062b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenstatic int
6072b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
6082b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
6092b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *bcn;
6102b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int head_len, tail_len;
6112b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct sk_buff *skb;
6122b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_mgmt *mgmt;
6132b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_chanctx_conf *chanctx_conf;
614b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct mesh_csa_settings *csa;
6152b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	enum ieee80211_band band;
6162b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	u8 *pos;
6172b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_sub_if_data *sdata;
6182b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
6192b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		      sizeof(mgmt->u.beacon);
6202b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6212b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
6222b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_read_lock();
6232b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
6242b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	band = chanctx_conf->def.chan->band;
6252b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_read_unlock();
6262b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6272b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	head_len = hdr_len +
6282b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + /* NULL SSID */
629b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		   /* Channel Switch Announcement */
630b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		   2 + sizeof(struct ieee80211_channel_sw_ie) +
631b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		   /* Mesh Channel Swith Parameters */
632b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		   2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
6332b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + 8 + /* supported rates */
6342b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + 3; /* DS params */
6352b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
6362b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_ht_cap) +
6372b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_ht_operation) +
6382b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + ifmsh->mesh_id_len +
6392b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_meshconf_ie) +
6402b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(__le16) + /* awake window */
6412b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   ifmsh->ie_len;
6422b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6432b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
6442b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/* need an skb for IE builders to operate on */
6452b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	skb = dev_alloc_skb(max(head_len, tail_len));
6462b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6472b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (!bcn || !skb)
6482b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		goto out_free;
6492b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6502b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/*
6512b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 * pointers go into the block we allocated,
6522b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 * memory is | beacon_data | head | tail |
6532b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 */
6542b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->head = ((u8 *) bcn) + sizeof(*bcn);
6552b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6562b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/* fill in the head */
6572b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
6582b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memset(mgmt, 0, hdr_len);
6592b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
6602b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen					  IEEE80211_STYPE_BEACON);
6612b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	eth_broadcast_addr(mgmt->da);
6622b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
6632b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
6642b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt);
6652b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->u.beacon.beacon_int =
6662b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		cpu_to_le16(sdata->vif.bss_conf.beacon_int);
6672b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->u.beacon.capab_info |= cpu_to_le16(
6682b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
6692b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6702b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	pos = skb_put(skb, 2);
6712b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	*pos++ = WLAN_EID_SSID;
6722b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	*pos++ = 0x0;
6732b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
674b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	rcu_read_lock();
675b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	csa = rcu_dereference(ifmsh->csa);
676b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (csa) {
677b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		__le16 pre_value;
678b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
679b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		pos = skb_put(skb, 13);
680b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		memset(pos, 0, 13);
681b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = WLAN_EID_CHANNEL_SWITCH;
682b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = 3;
683b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = 0x0;
684b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = ieee80211_frequency_to_channel(
685b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh				csa->settings.chandef.chan->center_freq);
686b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		sdata->csa_counter_offset_beacon = hdr_len + 6;
687b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = csa->settings.count;
688b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
689b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = 6;
690b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		if (ifmsh->chsw_init) {
691b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			*pos++ = ifmsh->mshcfg.dot11MeshTTL;
692b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			*pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
693b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		} else {
694b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			*pos++ = ifmsh->chsw_ttl;
695b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		}
696b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ |= csa->settings.block_tx ?
697b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			  WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
698b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
699b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		pos += 2;
700b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		pre_value = cpu_to_le16(ifmsh->pre_value);
701b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		memcpy(pos, &pre_value, 2);
702b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		pos += 2;
703b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	}
704b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	rcu_read_unlock();
705b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
7062b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
707bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_ds_params_ie(sdata, skb))
7082b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		goto out_free;
7092b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7102b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->head_len = skb->len;
7112b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(bcn->head, skb->data, bcn->head_len);
7122b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7132b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/* now the tail */
7142b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	skb_trim(skb, 0);
7152b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->tail = bcn->head + bcn->head_len;
7162b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7172b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
718bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_rsn_ie(sdata, skb) ||
719bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_ht_cap_ie(sdata, skb) ||
720bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_ht_oper_ie(sdata, skb) ||
721bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_meshid_ie(sdata, skb) ||
722bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_meshconf_ie(sdata, skb) ||
723bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_awake_window_ie(sdata, skb) ||
724bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_vendor_ies(sdata, skb))
7252b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		goto out_free;
7262b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7272b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->tail_len = skb->len;
7282b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(bcn->tail, skb->data, bcn->tail_len);
7292b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7302b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	dev_kfree_skb(skb);
7312b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_assign_pointer(ifmsh->beacon, bcn);
7322b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return 0;
7332b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenout_free:
7342b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	kfree(bcn);
7352b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	dev_kfree_skb(skb);
7362b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return -ENOMEM;
7372b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
7382b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7392b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenstatic int
7408d61ffa5e01c5f676431d12caba17db164a48a86Johannes Bergieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata)
7412b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
7422b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *old_bcn;
7432b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int ret;
7442b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7458d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg	old_bcn = rcu_dereference_protected(sdata->u.mesh.beacon,
7468d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg					    lockdep_is_held(&sdata->wdev.mtx));
7478d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg	ret = ieee80211_mesh_build_beacon(&sdata->u.mesh);
7482b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ret)
7492b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		/* just reuse old beacon */
7508d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg		return ret;
7512b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7522b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (old_bcn)
7532b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		kfree_rcu(old_bcn, rcu_head);
7548d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg	return 0;
7552b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
7562b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7572b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenvoid ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
7582b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen				       u32 changed)
7592b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
760f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
761f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	unsigned long bits = changed;
762f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	u32 bit;
763f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
764f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	if (!bits)
765f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		return;
766f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
767f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	/* if we race with running work, worst case this work becomes a noop */
768f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
769f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		set_bit(bit, &ifmsh->mbss_changed);
770f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
771f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
7722b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
7732b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7742b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenint ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
775472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
776472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
777472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
778f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh	u32 changed = BSS_CHANGED_BEACON |
779f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BEACON_ENABLED |
780f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_HT |
781f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BASIC_RATES |
782f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BEACON_INT;
783472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
78409b174702601079c3a04806754be30ffbd70db4dJohannes Berg	local->fif_other_bss++;
78509b174702601079c3a04806754be30ffbd70db4dJohannes Berg	/* mesh ifaces must set allmulti to forward mcast traffic */
78609b174702601079c3a04806754be30ffbd70db4dJohannes Berg	atomic_inc(&local->iff_allmultis);
78709b174702601079c3a04806754be30ffbd70db4dJohannes Berg	ieee80211_configure_filter(local);
78809b174702601079c3a04806754be30ffbd70db4dJohannes Berg
789c7108a7111cd9e592d6ad498be37276dbea75d2bJavier Cardona	ifmsh->mesh_cc_id = 0;	/* Disabled */
790dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	/* register sync ops from extensible synchronization framework */
791dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id);
792dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->adjusting_tbtt = false;
793dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->sync_offset_clockdrift_max = 0;
7946b9ac4425d6ec871faf54540e0f1c5ff420a8f29Rui Paulo	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
79563c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	ieee80211_mesh_root_setup(ifmsh);
79664592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg	ieee80211_queue_work(&local->hw, &sdata->work);
79770c33eaae79e53f9e48324736c0cb85534d3f093Ashok Nagarajan	sdata->vif.bss_conf.ht_operation_mode =
79870c33eaae79e53f9e48324736c0cb85534d3f093Ashok Nagarajan				ifmsh->mshcfg.ht_opmode;
799d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	sdata->vif.bss_conf.enable_beacon = true;
800f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh
80139886b618aba3c39e650c191d601e26ec581ce0fThomas Pedersen	changed |= ieee80211_mps_local_status_update(sdata);
8023f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
8032b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ieee80211_mesh_build_beacon(ifmsh)) {
8042b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		ieee80211_stop_mesh(sdata);
8052b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		return -ENOMEM;
8062b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	}
8072b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
808f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, changed);
809c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg
810c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg	netif_carrier_on(sdata->dev);
8112b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return 0;
812472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
813472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
814472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
815472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
81609b174702601079c3a04806754be30ffbd70db4dJohannes Berg	struct ieee80211_local *local = sdata->local;
81729cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
8182b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *bcn;
81929cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg
820c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg	netif_carrier_off(sdata->dev);
821c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg
8220d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	/* stop the beacon */
82329cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	ifmsh->mesh_id_len = 0;
824d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	sdata->vif.bss_conf.enable_beacon = false;
825d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
82629cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
8272b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn = rcu_dereference_protected(ifmsh->beacon,
8288d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg					lockdep_is_held(&sdata->wdev.mtx));
8292b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_assign_pointer(ifmsh->beacon, NULL);
8302b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	kfree_rcu(bcn, rcu_head);
8310d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen
8320d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	/* flush STAs and mpaths on this iface */
833b998e8bb3e1c6eeae5eab9d6a434563270286c3bJohannes Berg	sta_info_flush(sdata);
8340d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	mesh_path_flush_by_iface(sdata);
83509b174702601079c3a04806754be30ffbd70db4dJohannes Berg
8363f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* free all potentially still buffered group-addressed frames */
8373f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	local->total_ps_buffered -= skb_queue_len(&ifmsh->ps.bc_buf);
8383f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	skb_queue_purge(&ifmsh->ps.bc_buf);
8393f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
840472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
841e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
842dd4c9260e7f23f2e951cbfb2726e468c6d30306cJohannes Berg	del_timer_sync(&sdata->u.mesh.mesh_path_timer);
84309b174702601079c3a04806754be30ffbd70db4dJohannes Berg
844f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	/* clear any mesh work (for next join) we may have accrued */
845f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	ifmsh->wrkq_flags = 0;
846f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	ifmsh->mbss_changed = 0;
847f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
84809b174702601079c3a04806754be30ffbd70db4dJohannes Berg	local->fif_other_bss--;
84909b174702601079c3a04806754be30ffbd70db4dJohannes Berg	atomic_dec(&local->iff_allmultis);
85009b174702601079c3a04806754be30ffbd70db4dJohannes Berg	ieee80211_configure_filter(local);
851472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
852472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
85333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeohstatic bool
85433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeohieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
85533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh				 struct ieee802_11_elems *elems, bool beacon)
85633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh{
85733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct cfg80211_csa_settings params;
85833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct ieee80211_csa_ie csa_ie;
85933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct ieee80211_chanctx_conf *chanctx_conf;
86033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct ieee80211_chanctx *chanctx;
86133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
86233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
86333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	int err, num_chanctx;
86433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	u32 sta_flags;
86533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
86633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (sdata->vif.csa_active)
86733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return true;
86833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
86933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!ifmsh->mesh_id)
87033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
87133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
87233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	sta_flags = IEEE80211_STA_DISABLE_VHT;
87333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	switch (sdata->vif.bss_conf.chandef.width) {
87433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	case NL80211_CHAN_WIDTH_20_NOHT:
87533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		sta_flags |= IEEE80211_STA_DISABLE_HT;
87633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	case NL80211_CHAN_WIDTH_20:
87733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
87833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		break;
87933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	default:
88033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		break;
88133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	}
88233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
88333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	memset(&params, 0, sizeof(params));
88433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	memset(&csa_ie, 0, sizeof(csa_ie));
88533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, band,
88633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh					   sta_flags, sdata->vif.addr,
88733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh					   &csa_ie);
88833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (err < 0)
88933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
89033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (err)
89133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
89233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
89333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	params.chandef = csa_ie.chandef;
89433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	params.count = csa_ie.count;
89533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
89633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (sdata->vif.bss_conf.chandef.chan->band !=
89733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	    params.chandef.chan->band)
89833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
89933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
90033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
90133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh				     IEEE80211_CHAN_DISABLED)) {
90233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		sdata_info(sdata,
90333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
90433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   sdata->vif.addr,
90533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   params.chandef.chan->center_freq,
90633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   params.chandef.width,
90733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   params.chandef.center_freq1,
90833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   params.chandef.center_freq2);
90933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
91033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	}
91133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
91233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
91333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh					    &params.chandef);
91433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (err < 0)
91533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
91633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (err) {
91733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		params.radar_required = true;
91833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		/* TODO: DFS not (yet) supported */
91933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
92033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	}
92133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
92233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	rcu_read_lock();
92333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
92433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!chanctx_conf)
92533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		goto failed_chswitch;
92633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
92733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	/* don't handle for multi-VIF cases */
92833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
92933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (chanctx->refcount > 1)
93033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		goto failed_chswitch;
93133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
93233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	num_chanctx = 0;
93333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
93433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		num_chanctx++;
93533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
93633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (num_chanctx > 1)
93733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		goto failed_chswitch;
93833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
93933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	rcu_read_unlock();
94033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
94133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	mcsa_dbg(sdata,
94233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		 "received channel switch announcement to go to channel %d MHz\n",
94333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		 params.chandef.chan->center_freq);
94433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
94533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
94633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (beacon)
94733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		ifmsh->chsw_ttl = csa_ie.ttl - 1;
94833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	else
94933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		ifmsh->chsw_ttl = 0;
95033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
95133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (ifmsh->chsw_ttl > 0)
95233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		if (ieee80211_mesh_csa_beacon(sdata, &params, false) < 0)
95333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			return false;
95433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
95533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	sdata->csa_radar_required = params.radar_required;
95633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
95733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (params.block_tx)
95833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		ieee80211_stop_queues_by_reason(&sdata->local->hw,
95933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh				IEEE80211_MAX_QUEUE_MAP,
96033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh				IEEE80211_QUEUE_STOP_REASON_CSA);
96133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
96233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	sdata->local->csa_chandef = params.chandef;
96333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	sdata->vif.csa_active = true;
96433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
96533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, err);
96633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	drv_channel_switch_beacon(sdata, &params.chandef);
96733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
96833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	return true;
96933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeohfailed_chswitch:
97033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	rcu_read_unlock();
97133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	return false;
97233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh}
97333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
9749fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenstatic void
9759fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
9769fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen			    struct ieee80211_mgmt *mgmt, size_t len)
9779fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen{
9789fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_local *local = sdata->local;
9799fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
9809fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct sk_buff *presp;
9819fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct beacon_data *bcn;
9829fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_mgmt *hdr;
9839fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee802_11_elems elems;
9849fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	size_t baselen;
985511044ea0bfc06614d903263ad094d1071fa172fJohannes Berg	u8 *pos;
9869fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
9879fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	pos = mgmt->u.probe_req.variable;
9889fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	baselen = (u8 *) pos - (u8 *) mgmt;
9899fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (baselen > len)
9909fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
9919fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
992b2e506bfc4d752b68a0ccaae1e977898263eba4cJohannes Berg	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
9939fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
994a4ef66a915b957416a89a48365aea2ec2dc551f6Chun-Yeow Yeoh	if (!elems.mesh_id)
995a4ef66a915b957416a89a48365aea2ec2dc551f6Chun-Yeow Yeoh		return;
996a4ef66a915b957416a89a48365aea2ec2dc551f6Chun-Yeow Yeoh
9979fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	/* 802.11-2012 10.1.4.3.2 */
9989fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
9999fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	     !is_broadcast_ether_addr(mgmt->da)) ||
10009fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	    elems.ssid_len != 0)
10019fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
10029fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10039fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (elems.mesh_id_len != 0 &&
10049fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	    (elems.mesh_id_len != ifmsh->mesh_id_len ||
10059fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	     memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
10069fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
10079fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10089fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	rcu_read_lock();
10099fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	bcn = rcu_dereference(ifmsh->beacon);
10109fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10119fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (!bcn)
10129fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		goto out;
10139fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10149fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	presp = dev_alloc_skb(local->tx_headroom +
10159fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen			      bcn->head_len + bcn->tail_len);
10169fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (!presp)
10179fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		goto out;
10189fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10199fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	skb_reserve(presp, local->tx_headroom);
10209fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(skb_put(presp, bcn->head_len), bcn->head, bcn->head_len);
10219fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(skb_put(presp, bcn->tail_len), bcn->tail, bcn->tail_len);
10229fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	hdr = (struct ieee80211_mgmt *) presp->data;
10239fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
10249fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen					 IEEE80211_STYPE_PROBE_RESP);
10259fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(hdr->da, mgmt->sa, ETH_ALEN);
10269fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
10279fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	ieee80211_tx_skb(sdata, presp);
10289fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenout:
10299fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	rcu_read_unlock();
10309fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen}
10319fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
1032472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
1033472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					u16 stype,
1034472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					struct ieee80211_mgmt *mgmt,
1035472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					size_t len,
1036472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					struct ieee80211_rx_status *rx_status)
1037472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1038c6a1fa12d206882757264869f8e32d606b930e2aJohannes Berg	struct ieee80211_local *local = sdata->local;
1039dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1040472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee802_11_elems elems;
1041472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_channel *channel;
1042472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	size_t baselen;
1043472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	int freq;
1044472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	enum ieee80211_band band = rx_status->band;
1045472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1046472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	/* ignore ProbeResp to foreign address */
1047472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (stype == IEEE80211_STYPE_PROBE_RESP &&
1048b203ca39126bad99583c908be587df067820a1eaJoe Perches	    !ether_addr_equal(mgmt->da, sdata->vif.addr))
1049472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
1050472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1051472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
1052472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (baselen > len)
1053472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
1054472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1055472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
1056b2e506bfc4d752b68a0ccaae1e977898263eba4cJohannes Berg			       false, &elems);
1057472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
10589a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	/* ignore non-mesh or secure / unsecure mismatch */
10599a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	if ((!elems.mesh_id || !elems.mesh_config) ||
10609a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	    (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
10619a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	    (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
10625cff5e01e818029a5d2c3c31b7ae5e5e7ee70452Javier Cardona		return;
10635cff5e01e818029a5d2c3c31b7ae5e5e7ee70452Javier Cardona
10641cd8e88e17729f57a9c7f751103e522596bb5de2Johannes Berg	if (elems.ds_params)
106559eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
1066472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	else
1067472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		freq = rx_status->freq;
1068472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1069472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	channel = ieee80211_get_channel(local->hw.wiphy, freq);
1070472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1071472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
1072472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
1073472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
10749a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	if (mesh_matches_local(sdata, &elems))
1075f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen		mesh_neighbour_update(sdata, mgmt->sa, &elems);
1076dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona
1077dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	if (ifmsh->sync_ops)
1078dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona		ifmsh->sync_ops->rx_bcn_presp(sdata,
1079dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona			stype, mgmt, &elems, rx_status);
108033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
108133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!ifmsh->chsw_init)
108233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		ieee80211_mesh_process_chnswitch(sdata, &elems, true);
1083472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1084472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1085b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeohint ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
1086b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh{
1087b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1088b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct mesh_csa_settings *tmp_csa_settings;
1089b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	int ret = 0;
1090b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1091b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	/* Reset the TTL value and Initiator flag */
1092b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ifmsh->chsw_init = false;
1093b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ifmsh->chsw_ttl = 0;
1094b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1095b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	/* Remove the CSA and MCSP elements from the beacon */
1096b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	tmp_csa_settings = rcu_dereference(ifmsh->csa);
1097b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	rcu_assign_pointer(ifmsh->csa, NULL);
1098b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	kfree_rcu(tmp_csa_settings, rcu_head);
1099b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ret = ieee80211_mesh_rebuild_beacon(sdata);
1100b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (ret)
1101b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		return -EINVAL;
1102b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1103b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
1104b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1105b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	mcsa_dbg(sdata, "complete switching to center freq %d MHz",
1106b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		 sdata->vif.bss_conf.chandef.chan->center_freq);
1107b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	return 0;
1108b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh}
1109b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1110b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeohint ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
1111b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			      struct cfg80211_csa_settings *csa_settings,
1112b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			      bool csa_action)
1113b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh{
1114b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1115b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct mesh_csa_settings *tmp_csa_settings;
1116b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	int ret = 0;
1117b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1118b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
1119b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh				   GFP_ATOMIC);
1120b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (!tmp_csa_settings)
1121b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		return -ENOMEM;
1122b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1123b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	memcpy(&tmp_csa_settings->settings, csa_settings,
1124b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	       sizeof(struct cfg80211_csa_settings));
1125b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1126b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	rcu_assign_pointer(ifmsh->csa, tmp_csa_settings);
1127b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1128b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ret = ieee80211_mesh_rebuild_beacon(sdata);
1129b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (ret) {
1130b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		tmp_csa_settings = rcu_dereference(ifmsh->csa);
1131b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		rcu_assign_pointer(ifmsh->csa, NULL);
1132b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		kfree_rcu(tmp_csa_settings, rcu_head);
1133b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		return ret;
1134b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	}
1135b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1136b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
1137b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1138b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (csa_action)
1139b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		ieee80211_send_action_csa(sdata, csa_settings);
1140b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1141b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	return 0;
1142b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh}
1143b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
11448f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeohstatic int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
11458f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh			       struct ieee80211_mgmt *mgmt, size_t len)
11468f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh{
11478f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct ieee80211_mgmt *mgmt_fwd;
11488f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct sk_buff *skb;
11498f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct ieee80211_local *local = sdata->local;
11508f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	u8 *pos = mgmt->u.action.u.chan_switch.variable;
11518f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	size_t offset_ttl;
11528f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11538f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	skb = dev_alloc_skb(local->tx_headroom + len);
11548f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (!skb)
11558f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		return -ENOMEM;
11568f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	skb_reserve(skb, local->tx_headroom);
11578f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
11588f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11598f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	/* offset_ttl is based on whether the secondary channel
11608f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	 * offset is available or not. Substract 1 from the mesh TTL
11618f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	 * and disable the initiator flag before forwarding.
11628f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	 */
11638f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	offset_ttl = (len < 42) ? 7 : 10;
11648f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	*(pos + offset_ttl) -= 1;
11658f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	*(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
1166b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);
11678f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11688f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	memcpy(mgmt_fwd, mgmt, len);
11698f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	eth_broadcast_addr(mgmt_fwd->da);
11708f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
11718f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
11728f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11738f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ieee80211_tx_skb(sdata, skb);
11748f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	return 0;
11758f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh}
11768f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11778f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeohstatic void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
11788f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh			      struct ieee80211_mgmt *mgmt, size_t len)
11798f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh{
11808f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
11818f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct ieee802_11_elems elems;
11828f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	u16 pre_value;
118333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	bool fwd_csa = true;
11848f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	size_t baselen;
11858f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	u8 *pos, ttl;
11868f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11878f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (mgmt->u.action.u.measurement.action_code !=
11888f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	    WLAN_ACTION_SPCT_CHL_SWITCH)
11898f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		return;
11908f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11918f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	pos = mgmt->u.action.u.chan_switch.variable;
11928f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	baselen = offsetof(struct ieee80211_mgmt,
11938f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh			   u.action.u.chan_switch.variable);
11948f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
11958f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11968f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ttl = elems.mesh_chansw_params_ie->mesh_ttl;
11978f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (!--ttl)
11988f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		fwd_csa = false;
11998f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
12008f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
12018f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (ifmsh->pre_value >= pre_value)
12028f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		return;
12038f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
12048f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ifmsh->pre_value = pre_value;
12058f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
120633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
120733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		mcsa_dbg(sdata, "Failed to process CSA action frame");
120833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return;
120933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	}
121033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
12118f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	/* forward or re-broadcast the CSA frame */
12128f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (fwd_csa) {
12138f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
12148f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh			mcsa_dbg(sdata, "Failed to forward the CSA frame");
12158f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	}
12168f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh}
12178f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
1218472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
1219472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct ieee80211_mgmt *mgmt,
1220472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  size_t len,
1221472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct ieee80211_rx_status *rx_status)
1222472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1223472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (mgmt->u.action.category) {
12248db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen	case WLAN_CATEGORY_SELF_PROTECTED:
12258db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		switch (mgmt->u.action.u.self_prot.action_code) {
12268db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_OPEN:
12278db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_CLOSE:
12288db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_CONFIRM:
12298db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen			mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
12308db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen			break;
12318db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		}
1232472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
123325d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen	case WLAN_CATEGORY_MESH_ACTION:
123425d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen		if (mesh_action_is_path_sel(mgmt))
123525d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen			mesh_rx_path_sel_frame(sdata, mgmt, len);
1236472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
12378f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	case WLAN_CATEGORY_SPECTRUM_MGMT:
12388f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		mesh_rx_csa_frame(sdata, mgmt, len);
12398f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		break;
1240472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
1241472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1242472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
12431fa57d017366fb26b58af110a38b36a4f0214a62Johannes Bergvoid ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
12441fa57d017366fb26b58af110a38b36a4f0214a62Johannes Berg				   struct sk_buff *skb)
1245472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1246472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_rx_status *rx_status;
1247472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_mgmt *mgmt;
1248472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	u16 stype;
1249472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1250ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	sdata_lock(sdata);
1251ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1252ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	/* mesh already went down */
1253ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	if (!sdata->wdev.mesh_id_len)
1254ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen		goto out;
1255ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1256f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg	rx_status = IEEE80211_SKB_RXCB(skb);
1257472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mgmt = (struct ieee80211_mgmt *) skb->data;
1258472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
1259472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1260472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (stype) {
1261472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_PROBE_RESP:
1262472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_BEACON:
1263472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
1264472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					    rx_status);
1265472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
12669fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	case IEEE80211_STYPE_PROBE_REQ:
12679fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len);
12689fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		break;
1269472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_ACTION:
1270472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
1271472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
1272472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
1273ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersenout:
1274ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	sdata_unlock(sdata);
1275472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1276472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1277f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersenstatic void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata)
1278f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen{
1279f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1280f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	u32 bit, changed = 0;
1281f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
1282f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	for_each_set_bit(bit, &ifmsh->mbss_changed,
1283f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			 sizeof(changed) * BITS_PER_BYTE) {
1284f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		clear_bit(bit, &ifmsh->mbss_changed);
1285f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		changed |= BIT(bit);
1286f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	}
1287f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
1288f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	if (sdata->vif.bss_conf.enable_beacon &&
1289f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	    (changed & (BSS_CHANGED_BEACON |
1290f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			BSS_CHANGED_HT |
1291f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			BSS_CHANGED_BASIC_RATES |
1292f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			BSS_CHANGED_BEACON_INT)))
1293f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		if (ieee80211_mesh_rebuild_beacon(sdata))
1294f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			return;
1295f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
1296f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	ieee80211_bss_info_change_notify(sdata, changed);
1297f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen}
1298f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
12991fa57d017366fb26b58af110a38b36a4f0214a62Johannes Bergvoid ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
1300472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1301472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1302472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1303ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	sdata_lock(sdata);
1304ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1305ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	/* mesh already went down */
1306ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	if (!sdata->wdev.mesh_id_len)
1307ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen		goto out;
1308ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1309472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (ifmsh->preq_queue_len &&
1310472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	    time_after(jiffies,
1311472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		       ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
1312472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		mesh_path_start_discovery(sdata);
1313472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
131418889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
131518889231e4527dfe23145efe318e74744794a95dJavier Cardona		mesh_mpath_table_grow();
131618889231e4527dfe23145efe318e74744794a95dJavier Cardona
1317dcac908babcd8ce21057e476c8df609b28ad2cd8Nick Ledovskikh	if (test_and_clear_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags))
131818889231e4527dfe23145efe318e74744794a95dJavier Cardona		mesh_mpp_table_grow();
131918889231e4527dfe23145efe318e74744794a95dJavier Cardona
132018889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
1321bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		ieee80211_mesh_housekeeping(sdata);
1322e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
1323e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
1324e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		ieee80211_mesh_rootpath(sdata);
1325dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona
1326dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
1327dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona		mesh_sync_adjust_tbtt(sdata);
1328ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1329f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags))
1330f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		mesh_bss_info_changed(sdata);
1331ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersenout:
1332ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	sdata_unlock(sdata);
1333472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1334472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1335472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
1336472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1337472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_sub_if_data *sdata;
1338472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1339472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	rcu_read_lock();
1340472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	list_for_each_entry_rcu(sdata, &local->interfaces, list)
1341370bd005937c0e00f9104a602f9fe1dd6b21b54bBen Greear		if (ieee80211_vif_is_mesh(&sdata->vif) &&
1342370bd005937c0e00f9104a602f9fe1dd6b21b54bBen Greear		    ieee80211_sdata_running(sdata))
134364592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg			ieee80211_queue_work(&local->hw, &sdata->work);
1344472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	rcu_read_unlock();
1345472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1346472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1347902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Bergvoid ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
1348902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
1349472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1350ad2d223aa900179031feb40273881e212941573dJohannes Berg	static u8 zero_addr[ETH_ALEN] = {};
1351472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1352472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	setup_timer(&ifmsh->housekeeping_timer,
1353472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		    ieee80211_mesh_housekeeping_timer,
1354472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		    (unsigned long) sdata);
1355472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1356472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->accepting_plinks = true;
1357472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	atomic_set(&ifmsh->mpaths, 0);
1358f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	mesh_rmc_init(sdata);
1359472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->last_preq = jiffies;
1360dca7e9430cb3e492437a5ce891b8b3e315c147caThomas Pedersen	ifmsh->next_perr = jiffies;
13618f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ifmsh->chsw_init = false;
1362902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	/* Allocate all mesh structures when creating the first mesh interface. */
1363902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	if (!mesh_allocated)
1364902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		ieee80211s_init();
1365472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	setup_timer(&ifmsh->mesh_path_timer,
1366902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    ieee80211_mesh_path_timer,
1367902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    (unsigned long) sdata);
1368e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	setup_timer(&ifmsh->mesh_path_root_timer,
1369e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		    ieee80211_mesh_path_root_timer,
1370e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		    (unsigned long) sdata);
1371472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
13723f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	skb_queue_head_init(&ifmsh->ps.bc_buf);
1373472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
1374dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	spin_lock_init(&ifmsh->sync_offset_lock);
13752b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	RCU_INIT_POINTER(ifmsh->beacon, NULL);
1376ad2d223aa900179031feb40273881e212941573dJohannes Berg
1377ad2d223aa900179031feb40273881e212941573dJohannes Berg	sdata->vif.bss_conf.bssid = zero_addr;
1378472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1379