mesh.c revision 43552be1da3c420931c89727b6115b7fa35368f8
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
26243552be1da3c420931c89727b6115b7fa35368f8Thomas Pedersen	/* save a pointer for quick updates in pre-tbtt */
26343552be1da3c420931c89727b6115b7fa35368f8Thomas Pedersen	ifmsh->meshconf_offset = pos - skb->data;
26443552be1da3c420931c89727b6115b7fa35368f8Thomas Pedersen
265082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Active path selection protocol ID */
266082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_pp_id;
267082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Active path selection metric ID   */
268082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_pm_id;
269082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Congestion control mode identifier */
270082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_cc_id;
271082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Synchronization protocol identifier */
272082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_sp_id;
273082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Authentication Protocol identifier */
274082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_auth_id;
275082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Mesh Formation Info - number of neighbors */
2761258d97616fdca9abc0c21f2edeb1d5b21dcb128Ashok Nagarajan	neighbors = atomic_read(&ifmsh->estab_plinks);
277e05ecccdf752122a439b03c3190458d2c8f0bac6Jacob Minshall	neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS);
278082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = neighbors << 1;
279082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Mesh capability */
280b60e527a729cbb9c88b49cc10738a13328cd1ed2Chun-Yeow Yeoh	*pos = 0x00;
281b60e527a729cbb9c88b49cc10738a13328cd1ed2Chun-Yeow Yeoh	*pos |= ifmsh->mshcfg.dot11MeshForwarding ?
282b60e527a729cbb9c88b49cc10738a13328cd1ed2Chun-Yeow Yeoh			IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00;
283dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	*pos |= ifmsh->accepting_plinks ?
284bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
2853f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
2863f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos |= ifmsh->ps_peers_deep_sleep ?
287bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
288dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	*pos++ |= ifmsh->adjusting_tbtt ?
289bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
290082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = 0x00;
291082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
292082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
293082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
294082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
295bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
296082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
297082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
298082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 *pos;
299082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
300082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
301082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return -ENOMEM;
302082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
303082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
304082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = WLAN_EID_MESH_ID;
305082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_id_len;
306082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (ifmsh->mesh_id_len)
307082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
308082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
309082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
310082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
311082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
312bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata,
313bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				    struct sk_buff *skb)
3143f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch{
3153f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
3163f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	u8 *pos;
3173f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3183f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* see IEEE802.11-2012 13.14.6 */
3193f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	if (ifmsh->ps_peers_light_sleep == 0 &&
3203f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	    ifmsh->ps_peers_deep_sleep == 0 &&
3213f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	    ifmsh->nonpeer_pm == NL80211_MESH_POWER_ACTIVE)
3223f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch		return 0;
3233f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3243f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	if (skb_tailroom(skb) < 4)
3253f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch		return -ENOMEM;
3263f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3273f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	pos = skb_put(skb, 2 + 2);
3283f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos++ = WLAN_EID_MESH_AWAKE_WINDOW;
3293f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos++ = 2;
3303f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	put_unaligned_le16(ifmsh->mshcfg.dot11MeshAwakeWindowDuration, pos);
3313f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3323f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	return 0;
3333f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch}
3343f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
335bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
336bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			struct sk_buff *skb)
337082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
338082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
339082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 offset, len;
340082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	const u8 *data;
341082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
342082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (!ifmsh->ie || !ifmsh->ie_len)
343082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return 0;
344082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
345082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* fast-forward to vendor IEs */
346082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
347082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
348082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (offset) {
349082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		len = ifmsh->ie_len - offset;
350082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		data = ifmsh->ie + offset;
351082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (skb_tailroom(skb) < len)
352082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			return -ENOMEM;
353082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(skb_put(skb, len), data, len);
354082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
355082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
356082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
357082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
358082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
359bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
360082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
361082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
362082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 len = 0;
363082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	const u8 *data;
364082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
365082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (!ifmsh->ie || !ifmsh->ie_len)
366082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return 0;
367082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
368082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* find RSN IE */
369082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	data = ifmsh->ie;
370082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	while (data < ifmsh->ie + ifmsh->ie_len) {
371082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (*data == WLAN_EID_RSN) {
372082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			len = data[1] + 2;
373082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			break;
374082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		}
375082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		data++;
376082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
377082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
378082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (len) {
379082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (skb_tailroom(skb) < len)
380082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			return -ENOMEM;
381082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(skb_put(skb, len), data, len);
382082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
383082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
384082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
385082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
386082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
387bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata,
388bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				 struct sk_buff *skb)
389082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
39055de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_chanctx_conf *chanctx_conf;
39155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_channel *chan;
392082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 *pos;
3932e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
394082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (skb_tailroom(skb) < 3)
395082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return -ENOMEM;
396082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
39755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_lock();
39855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
39955de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	if (WARN_ON(!chanctx_conf)) {
40055de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		rcu_read_unlock();
40155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		return -EINVAL;
40255de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	}
4034bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	chan = chanctx_conf->def.chan;
40455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_unlock();
40555de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
406601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	pos = skb_put(skb, 2 + 1);
407601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = WLAN_EID_DS_PARAMS;
408601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = 1;
409601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
410be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo
411082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
4122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
4132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
414bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
415bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		       struct sk_buff *skb)
416176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen{
417176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_local *local = sdata->local;
41855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
419176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_supported_band *sband;
420176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	u8 *pos;
421176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
42255de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	sband = local->hw.wiphy->bands[band];
423176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (!sband->ht_cap.ht_supported ||
4240418a445838749c51cf1e31a9c7ace6685ae87cdSimon Wunderlich	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
4250418a445838749c51cf1e31a9c7ace6685ae87cdSimon Wunderlich	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
4260418a445838749c51cf1e31a9c7ace6685ae87cdSimon Wunderlich	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
427176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return 0;
428176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
429176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
430176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return -ENOMEM;
431176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
432176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
433ef96a84202ccfb48a4569256ffba45e32308f7eeBen Greear	ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
434176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
435176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	return 0;
436176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen}
437176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
438bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
439bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			struct sk_buff *skb)
440176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen{
441176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_local *local = sdata->local;
44255de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_chanctx_conf *chanctx_conf;
44355de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_channel *channel;
444466f310d100ff54f346c1be481af9935c42467b3Johannes Berg	enum nl80211_channel_type channel_type =
4454bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg		cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef);
44655de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_supported_band *sband;
44755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_sta_ht_cap *ht_cap;
448176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	u8 *pos;
449176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
45055de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_lock();
45155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
45255de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	if (WARN_ON(!chanctx_conf)) {
45355de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		rcu_read_unlock();
45455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		return -EINVAL;
45555de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	}
4564bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	channel = chanctx_conf->def.chan;
45755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_unlock();
45855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
45955de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	sband = local->hw.wiphy->bands[channel->band];
46055de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	ht_cap = &sband->ht_cap;
46155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
462176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
463176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return 0;
464176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
465074d46d1d23f27488a3f314e29cae2453541f17dJohannes Berg	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
466176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return -ENOMEM;
467176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
468074d46d1d23f27488a3f314e29cae2453541f17dJohannes Berg	pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
4694bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
470431e31542383b71bc5f2642572a1e6ef07f1bb87Ashok Nagarajan				   sdata->vif.bss_conf.ht_operation_mode);
471176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
472176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	return 0;
473176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen}
474bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
4752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic void ieee80211_mesh_path_timer(unsigned long data)
4762e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
4772e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_sub_if_data *sdata =
4782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		(struct ieee80211_sub_if_data *) data;
4795bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
480690205f18fd069898c70d743f498ba42798e5c4eStanislaw Gruszka	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
4812e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
4822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
483e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulostatic void ieee80211_mesh_path_root_timer(unsigned long data)
484e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo{
485e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_sub_if_data *sdata =
486e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		(struct ieee80211_sub_if_data *) data;
487e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
488e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
489e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
490e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
491690205f18fd069898c70d743f498ba42798e5c4eStanislaw Gruszka	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
492e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo}
493e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
49463c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulovoid ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
49563c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo{
496dbb912cd4ce64e763c5610b49a85529d2634e9d8Chun-Yeow Yeoh	if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)
49763c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
49863c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	else {
49963c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
50063c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		/* stop running timer */
50163c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		del_timer_sync(&ifmsh->mesh_path_root_timer);
50263c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	}
50363c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo}
50463c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo
505902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg/**
5063c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
507bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg * @hdr:	802.11 frame header
5083c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @fc:		frame control field
5093c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @meshda:	destination address in the mesh
5103c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @meshsa:	source address address in the mesh.  Same as TA, as frame is
5113c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *              locally originated.
5123c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *
5133c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * Return the length of the 802.11 (does not include a mesh control header)
5143c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona */
51515ff63653e507ec928a4a4386405a82446e096b1Johannes Bergint ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
51615ff63653e507ec928a4a4386405a82446e096b1Johannes Berg				  const u8 *meshda, const u8 *meshsa)
51715ff63653e507ec928a4a4386405a82446e096b1Johannes Berg{
5183c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	if (is_multicast_ether_addr(meshda)) {
5193c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
5203c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		/* DA TA SA */
5213c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr1, meshda, ETH_ALEN);
5223c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr2, meshsa, ETH_ALEN);
5233c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr3, meshsa, ETH_ALEN);
5243c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		return 24;
5253c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	} else {
5262154c81c32fa44364f83218a10d8dbec4e76d4f5Javier Cardona		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
5273c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		/* RA TA DA SA */
5283c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memset(hdr->addr1, 0, ETH_ALEN);   /* RA is resolved later */
5293c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr2, meshsa, ETH_ALEN);
5303c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr3, meshda, ETH_ALEN);
5313c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr4, meshsa, ETH_ALEN);
5323c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		return 30;
5333c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
5343c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona}
5353c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona
5363c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona/**
537902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * ieee80211_new_mesh_header - create a new mesh header
538902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * @sdata:	mesh interface to be used
539bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg * @meshhdr:    uninitialized mesh header
54061ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona * @addr4or5:   1st address in the ae header, which may correspond to address 4
54161ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              (if addr6 is NULL) or address 5 (if addr6 is present). It may
54261ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              be NULL.
54361ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona * @addr6:	2nd address in the ae header, which corresponds to addr6 of the
54461ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              mesh frame
545902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg *
546902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * Return the header length.
547902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg */
548bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
549bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			      struct ieee80211s_hdr *meshhdr,
550bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			      const char *addr4or5, const char *addr6)
551902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
552bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	if (WARN_ON(!addr4or5 && addr6))
553bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 0;
554bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
5550c3cee72a403e3b4992a5478c9c33d668c246c22Julia Lawall	memset(meshhdr, 0, sizeof(*meshhdr));
556bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
557472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
558bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
559bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	/* FIXME: racy -- TX on multiple queues can be concurrent */
560472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
561472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.mesh_seqnum++;
562bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
56361ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona	if (addr4or5 && !addr6) {
5643c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		meshhdr->flags |= MESH_FLAGS_AE_A4;
56561ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
566bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 2 * ETH_ALEN;
56761ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona	} else if (addr4or5 && addr6) {
5683c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
56961ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
57061ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
571bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 3 * ETH_ALEN;
5723c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
573bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
574bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	return ETH_ALEN;
575902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg}
576902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg
577bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
578472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
579bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
580df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	u32 changed;
581472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
58266de671374f003467b5ef7c65ecbe1930480c8c9Colleen Twitty	ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
583472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mesh_path_expire(sdata);
584472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
585df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	changed = mesh_accept_plinks_update(sdata);
5862b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	ieee80211_mbss_info_change_notify(sdata, changed);
587472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
588472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mod_timer(&ifmsh->housekeeping_timer,
589bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		  round_jiffies(jiffies +
590bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
591472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
592472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
593e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulostatic void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
594e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo{
595e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
596a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	u32 interval;
597e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
598e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	mesh_path_tx_root_frame(sdata);
599a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh
600a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN)
601a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
602a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	else
603a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		interval = ifmsh->mshcfg.dot11MeshHWMProotInterval;
604a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh
605e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	mod_timer(&ifmsh->mesh_path_root_timer,
606a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		  round_jiffies(TU_TO_EXP_TIME(interval)));
607e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo}
608e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
6092b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenstatic int
6102b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
6112b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
6122b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *bcn;
6132b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int head_len, tail_len;
6142b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct sk_buff *skb;
6152b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_mgmt *mgmt;
6162b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_chanctx_conf *chanctx_conf;
617b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct mesh_csa_settings *csa;
6182b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	enum ieee80211_band band;
6192b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	u8 *pos;
6202b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_sub_if_data *sdata;
6212b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
6222b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		      sizeof(mgmt->u.beacon);
6232b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6242b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
6252b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_read_lock();
6262b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
6272b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	band = chanctx_conf->def.chan->band;
6282b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_read_unlock();
6292b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6302b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	head_len = hdr_len +
6312b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + /* NULL SSID */
632b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		   /* Channel Switch Announcement */
633b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		   2 + sizeof(struct ieee80211_channel_sw_ie) +
634b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		   /* Mesh Channel Swith Parameters */
635b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		   2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
6362b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + 8 + /* supported rates */
6372b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + 3; /* DS params */
6382b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
6392b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_ht_cap) +
6402b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_ht_operation) +
6412b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + ifmsh->mesh_id_len +
6422b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_meshconf_ie) +
6432b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(__le16) + /* awake window */
6442b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   ifmsh->ie_len;
6452b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6462b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
6472b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/* need an skb for IE builders to operate on */
6482b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	skb = dev_alloc_skb(max(head_len, tail_len));
6492b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6502b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (!bcn || !skb)
6512b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		goto out_free;
6522b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6532b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/*
6542b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 * pointers go into the block we allocated,
6552b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 * memory is | beacon_data | head | tail |
6562b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 */
6572b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->head = ((u8 *) bcn) + sizeof(*bcn);
6582b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6592b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/* fill in the head */
6602b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
6612b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memset(mgmt, 0, hdr_len);
6622b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
6632b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen					  IEEE80211_STYPE_BEACON);
6642b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	eth_broadcast_addr(mgmt->da);
6652b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
6662b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
6672b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt);
6682b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->u.beacon.beacon_int =
6692b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		cpu_to_le16(sdata->vif.bss_conf.beacon_int);
6702b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->u.beacon.capab_info |= cpu_to_le16(
6712b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
6722b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6732b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	pos = skb_put(skb, 2);
6742b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	*pos++ = WLAN_EID_SSID;
6752b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	*pos++ = 0x0;
6762b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
677b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	rcu_read_lock();
678b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	csa = rcu_dereference(ifmsh->csa);
679b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (csa) {
680b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		pos = skb_put(skb, 13);
681b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		memset(pos, 0, 13);
682b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = WLAN_EID_CHANNEL_SWITCH;
683b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = 3;
684b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = 0x0;
685b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = ieee80211_frequency_to_channel(
686b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh				csa->settings.chandef.chan->center_freq);
687b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		sdata->csa_counter_offset_beacon = hdr_len + 6;
688b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = csa->settings.count;
689b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
690b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ = 6;
691b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		if (ifmsh->chsw_init) {
692b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			*pos++ = ifmsh->mshcfg.dot11MeshTTL;
693b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			*pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
694b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		} else {
695b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			*pos++ = ifmsh->chsw_ttl;
696b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		}
697b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		*pos++ |= csa->settings.block_tx ?
698b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			  WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
699b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
700b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		pos += 2;
701ca91dc97b8a0ffd05721806654eaff2cf13ba5cbChun-Yeow Yeoh		put_unaligned_le16(ifmsh->pre_value, pos);
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);
72943552be1da3c420931c89727b6115b7fa35368f8Thomas Pedersen	bcn->meshconf = (struct ieee80211_meshconf_ie *)
73043552be1da3c420931c89727b6115b7fa35368f8Thomas Pedersen					(bcn->tail + ifmsh->meshconf_offset);
7312b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7322b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	dev_kfree_skb(skb);
7332b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_assign_pointer(ifmsh->beacon, bcn);
7342b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return 0;
7352b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenout_free:
7362b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	kfree(bcn);
7372b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	dev_kfree_skb(skb);
7382b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return -ENOMEM;
7392b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
7402b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7412b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenstatic int
7428d61ffa5e01c5f676431d12caba17db164a48a86Johannes Bergieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata)
7432b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
7442b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *old_bcn;
7452b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int ret;
7462b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7478d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg	old_bcn = rcu_dereference_protected(sdata->u.mesh.beacon,
7488d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg					    lockdep_is_held(&sdata->wdev.mtx));
7498d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg	ret = ieee80211_mesh_build_beacon(&sdata->u.mesh);
7502b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ret)
7512b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		/* just reuse old beacon */
7528d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg		return ret;
7532b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7542b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (old_bcn)
7552b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		kfree_rcu(old_bcn, rcu_head);
7568d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg	return 0;
7572b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
7582b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7592b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenvoid ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
7602b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen				       u32 changed)
7612b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
762f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
763f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	unsigned long bits = changed;
764f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	u32 bit;
765f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
766f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	if (!bits)
767f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		return;
768f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
769f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	/* if we race with running work, worst case this work becomes a noop */
770f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
771f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		set_bit(bit, &ifmsh->mbss_changed);
772f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
773f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
7742b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
7752b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7762b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenint ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
777472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
778472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
779472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
780f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh	u32 changed = BSS_CHANGED_BEACON |
781f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BEACON_ENABLED |
782f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_HT |
783f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BASIC_RATES |
784f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BEACON_INT;
785472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
78609b174702601079c3a04806754be30ffbd70db4dJohannes Berg	local->fif_other_bss++;
78709b174702601079c3a04806754be30ffbd70db4dJohannes Berg	/* mesh ifaces must set allmulti to forward mcast traffic */
78809b174702601079c3a04806754be30ffbd70db4dJohannes Berg	atomic_inc(&local->iff_allmultis);
78909b174702601079c3a04806754be30ffbd70db4dJohannes Berg	ieee80211_configure_filter(local);
79009b174702601079c3a04806754be30ffbd70db4dJohannes Berg
791c7108a7111cd9e592d6ad498be37276dbea75d2bJavier Cardona	ifmsh->mesh_cc_id = 0;	/* Disabled */
792dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	/* register sync ops from extensible synchronization framework */
793dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id);
794dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->adjusting_tbtt = false;
795dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->sync_offset_clockdrift_max = 0;
7966b9ac4425d6ec871faf54540e0f1c5ff420a8f29Rui Paulo	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
79763c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	ieee80211_mesh_root_setup(ifmsh);
79864592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg	ieee80211_queue_work(&local->hw, &sdata->work);
79970c33eaae79e53f9e48324736c0cb85534d3f093Ashok Nagarajan	sdata->vif.bss_conf.ht_operation_mode =
80070c33eaae79e53f9e48324736c0cb85534d3f093Ashok Nagarajan				ifmsh->mshcfg.ht_opmode;
801d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	sdata->vif.bss_conf.enable_beacon = true;
802f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh
80339886b618aba3c39e650c191d601e26ec581ce0fThomas Pedersen	changed |= ieee80211_mps_local_status_update(sdata);
8043f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
8052b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ieee80211_mesh_build_beacon(ifmsh)) {
8062b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		ieee80211_stop_mesh(sdata);
8072b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		return -ENOMEM;
8082b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	}
8092b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
810f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, changed);
811c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg
812c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg	netif_carrier_on(sdata->dev);
8132b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return 0;
814472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
815472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
816472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
817472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
81809b174702601079c3a04806754be30ffbd70db4dJohannes Berg	struct ieee80211_local *local = sdata->local;
81929cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
8202b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *bcn;
82129cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg
822c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg	netif_carrier_off(sdata->dev);
823c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg
8240d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	/* stop the beacon */
82529cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	ifmsh->mesh_id_len = 0;
826d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	sdata->vif.bss_conf.enable_beacon = false;
827d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
82829cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
8292b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn = rcu_dereference_protected(ifmsh->beacon,
8308d61ffa5e01c5f676431d12caba17db164a48a86Johannes Berg					lockdep_is_held(&sdata->wdev.mtx));
8312b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_assign_pointer(ifmsh->beacon, NULL);
8322b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	kfree_rcu(bcn, rcu_head);
8330d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen
8340d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	/* flush STAs and mpaths on this iface */
835b998e8bb3e1c6eeae5eab9d6a434563270286c3bJohannes Berg	sta_info_flush(sdata);
8360d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	mesh_path_flush_by_iface(sdata);
83709b174702601079c3a04806754be30ffbd70db4dJohannes Berg
8383f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* free all potentially still buffered group-addressed frames */
8393f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	local->total_ps_buffered -= skb_queue_len(&ifmsh->ps.bc_buf);
8403f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	skb_queue_purge(&ifmsh->ps.bc_buf);
8413f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
842472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
843e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
844dd4c9260e7f23f2e951cbfb2726e468c6d30306cJohannes Berg	del_timer_sync(&sdata->u.mesh.mesh_path_timer);
84509b174702601079c3a04806754be30ffbd70db4dJohannes Berg
846f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	/* clear any mesh work (for next join) we may have accrued */
847f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	ifmsh->wrkq_flags = 0;
848f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	ifmsh->mbss_changed = 0;
849f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
85009b174702601079c3a04806754be30ffbd70db4dJohannes Berg	local->fif_other_bss--;
85109b174702601079c3a04806754be30ffbd70db4dJohannes Berg	atomic_dec(&local->iff_allmultis);
85209b174702601079c3a04806754be30ffbd70db4dJohannes Berg	ieee80211_configure_filter(local);
853472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
854472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
85533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeohstatic bool
85633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeohieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
85733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh				 struct ieee802_11_elems *elems, bool beacon)
85833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh{
85933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct cfg80211_csa_settings params;
86033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct ieee80211_csa_ie csa_ie;
86133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct ieee80211_chanctx_conf *chanctx_conf;
86233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct ieee80211_chanctx *chanctx;
86333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
86433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
86533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	int err, num_chanctx;
86633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	u32 sta_flags;
86733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
86833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (sdata->vif.csa_active)
86933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return true;
87033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
87133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!ifmsh->mesh_id)
87233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
87333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
87433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	sta_flags = IEEE80211_STA_DISABLE_VHT;
87533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	switch (sdata->vif.bss_conf.chandef.width) {
87633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	case NL80211_CHAN_WIDTH_20_NOHT:
87733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		sta_flags |= IEEE80211_STA_DISABLE_HT;
87833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	case NL80211_CHAN_WIDTH_20:
87933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
88033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		break;
88133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	default:
88233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		break;
88333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	}
88433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
88533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	memset(&params, 0, sizeof(params));
88633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	memset(&csa_ie, 0, sizeof(csa_ie));
88733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, band,
88833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh					   sta_flags, sdata->vif.addr,
88933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh					   &csa_ie);
89033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (err < 0)
89133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
89233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (err)
89333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
89433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
89533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	params.chandef = csa_ie.chandef;
89633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	params.count = csa_ie.count;
89733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
89833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (sdata->vif.bss_conf.chandef.chan->band !=
89933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	    params.chandef.chan->band)
90033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
90133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
90233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
90333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh				     IEEE80211_CHAN_DISABLED)) {
90433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		sdata_info(sdata,
90533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
90633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   sdata->vif.addr,
90733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   params.chandef.chan->center_freq,
90833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   params.chandef.width,
90933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   params.chandef.center_freq1,
91033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			   params.chandef.center_freq2);
91133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
91233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	}
91333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
91433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
91533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh					    &params.chandef);
91633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (err < 0)
91733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
91833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (err) {
91933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		params.radar_required = true;
92033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		/* TODO: DFS not (yet) supported */
92133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return false;
92233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	}
92333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
92433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	rcu_read_lock();
92533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
92633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!chanctx_conf)
92733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		goto failed_chswitch;
92833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
92933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	/* don't handle for multi-VIF cases */
93033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
93133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (chanctx->refcount > 1)
93233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		goto failed_chswitch;
93333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
93433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	num_chanctx = 0;
93533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
93633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		num_chanctx++;
93733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
93833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (num_chanctx > 1)
93933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		goto failed_chswitch;
94033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
94133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	rcu_read_unlock();
94233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
94333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	mcsa_dbg(sdata,
94433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		 "received channel switch announcement to go to channel %d MHz\n",
94533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		 params.chandef.chan->center_freq);
94633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
94733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
9483f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh	if (beacon) {
94933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		ifmsh->chsw_ttl = csa_ie.ttl - 1;
9503f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh		if (ifmsh->pre_value >= csa_ie.pre_value)
9513f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh			return false;
9523f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh		ifmsh->pre_value = csa_ie.pre_value;
9533f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh	}
95433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
9553f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh	if (ifmsh->chsw_ttl < ifmsh->mshcfg.dot11MeshTTL) {
95633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		if (ieee80211_mesh_csa_beacon(sdata, &params, false) < 0)
95733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh			return false;
9583f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh	} else {
9593f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh		return false;
9603f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh	}
96133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
96233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	sdata->csa_radar_required = params.radar_required;
96333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
96433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (params.block_tx)
96533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		ieee80211_stop_queues_by_reason(&sdata->local->hw,
96633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh				IEEE80211_MAX_QUEUE_MAP,
96733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh				IEEE80211_QUEUE_STOP_REASON_CSA);
96833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
96933787fc4bea0347d78a211d1f38289b73d9ec1a6Luciano Coelho	sdata->csa_chandef = params.chandef;
97033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	sdata->vif.csa_active = true;
97133a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
97233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, err);
97333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	drv_channel_switch_beacon(sdata, &params.chandef);
97433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
97533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	return true;
97633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeohfailed_chswitch:
97733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	rcu_read_unlock();
97833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	return false;
97933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh}
98033a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
9819fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenstatic void
9829fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
9839fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen			    struct ieee80211_mgmt *mgmt, size_t len)
9849fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen{
9859fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_local *local = sdata->local;
9869fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
9879fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct sk_buff *presp;
9889fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct beacon_data *bcn;
9899fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_mgmt *hdr;
9909fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee802_11_elems elems;
9919fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	size_t baselen;
992511044ea0bfc06614d903263ad094d1071fa172fJohannes Berg	u8 *pos;
9939fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
9949fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	pos = mgmt->u.probe_req.variable;
9959fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	baselen = (u8 *) pos - (u8 *) mgmt;
9969fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (baselen > len)
9979fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
9989fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
999b2e506bfc4d752b68a0ccaae1e977898263eba4cJohannes Berg	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
10009fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
1001a4ef66a915b957416a89a48365aea2ec2dc551f6Chun-Yeow Yeoh	if (!elems.mesh_id)
1002a4ef66a915b957416a89a48365aea2ec2dc551f6Chun-Yeow Yeoh		return;
1003a4ef66a915b957416a89a48365aea2ec2dc551f6Chun-Yeow Yeoh
10049fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	/* 802.11-2012 10.1.4.3.2 */
10059fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
10069fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	     !is_broadcast_ether_addr(mgmt->da)) ||
10079fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	    elems.ssid_len != 0)
10089fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
10099fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10109fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (elems.mesh_id_len != 0 &&
10119fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	    (elems.mesh_id_len != ifmsh->mesh_id_len ||
10129fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	     memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
10139fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
10149fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10159fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	rcu_read_lock();
10169fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	bcn = rcu_dereference(ifmsh->beacon);
10179fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10189fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (!bcn)
10199fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		goto out;
10209fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10219fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	presp = dev_alloc_skb(local->tx_headroom +
10229fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen			      bcn->head_len + bcn->tail_len);
10239fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (!presp)
10249fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		goto out;
10259fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
10269fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	skb_reserve(presp, local->tx_headroom);
10279fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(skb_put(presp, bcn->head_len), bcn->head, bcn->head_len);
10289fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(skb_put(presp, bcn->tail_len), bcn->tail, bcn->tail_len);
10299fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	hdr = (struct ieee80211_mgmt *) presp->data;
10309fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
10319fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen					 IEEE80211_STYPE_PROBE_RESP);
10329fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(hdr->da, mgmt->sa, ETH_ALEN);
10339fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
10349fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	ieee80211_tx_skb(sdata, presp);
10359fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenout:
10369fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	rcu_read_unlock();
10379fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen}
10389fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
1039472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
1040472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					u16 stype,
1041472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					struct ieee80211_mgmt *mgmt,
1042472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					size_t len,
1043472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					struct ieee80211_rx_status *rx_status)
1044472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1045c6a1fa12d206882757264869f8e32d606b930e2aJohannes Berg	struct ieee80211_local *local = sdata->local;
1046dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1047472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee802_11_elems elems;
1048472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_channel *channel;
1049472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	size_t baselen;
1050472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	int freq;
1051472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	enum ieee80211_band band = rx_status->band;
1052472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1053472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	/* ignore ProbeResp to foreign address */
1054472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (stype == IEEE80211_STYPE_PROBE_RESP &&
1055b203ca39126bad99583c908be587df067820a1eaJoe Perches	    !ether_addr_equal(mgmt->da, sdata->vif.addr))
1056472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
1057472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1058472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
1059472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (baselen > len)
1060472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
1061472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1062472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
1063b2e506bfc4d752b68a0ccaae1e977898263eba4cJohannes Berg			       false, &elems);
1064472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
10659a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	/* ignore non-mesh or secure / unsecure mismatch */
10669a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	if ((!elems.mesh_id || !elems.mesh_config) ||
10679a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	    (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
10689a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	    (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
10695cff5e01e818029a5d2c3c31b7ae5e5e7ee70452Javier Cardona		return;
10705cff5e01e818029a5d2c3c31b7ae5e5e7ee70452Javier Cardona
10711cd8e88e17729f57a9c7f751103e522596bb5de2Johannes Berg	if (elems.ds_params)
107259eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
1073472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	else
1074472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		freq = rx_status->freq;
1075472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1076472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	channel = ieee80211_get_channel(local->hw.wiphy, freq);
1077472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1078472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
1079472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
1080472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
10819a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	if (mesh_matches_local(sdata, &elems))
1082f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen		mesh_neighbour_update(sdata, mgmt->sa, &elems);
1083dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona
1084dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	if (ifmsh->sync_ops)
1085dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona		ifmsh->sync_ops->rx_bcn_presp(sdata,
1086dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona			stype, mgmt, &elems, rx_status);
108733a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
108833a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!ifmsh->chsw_init)
108933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		ieee80211_mesh_process_chnswitch(sdata, &elems, true);
1090472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1091472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1092b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeohint ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
1093b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh{
1094b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1095b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct mesh_csa_settings *tmp_csa_settings;
1096b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	int ret = 0;
1097b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1098b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	/* Reset the TTL value and Initiator flag */
1099b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ifmsh->chsw_init = false;
1100b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ifmsh->chsw_ttl = 0;
1101b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1102b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	/* Remove the CSA and MCSP elements from the beacon */
1103b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	tmp_csa_settings = rcu_dereference(ifmsh->csa);
1104b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	rcu_assign_pointer(ifmsh->csa, NULL);
1105b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	kfree_rcu(tmp_csa_settings, rcu_head);
1106b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ret = ieee80211_mesh_rebuild_beacon(sdata);
1107b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (ret)
1108b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		return -EINVAL;
1109b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1110b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
1111b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1112b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	mcsa_dbg(sdata, "complete switching to center freq %d MHz",
1113b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		 sdata->vif.bss_conf.chandef.chan->center_freq);
1114b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	return 0;
1115b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh}
1116b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1117b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeohint ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
1118b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			      struct cfg80211_csa_settings *csa_settings,
1119b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh			      bool csa_action)
1120b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh{
1121b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1122b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	struct mesh_csa_settings *tmp_csa_settings;
1123b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	int ret = 0;
1124b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1125b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
1126b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh				   GFP_ATOMIC);
1127b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (!tmp_csa_settings)
1128b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		return -ENOMEM;
1129b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1130b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	memcpy(&tmp_csa_settings->settings, csa_settings,
1131b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	       sizeof(struct cfg80211_csa_settings));
1132b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1133b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	rcu_assign_pointer(ifmsh->csa, tmp_csa_settings);
1134b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1135b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ret = ieee80211_mesh_rebuild_beacon(sdata);
1136b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (ret) {
1137b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		tmp_csa_settings = rcu_dereference(ifmsh->csa);
1138b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		rcu_assign_pointer(ifmsh->csa, NULL);
1139b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		kfree_rcu(tmp_csa_settings, rcu_head);
1140b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		return ret;
1141b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	}
1142b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1143b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
1144b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1145b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	if (csa_action)
1146b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh		ieee80211_send_action_csa(sdata, csa_settings);
1147b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
1148b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh	return 0;
1149b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh}
1150b8456a14e9d2770846fcf74de18ff95b676149a3Chun-Yeow Yeoh
11518f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeohstatic int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
11528f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh			       struct ieee80211_mgmt *mgmt, size_t len)
11538f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh{
11548f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct ieee80211_mgmt *mgmt_fwd;
11558f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct sk_buff *skb;
11568f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct ieee80211_local *local = sdata->local;
11578f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	u8 *pos = mgmt->u.action.u.chan_switch.variable;
11588f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	size_t offset_ttl;
11598f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11608f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	skb = dev_alloc_skb(local->tx_headroom + len);
11618f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (!skb)
11628f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		return -ENOMEM;
11638f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	skb_reserve(skb, local->tx_headroom);
11648f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
11658f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11668f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	/* offset_ttl is based on whether the secondary channel
11678f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	 * offset is available or not. Substract 1 from the mesh TTL
11688f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	 * and disable the initiator flag before forwarding.
11698f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	 */
11708f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	offset_ttl = (len < 42) ? 7 : 10;
11718f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	*(pos + offset_ttl) -= 1;
11728f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	*(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
11738f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11748f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	memcpy(mgmt_fwd, mgmt, len);
11758f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	eth_broadcast_addr(mgmt_fwd->da);
11768f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
11778f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
11788f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11798f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ieee80211_tx_skb(sdata, skb);
11808f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	return 0;
11818f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh}
11828f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11838f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeohstatic void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
11848f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh			      struct ieee80211_mgmt *mgmt, size_t len)
11858f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh{
11868f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
11878f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	struct ieee802_11_elems elems;
11888f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	u16 pre_value;
118933a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	bool fwd_csa = true;
11908f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	size_t baselen;
11913f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh	u8 *pos;
11928f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11938f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (mgmt->u.action.u.measurement.action_code !=
11948f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	    WLAN_ACTION_SPCT_CHL_SWITCH)
11958f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		return;
11968f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
11978f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	pos = mgmt->u.action.u.chan_switch.variable;
11988f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	baselen = offsetof(struct ieee80211_mgmt,
11998f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh			   u.action.u.chan_switch.variable);
12008f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
12018f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
12023f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh	ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
12033f718fd8401d7db86b9efc3ea1cdf5df41354b9fChun-Yeow Yeoh	if (!--ifmsh->chsw_ttl)
12048f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		fwd_csa = false;
12058f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
12068f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
12078f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (ifmsh->pre_value >= pre_value)
12088f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		return;
12098f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
12108f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ifmsh->pre_value = pre_value;
12118f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
121233a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
121333a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		mcsa_dbg(sdata, "Failed to process CSA action frame");
121433a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh		return;
121533a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh	}
121633a45867c56074a23d01e286890e3b61f3ff8fffChun-Yeow Yeoh
12178f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	/* forward or re-broadcast the CSA frame */
12188f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	if (fwd_csa) {
12198f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
12208f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh			mcsa_dbg(sdata, "Failed to forward the CSA frame");
12218f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	}
12228f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh}
12238f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh
1224472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
1225472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct ieee80211_mgmt *mgmt,
1226472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  size_t len,
1227472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct ieee80211_rx_status *rx_status)
1228472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1229472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (mgmt->u.action.category) {
12308db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen	case WLAN_CATEGORY_SELF_PROTECTED:
12318db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		switch (mgmt->u.action.u.self_prot.action_code) {
12328db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_OPEN:
12338db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_CLOSE:
12348db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_CONFIRM:
12358db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen			mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
12368db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen			break;
12378db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		}
1238472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
123925d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen	case WLAN_CATEGORY_MESH_ACTION:
124025d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen		if (mesh_action_is_path_sel(mgmt))
124125d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen			mesh_rx_path_sel_frame(sdata, mgmt, len);
1242472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
12438f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	case WLAN_CATEGORY_SPECTRUM_MGMT:
12448f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		mesh_rx_csa_frame(sdata, mgmt, len);
12458f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh		break;
1246472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
1247472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1248472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
12491fa57d017366fb26b58af110a38b36a4f0214a62Johannes Bergvoid ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
12501fa57d017366fb26b58af110a38b36a4f0214a62Johannes Berg				   struct sk_buff *skb)
1251472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1252472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_rx_status *rx_status;
1253472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_mgmt *mgmt;
1254472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	u16 stype;
1255472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1256ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	sdata_lock(sdata);
1257ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1258ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	/* mesh already went down */
1259ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	if (!sdata->wdev.mesh_id_len)
1260ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen		goto out;
1261ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1262f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg	rx_status = IEEE80211_SKB_RXCB(skb);
1263472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mgmt = (struct ieee80211_mgmt *) skb->data;
1264472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
1265472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1266472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (stype) {
1267472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_PROBE_RESP:
1268472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_BEACON:
1269472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
1270472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					    rx_status);
1271472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
12729fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	case IEEE80211_STYPE_PROBE_REQ:
12739fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len);
12749fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		break;
1275472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_ACTION:
1276472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
1277472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
1278472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
1279ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersenout:
1280ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	sdata_unlock(sdata);
1281472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1282472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1283f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersenstatic void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata)
1284f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen{
1285f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1286f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	u32 bit, changed = 0;
1287f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
1288f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	for_each_set_bit(bit, &ifmsh->mbss_changed,
1289f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			 sizeof(changed) * BITS_PER_BYTE) {
1290f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		clear_bit(bit, &ifmsh->mbss_changed);
1291f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		changed |= BIT(bit);
1292f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	}
1293f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
1294f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	if (sdata->vif.bss_conf.enable_beacon &&
1295f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	    (changed & (BSS_CHANGED_BEACON |
1296f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			BSS_CHANGED_HT |
1297f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			BSS_CHANGED_BASIC_RATES |
1298f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			BSS_CHANGED_BEACON_INT)))
1299f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		if (ieee80211_mesh_rebuild_beacon(sdata))
1300f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen			return;
1301f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
1302f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	ieee80211_bss_info_change_notify(sdata, changed);
1303f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen}
1304f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen
13051fa57d017366fb26b58af110a38b36a4f0214a62Johannes Bergvoid ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
1306472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1307472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1308472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1309ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	sdata_lock(sdata);
1310ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1311ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	/* mesh already went down */
1312ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	if (!sdata->wdev.mesh_id_len)
1313ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen		goto out;
1314ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1315472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (ifmsh->preq_queue_len &&
1316472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	    time_after(jiffies,
1317472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		       ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
1318472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		mesh_path_start_discovery(sdata);
1319472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
132018889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
132118889231e4527dfe23145efe318e74744794a95dJavier Cardona		mesh_mpath_table_grow();
132218889231e4527dfe23145efe318e74744794a95dJavier Cardona
1323dcac908babcd8ce21057e476c8df609b28ad2cd8Nick Ledovskikh	if (test_and_clear_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags))
132418889231e4527dfe23145efe318e74744794a95dJavier Cardona		mesh_mpp_table_grow();
132518889231e4527dfe23145efe318e74744794a95dJavier Cardona
132618889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
1327bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		ieee80211_mesh_housekeeping(sdata);
1328e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
1329e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
1330e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		ieee80211_mesh_rootpath(sdata);
1331dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona
1332dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
1333dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona		mesh_sync_adjust_tbtt(sdata);
1334ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen
1335f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen	if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags))
1336f81a9dedaff434604c7fc3d9c299d277b76db0a8Thomas Pedersen		mesh_bss_info_changed(sdata);
1337ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersenout:
1338ecccd072b07e7fd09c54d0f86f9374e2645cde97Thomas Pedersen	sdata_unlock(sdata);
1339472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1340472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1341472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
1342472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1343472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_sub_if_data *sdata;
1344472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1345472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	rcu_read_lock();
1346472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	list_for_each_entry_rcu(sdata, &local->interfaces, list)
1347370bd005937c0e00f9104a602f9fe1dd6b21b54bBen Greear		if (ieee80211_vif_is_mesh(&sdata->vif) &&
1348370bd005937c0e00f9104a602f9fe1dd6b21b54bBen Greear		    ieee80211_sdata_running(sdata))
134964592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg			ieee80211_queue_work(&local->hw, &sdata->work);
1350472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	rcu_read_unlock();
1351472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1352472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1353902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Bergvoid ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
1354902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
1355472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1356ad2d223aa900179031feb40273881e212941573dJohannes Berg	static u8 zero_addr[ETH_ALEN] = {};
1357472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1358472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	setup_timer(&ifmsh->housekeeping_timer,
1359472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		    ieee80211_mesh_housekeeping_timer,
1360472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		    (unsigned long) sdata);
1361472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1362472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->accepting_plinks = true;
1363472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	atomic_set(&ifmsh->mpaths, 0);
1364f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	mesh_rmc_init(sdata);
1365472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->last_preq = jiffies;
1366dca7e9430cb3e492437a5ce891b8b3e315c147caThomas Pedersen	ifmsh->next_perr = jiffies;
13678f2535b92d685c68db4bc699dd78462a646f6ef9Chun-Yeow Yeoh	ifmsh->chsw_init = false;
1368902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	/* Allocate all mesh structures when creating the first mesh interface. */
1369902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	if (!mesh_allocated)
1370902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		ieee80211s_init();
1371472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	setup_timer(&ifmsh->mesh_path_timer,
1372902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    ieee80211_mesh_path_timer,
1373902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    (unsigned long) sdata);
1374e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	setup_timer(&ifmsh->mesh_path_root_timer,
1375e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		    ieee80211_mesh_path_root_timer,
1376e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		    (unsigned long) sdata);
1377472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
13783f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	skb_queue_head_init(&ifmsh->ps.bc_buf);
1379472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
1380dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	spin_lock_init(&ifmsh->sync_offset_lock);
13812b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	RCU_INIT_POINTER(ifmsh->beacon, NULL);
1382ad2d223aa900179031feb40273881e212941573dJohannes Berg
1383ad2d223aa900179031feb40273881e212941573dJohannes Berg	sdata->vif.bss_conf.bssid = zero_addr;
1384472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1385