mesh.c revision 511044ea0bfc06614d903263ad094d1071fa172f
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"
152e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
16bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic int mesh_allocated;
172e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic struct kmem_cache *rm_cache;
182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1925d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersenbool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
2025d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen{
2125d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen	return (mgmt->u.action.u.mesh_action.action_code ==
2225d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen			WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
2325d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen}
2425d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen
252e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid ieee80211s_init(void)
262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_pathtbl_init();
282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_allocated = 1;
292e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo				     0, 0, NULL);
312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid ieee80211s_stop(void)
342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
35bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	if (!mesh_allocated)
36bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return;
372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_pathtbl_unregister();
382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	kmem_cache_destroy(rm_cache);
392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
41472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_housekeeping_timer(unsigned long data)
42472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
43472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_sub_if_data *sdata = (void *) data;
44472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
45472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
46472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
476b9ac4425d6ec871faf54540e0f1c5ff420a8f29Rui Paulo	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
485bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
4964592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg	ieee80211_queue_work(&local->hw, &sdata->work);
50472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
51472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
522e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
532e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_matches_local - check if the config of a mesh point matches ours
542e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
55f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene * @sdata: local mesh subif
56f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen * @ie: information elements of a management frame from the mesh peer
572e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
582e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * This function checks if the mesh configuration of a mesh point matches the
592e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * local mesh configuration, i.e. if both nodes belong to the same mesh network.
602e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
61f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersenbool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
62f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen			struct ieee802_11_elems *ie)
632e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
64472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
65739522baa1d6804a3ff33e8c135db0e6b2165f75Thomas Pedersen	struct ieee80211_local *local = sdata->local;
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
8855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	ieee80211_sta_get_rates(local, 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
16445b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen	if (changed)
1652b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		ieee80211_mbss_info_change_notify(sdata, changed);
16645b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen}
16745b5028e86292284f4d5794047d5dfd742c22421Thomas Pedersen
168f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greeneint mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
1692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
1712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
172472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
173472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!sdata->u.mesh.rmc)
1742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return -ENOMEM;
175472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
1762e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i < RMC_BUCKETS; i++)
177b7cfcd113ac2a1e6b02afc7d283295729fc178a9Thomas Pedersen		INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i]);
1782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return 0;
1792e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1802e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
181f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenevoid mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
1822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
183472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
1842e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct rmc_entry *p, *n;
1852e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
1862e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
187472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!sdata->u.mesh.rmc)
1882e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return;
1892e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
190bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	for (i = 0; i < RMC_BUCKETS; i++) {
191b7cfcd113ac2a1e6b02afc7d283295729fc178a9Thomas Pedersen		list_for_each_entry_safe(p, n, &rmc->bucket[i], list) {
1922e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			list_del(&p->list);
1932e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			kmem_cache_free(rm_cache, p);
1942e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		}
195bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	}
1962e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1972e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	kfree(rmc);
198472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc = NULL;
1992e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2002e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2012e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
2022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
2032e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
204bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg * @sdata:	interface
2052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @sa:		source address
2062e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @mesh_hdr:	mesh_header
2072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
2082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Returns: 0 if the frame is not in the cache, nonzero otherwise.
2092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
2102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Checks using the source address and the mesh sequence number if we have
2112e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * received this frame lately. If the frame is not in the cache, it is added to
2122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * it.
2132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
214bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
215bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		   const u8 *sa, struct ieee80211s_hdr *mesh_hdr)
2162e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
217472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
2182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u32 seqnum = 0;
2192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int entries = 0;
2202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u8 idx;
2212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct rmc_entry *p, *n;
2222e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Don't care about endianness since only match matters */
22451ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
22551ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
226b7cfcd113ac2a1e6b02afc7d283295729fc178a9Thomas Pedersen	list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
2272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		++entries;
2282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		if (time_after(jiffies, p->exp_time) ||
229bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		    entries == RMC_QUEUE_MAX_LEN) {
2302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			list_del(&p->list);
2312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			kmem_cache_free(rm_cache, p);
2322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			--entries;
233bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		} else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa))
2342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			return -1;
2352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
238d15b84590a1d2ec021ada00a0e67ee5851a0ea2bJoe Perches	if (!p)
2392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return 0;
240d15b84590a1d2ec021ada00a0e67ee5851a0ea2bJoe Perches
2412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p->seqnum = seqnum;
2422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p->exp_time = jiffies + RMC_TIMEOUT;
2432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(p->sa, sa, ETH_ALEN);
244b7cfcd113ac2a1e6b02afc7d283295729fc178a9Thomas Pedersen	list_add(&p->list, &rmc->bucket[idx]);
2452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return 0;
2462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2472e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
248bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
249bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			 struct sk_buff *skb)
250082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
251082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
252082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 *pos, neighbors;
253082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
254082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
255082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (skb_tailroom(skb) < 2 + meshconf_len)
256082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return -ENOMEM;
257082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
258082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	pos = skb_put(skb, 2 + meshconf_len);
259082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = WLAN_EID_MESH_CONFIG;
260082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = meshconf_len;
261082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
262082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Active path selection protocol ID */
263082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_pp_id;
264082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Active path selection metric ID   */
265082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_pm_id;
266082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Congestion control mode identifier */
267082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_cc_id;
268082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Synchronization protocol identifier */
269082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_sp_id;
270082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Authentication Protocol identifier */
271082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_auth_id;
272082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Mesh Formation Info - number of neighbors */
2731258d97616fdca9abc0c21f2edeb1d5b21dcb128Ashok Nagarajan	neighbors = atomic_read(&ifmsh->estab_plinks);
274082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Number of neighbor mesh STAs or 15 whichever is smaller */
275082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	neighbors = (neighbors > 15) ? 15 : neighbors;
276082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = neighbors << 1;
277082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* Mesh capability */
27865821635d26d3173a3b22781e2c60d5e6fcaeb22Marco Porsch	*pos = IEEE80211_MESHCONF_CAPAB_FORWARDING;
279dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	*pos |= ifmsh->accepting_plinks ?
280bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
2813f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
2823f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos |= ifmsh->ps_peers_deep_sleep ?
283bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
284dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	*pos++ |= ifmsh->adjusting_tbtt ?
285bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
286082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = 0x00;
287082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
288082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
289082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
290082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
291bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
292082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
293082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
294082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 *pos;
295082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
296082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
297082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return -ENOMEM;
298082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
299082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
300082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = WLAN_EID_MESH_ID;
301082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	*pos++ = ifmsh->mesh_id_len;
302082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (ifmsh->mesh_id_len)
303082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
304082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
305082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
306082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
307082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
308bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata,
309bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				    struct sk_buff *skb)
3103f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch{
3113f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
3123f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	u8 *pos;
3133f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3143f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* see IEEE802.11-2012 13.14.6 */
3153f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	if (ifmsh->ps_peers_light_sleep == 0 &&
3163f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	    ifmsh->ps_peers_deep_sleep == 0 &&
3173f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	    ifmsh->nonpeer_pm == NL80211_MESH_POWER_ACTIVE)
3183f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch		return 0;
3193f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3203f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	if (skb_tailroom(skb) < 4)
3213f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch		return -ENOMEM;
3223f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3233f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	pos = skb_put(skb, 2 + 2);
3243f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos++ = WLAN_EID_MESH_AWAKE_WINDOW;
3253f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	*pos++ = 2;
3263f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	put_unaligned_le16(ifmsh->mshcfg.dot11MeshAwakeWindowDuration, pos);
3273f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
3283f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	return 0;
3293f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch}
3303f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
331bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
332bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			struct sk_buff *skb)
333082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
334082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
335082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 offset, len;
336082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	const u8 *data;
337082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
338082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (!ifmsh->ie || !ifmsh->ie_len)
339082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return 0;
340082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
341082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* fast-forward to vendor IEs */
342082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
343082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
344082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (offset) {
345082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		len = ifmsh->ie_len - offset;
346082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		data = ifmsh->ie + offset;
347082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (skb_tailroom(skb) < len)
348082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			return -ENOMEM;
349082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(skb_put(skb, len), data, len);
350082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
351082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
352082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
353082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
354082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
355bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
356082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
357082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
358082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 len = 0;
359082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	const u8 *data;
360082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
361082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (!ifmsh->ie || !ifmsh->ie_len)
362082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return 0;
363082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
364082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	/* find RSN IE */
365082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	data = ifmsh->ie;
366082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	while (data < ifmsh->ie + ifmsh->ie_len) {
367082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (*data == WLAN_EID_RSN) {
368082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			len = data[1] + 2;
369082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			break;
370082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		}
371082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		data++;
372082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
373082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
374082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (len) {
375082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		if (skb_tailroom(skb) < len)
376082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen			return -ENOMEM;
377082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		memcpy(skb_put(skb, len), data, len);
378082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	}
379082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
380082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
381082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen}
382082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
383bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata,
384bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				 struct sk_buff *skb)
385082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen{
38655de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_chanctx_conf *chanctx_conf;
38755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_channel *chan;
388082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	u8 *pos;
3892e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
390082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	if (skb_tailroom(skb) < 3)
391082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen		return -ENOMEM;
392082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen
39355de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_lock();
39455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
39555de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	if (WARN_ON(!chanctx_conf)) {
39655de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		rcu_read_unlock();
39755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		return -EINVAL;
39855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	}
3994bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	chan = chanctx_conf->def.chan;
40055de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_unlock();
40155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
402601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	pos = skb_put(skb, 2 + 1);
403601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = WLAN_EID_DS_PARAMS;
404601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = 1;
405601513aa208f27ea87400a410d42c978421530ecEmanuel Taube	*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
406be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo
407082ebb0c258d28af7452b19df9ef8b7553f37690Thomas Pedersen	return 0;
4082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
4092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
410bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
411bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		       struct sk_buff *skb)
412176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen{
413176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_local *local = sdata->local;
41455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
415176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_supported_band *sband;
416176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	u8 *pos;
417176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
41855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	sband = local->hw.wiphy->bands[band];
419176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (!sband->ht_cap.ht_supported ||
4204bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
421176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return 0;
422176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
423176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
424176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return -ENOMEM;
425176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
426176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
427ef96a84202ccfb48a4569256ffba45e32308f7eeBen Greear	ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
428176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
429176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	return 0;
430176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen}
431176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
432bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
433bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			struct sk_buff *skb)
434176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen{
435176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	struct ieee80211_local *local = sdata->local;
43655de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_chanctx_conf *chanctx_conf;
43755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_channel *channel;
438466f310d100ff54f346c1be481af9935c42467b3Johannes Berg	enum nl80211_channel_type channel_type =
4394bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg		cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef);
44055de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_supported_band *sband;
44155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	struct ieee80211_sta_ht_cap *ht_cap;
442176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	u8 *pos;
443176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
44455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_lock();
44555de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
44655de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	if (WARN_ON(!chanctx_conf)) {
44755de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		rcu_read_unlock();
44855de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg		return -EINVAL;
44955de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	}
4504bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	channel = chanctx_conf->def.chan;
45155de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	rcu_read_unlock();
45255de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
45355de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	sband = local->hw.wiphy->bands[channel->band];
45455de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg	ht_cap = &sband->ht_cap;
45555de908ab292c03f1eb280f51170ddb9c6b57e31Johannes Berg
456176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
457176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return 0;
458176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
459074d46d1d23f27488a3f314e29cae2453541f17dJohannes Berg	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
460176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen		return -ENOMEM;
461176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
462074d46d1d23f27488a3f314e29cae2453541f17dJohannes Berg	pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
4634bf88530be971bf95a7830ca61b4120980bf4347Johannes Berg	ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
464431e31542383b71bc5f2642572a1e6ef07f1bb87Ashok Nagarajan				   sdata->vif.bss_conf.ht_operation_mode);
465176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen
466176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen	return 0;
467176f36086e8a00bdf701dc6e4c5a8784ef6529dfThomas Pedersen}
468bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
4692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic void ieee80211_mesh_path_timer(unsigned long data)
4702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
4712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_sub_if_data *sdata =
4722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		(struct ieee80211_sub_if_data *) data;
4735bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
474690205f18fd069898c70d743f498ba42798e5c4eStanislaw Gruszka	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
4752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
4762e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
477e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulostatic void ieee80211_mesh_path_root_timer(unsigned long data)
478e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo{
479e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_sub_if_data *sdata =
480e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		(struct ieee80211_sub_if_data *) data;
481e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
482e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
483e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
484e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
485690205f18fd069898c70d743f498ba42798e5c4eStanislaw Gruszka	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
486e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo}
487e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
48863c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulovoid ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
48963c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo{
490dbb912cd4ce64e763c5610b49a85529d2634e9d8Chun-Yeow Yeoh	if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)
49163c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
49263c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	else {
49363c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
49463c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		/* stop running timer */
49563c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		del_timer_sync(&ifmsh->mesh_path_root_timer);
49663c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	}
49763c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo}
49863c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo
499902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg/**
5003c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
501bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg * @hdr:	802.11 frame header
5023c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @fc:		frame control field
5033c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @meshda:	destination address in the mesh
5043c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @meshsa:	source address address in the mesh.  Same as TA, as frame is
5053c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *              locally originated.
5063c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *
5073c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * Return the length of the 802.11 (does not include a mesh control header)
5083c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona */
50915ff63653e507ec928a4a4386405a82446e096b1Johannes Bergint ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
51015ff63653e507ec928a4a4386405a82446e096b1Johannes Berg				  const u8 *meshda, const u8 *meshsa)
51115ff63653e507ec928a4a4386405a82446e096b1Johannes Berg{
5123c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	if (is_multicast_ether_addr(meshda)) {
5133c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
5143c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		/* DA TA SA */
5153c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr1, meshda, ETH_ALEN);
5163c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr2, meshsa, ETH_ALEN);
5173c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr3, meshsa, ETH_ALEN);
5183c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		return 24;
5193c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	} else {
5202154c81c32fa44364f83218a10d8dbec4e76d4f5Javier Cardona		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
5213c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		/* RA TA DA SA */
5223c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memset(hdr->addr1, 0, ETH_ALEN);   /* RA is resolved later */
5233c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr2, meshsa, ETH_ALEN);
5243c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr3, meshda, ETH_ALEN);
5253c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr4, meshsa, ETH_ALEN);
5263c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		return 30;
5273c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
5283c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona}
5293c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona
5303c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona/**
531902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * ieee80211_new_mesh_header - create a new mesh header
532902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * @sdata:	mesh interface to be used
533bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg * @meshhdr:    uninitialized mesh header
53461ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona * @addr4or5:   1st address in the ae header, which may correspond to address 4
53561ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              (if addr6 is NULL) or address 5 (if addr6 is present). It may
53661ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              be NULL.
53761ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona * @addr6:	2nd address in the ae header, which corresponds to addr6 of the
53861ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona *              mesh frame
539902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg *
540902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * Return the header length.
541902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg */
542bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergint ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
543bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			      struct ieee80211s_hdr *meshhdr,
544bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg			      const char *addr4or5, const char *addr6)
545902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
546bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	if (WARN_ON(!addr4or5 && addr6))
547bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 0;
548bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
5490c3cee72a403e3b4992a5478c9c33d668c246c22Julia Lawall	memset(meshhdr, 0, sizeof(*meshhdr));
550bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
551472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
552bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
553bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	/* FIXME: racy -- TX on multiple queues can be concurrent */
554472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
555472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.mesh_seqnum++;
556bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
55761ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona	if (addr4or5 && !addr6) {
5583c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		meshhdr->flags |= MESH_FLAGS_AE_A4;
55961ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
560bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 2 * ETH_ALEN;
56161ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona	} else if (addr4or5 && addr6) {
5623c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
56361ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
56461ad5394590c5c5338ab4ec50553d809a9996d50Javier Cardona		memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
565bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		return 3 * ETH_ALEN;
5663c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
567bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg
568bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	return ETH_ALEN;
569902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg}
570902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg
571bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Bergstatic void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
572472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
573bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
574df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	u32 changed;
575472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
576472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
577472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mesh_path_expire(sdata);
578472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
579df32381896f5f0c78a371df2e49ab7c776b1a5baMarco Porsch	changed = mesh_accept_plinks_update(sdata);
5802b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	ieee80211_mbss_info_change_notify(sdata, changed);
581472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
582472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mod_timer(&ifmsh->housekeeping_timer,
583bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		  round_jiffies(jiffies +
584bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg				IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
585472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
586472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
587e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulostatic void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
588e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo{
589e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
590a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	u32 interval;
591e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
592e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	mesh_path_tx_root_frame(sdata);
593a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh
594a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN)
595a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
596a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh	else
597a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		interval = ifmsh->mshcfg.dot11MeshHWMProotInterval;
598a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh
599e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	mod_timer(&ifmsh->mesh_path_root_timer,
600a69cc44fe9ebb806c5f3f8bd83fb4a50ca63647bChun-Yeow Yeoh		  round_jiffies(TU_TO_EXP_TIME(interval)));
601e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo}
602e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
6032b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenstatic int
6042b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
6052b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
6062b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *bcn;
6072b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int head_len, tail_len;
6082b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct sk_buff *skb;
6092b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_mgmt *mgmt;
6102b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_chanctx_conf *chanctx_conf;
6112b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	enum ieee80211_band band;
6122b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	u8 *pos;
6132b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct ieee80211_sub_if_data *sdata;
6142b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
6152b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		      sizeof(mgmt->u.beacon);
6162b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6172b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
6182b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_read_lock();
6192b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
6202b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	band = chanctx_conf->def.chan->band;
6212b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_read_unlock();
6222b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6232b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	head_len = hdr_len +
6242b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + /* NULL SSID */
6252b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + 8 + /* supported rates */
6262b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + 3; /* DS params */
6272b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
6282b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_ht_cap) +
6292b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_ht_operation) +
6302b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + ifmsh->mesh_id_len +
6312b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(struct ieee80211_meshconf_ie) +
6322b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   2 + sizeof(__le16) + /* awake window */
6332b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		   ifmsh->ie_len;
6342b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6352b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
6362b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/* need an skb for IE builders to operate on */
6372b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	skb = dev_alloc_skb(max(head_len, tail_len));
6382b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6392b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (!bcn || !skb)
6402b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		goto out_free;
6412b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6422b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/*
6432b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 * pointers go into the block we allocated,
6442b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 * memory is | beacon_data | head | tail |
6452b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	 */
6462b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->head = ((u8 *) bcn) + sizeof(*bcn);
6472b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6482b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/* fill in the head */
6492b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
6502b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memset(mgmt, 0, hdr_len);
6512b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
6522b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen					  IEEE80211_STYPE_BEACON);
6532b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	eth_broadcast_addr(mgmt->da);
6542b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
6552b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
6562b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt);
6572b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->u.beacon.beacon_int =
6582b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		cpu_to_le16(sdata->vif.bss_conf.beacon_int);
6592b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mgmt->u.beacon.capab_info |= cpu_to_le16(
6602b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
6612b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6622b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	pos = skb_put(skb, 2);
6632b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	*pos++ = WLAN_EID_SSID;
6642b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	*pos++ = 0x0;
6652b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6662b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
667bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_ds_params_ie(sdata, skb))
6682b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		goto out_free;
6692b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6702b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->head_len = skb->len;
6712b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(bcn->head, skb->data, bcn->head_len);
6722b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6732b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	/* now the tail */
6742b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	skb_trim(skb, 0);
6752b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->tail = bcn->head + bcn->head_len;
6762b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6772b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
678bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_rsn_ie(sdata, skb) ||
679bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_ht_cap_ie(sdata, skb) ||
680bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_ht_oper_ie(sdata, skb) ||
681bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_meshid_ie(sdata, skb) ||
682bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_meshconf_ie(sdata, skb) ||
683bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_awake_window_ie(sdata, skb) ||
684bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg	    mesh_add_vendor_ies(sdata, skb))
6852b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		goto out_free;
6862b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6872b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn->tail_len = skb->len;
6882b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	memcpy(bcn->tail, skb->data, bcn->tail_len);
6892b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6902b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	dev_kfree_skb(skb);
6912b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_assign_pointer(ifmsh->beacon, bcn);
6922b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return 0;
6932b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenout_free:
6942b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	kfree(bcn);
6952b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	dev_kfree_skb(skb);
6962b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return -ENOMEM;
6972b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
6982b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
6992b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenstatic int
7002b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenieee80211_mesh_rebuild_beacon(struct ieee80211_if_mesh *ifmsh)
7012b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
7022b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *old_bcn;
7032b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	int ret;
7042b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7052b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mutex_lock(&ifmsh->mtx);
7062b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7072b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	old_bcn = rcu_dereference_protected(ifmsh->beacon,
7082b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen					    lockdep_is_held(&ifmsh->mtx));
7092b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	ret = ieee80211_mesh_build_beacon(ifmsh);
7102b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ret)
7112b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		/* just reuse old beacon */
7122b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		goto out;
7132b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7142b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (old_bcn)
7152b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		kfree_rcu(old_bcn, rcu_head);
7162b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenout:
7172b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mutex_unlock(&ifmsh->mtx);
7182b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return ret;
7192b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
7202b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7212b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenvoid ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
7222b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen				       u32 changed)
7232b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen{
7242b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (sdata->vif.bss_conf.enable_beacon &&
7252b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	    (changed & (BSS_CHANGED_BEACON |
7262b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen			BSS_CHANGED_HT |
7272b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen			BSS_CHANGED_BASIC_RATES |
7282b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen			BSS_CHANGED_BEACON_INT)))
7292b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		if (ieee80211_mesh_rebuild_beacon(&sdata->u.mesh))
7302b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen			return;
7312b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	ieee80211_bss_info_change_notify(sdata, changed);
7322b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen}
7332b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
7342b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersenint ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
735472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
736472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
737472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
738f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh	u32 changed = BSS_CHANGED_BEACON |
739f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BEACON_ENABLED |
740f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_HT |
741f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BASIC_RATES |
742f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		      BSS_CHANGED_BEACON_INT;
743f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
744472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
74509b174702601079c3a04806754be30ffbd70db4dJohannes Berg	local->fif_other_bss++;
74609b174702601079c3a04806754be30ffbd70db4dJohannes Berg	/* mesh ifaces must set allmulti to forward mcast traffic */
74709b174702601079c3a04806754be30ffbd70db4dJohannes Berg	atomic_inc(&local->iff_allmultis);
74809b174702601079c3a04806754be30ffbd70db4dJohannes Berg	ieee80211_configure_filter(local);
74909b174702601079c3a04806754be30ffbd70db4dJohannes Berg
750c7108a7111cd9e592d6ad498be37276dbea75d2bJavier Cardona	ifmsh->mesh_cc_id = 0;	/* Disabled */
751c7108a7111cd9e592d6ad498be37276dbea75d2bJavier Cardona	ifmsh->mesh_auth_id = 0;	/* Disabled */
752dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	/* register sync ops from extensible synchronization framework */
753dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id);
754dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->adjusting_tbtt = false;
755dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	ifmsh->sync_offset_clockdrift_max = 0;
7566b9ac4425d6ec871faf54540e0f1c5ff420a8f29Rui Paulo	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
75763c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	ieee80211_mesh_root_setup(ifmsh);
75864592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg	ieee80211_queue_work(&local->hw, &sdata->work);
75970c33eaae79e53f9e48324736c0cb85534d3f093Ashok Nagarajan	sdata->vif.bss_conf.ht_operation_mode =
76070c33eaae79e53f9e48324736c0cb85534d3f093Ashok Nagarajan				ifmsh->mshcfg.ht_opmode;
761d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	sdata->vif.bss_conf.enable_beacon = true;
762d934f7d0d6a3f8aa3049ca0692948ec59d738928Ashok Nagarajan	sdata->vif.bss_conf.basic_rates =
763f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh		ieee80211_mandatory_rates(local, band);
764f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh
76539886b618aba3c39e650c191d601e26ec581ce0fThomas Pedersen	changed |= ieee80211_mps_local_status_update(sdata);
7663f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
7672b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	if (ieee80211_mesh_build_beacon(ifmsh)) {
7682b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		ieee80211_stop_mesh(sdata);
7692b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen		return -ENOMEM;
7702b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	}
7712b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen
772f4eabc918c3b88763bc20dd9e2b248aa6c757005Chun-Yeow Yeoh	ieee80211_bss_info_change_notify(sdata, changed);
773c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg
774c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg	netif_carrier_on(sdata->dev);
7752b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	return 0;
776472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
777472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
778472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
779472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
78009b174702601079c3a04806754be30ffbd70db4dJohannes Berg	struct ieee80211_local *local = sdata->local;
78129cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
7822b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	struct beacon_data *bcn;
78329cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg
784c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg	netif_carrier_off(sdata->dev);
785c405c6298eacd423098afacf6020ddbda1b0378bJohannes Berg
7860d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	/* stop the beacon */
78729cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	ifmsh->mesh_id_len = 0;
788d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	sdata->vif.bss_conf.enable_beacon = false;
789d6a83228823fc0cc8d79d95c9f0bf568b7317862Johannes Berg	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
79029cbe68c516a48a9a88b3226878570c6cbd83c02Johannes Berg	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
7912b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mutex_lock(&ifmsh->mtx);
7922b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	bcn = rcu_dereference_protected(ifmsh->beacon,
7932b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen					lockdep_is_held(&ifmsh->mtx));
7942b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	rcu_assign_pointer(ifmsh->beacon, NULL);
7952b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	kfree_rcu(bcn, rcu_head);
7962b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mutex_unlock(&ifmsh->mtx);
7970d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen
7980d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	/* flush STAs and mpaths on this iface */
799b998e8bb3e1c6eeae5eab9d6a434563270286c3bJohannes Berg	sta_info_flush(sdata);
8000d466b9c6798d431141ab15ae6d5ea413b4d09b2Thomas Pedersen	mesh_path_flush_by_iface(sdata);
80109b174702601079c3a04806754be30ffbd70db4dJohannes Berg
8023f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	/* free all potentially still buffered group-addressed frames */
8033f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	local->total_ps_buffered -= skb_queue_len(&ifmsh->ps.bc_buf);
8043f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	skb_queue_purge(&ifmsh->ps.bc_buf);
8053f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch
806472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
807e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
808dd4c9260e7f23f2e951cbfb2726e468c6d30306cJohannes Berg	del_timer_sync(&sdata->u.mesh.mesh_path_timer);
809472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	/*
810b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * If the timer fired while we waited for it, it will have
811b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * requeued the work. Now the work will be running again
812b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * but will not rearm the timer again because it checks
813b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * whether the interface is running, which, at this point,
814b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * it no longer is.
815b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 */
81664592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg	cancel_work_sync(&sdata->work);
81709b174702601079c3a04806754be30ffbd70db4dJohannes Berg
81809b174702601079c3a04806754be30ffbd70db4dJohannes Berg	local->fif_other_bss--;
81909b174702601079c3a04806754be30ffbd70db4dJohannes Berg	atomic_dec(&local->iff_allmultis);
82009b174702601079c3a04806754be30ffbd70db4dJohannes Berg	ieee80211_configure_filter(local);
821472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
822472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
8239fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenstatic void
8249fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
8259fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen			    struct ieee80211_mgmt *mgmt, size_t len)
8269fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen{
8279fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_local *local = sdata->local;
8289fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
8299fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct sk_buff *presp;
8309fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct beacon_data *bcn;
8319fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee80211_mgmt *hdr;
8329fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	struct ieee802_11_elems elems;
8339fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	size_t baselen;
834511044ea0bfc06614d903263ad094d1071fa172fJohannes Berg	u8 *pos;
8359fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
8369fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	pos = mgmt->u.probe_req.variable;
8379fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	baselen = (u8 *) pos - (u8 *) mgmt;
8389fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (baselen > len)
8399fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
8409fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
8419fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	ieee802_11_parse_elems(pos, len - baselen, &elems);
8429fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
8439fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	/* 802.11-2012 10.1.4.3.2 */
8449fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
8459fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	     !is_broadcast_ether_addr(mgmt->da)) ||
8469fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	    elems.ssid_len != 0)
8479fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
8489fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
8499fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (elems.mesh_id_len != 0 &&
8509fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	    (elems.mesh_id_len != ifmsh->mesh_id_len ||
8519fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	     memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
8529fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		return;
8539fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
8549fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	rcu_read_lock();
8559fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	bcn = rcu_dereference(ifmsh->beacon);
8569fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
8579fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (!bcn)
8589fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		goto out;
8599fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
8609fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	presp = dev_alloc_skb(local->tx_headroom +
8619fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen			      bcn->head_len + bcn->tail_len);
8629fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	if (!presp)
8639fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		goto out;
8649fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
8659fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	skb_reserve(presp, local->tx_headroom);
8669fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(skb_put(presp, bcn->head_len), bcn->head, bcn->head_len);
8679fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(skb_put(presp, bcn->tail_len), bcn->tail, bcn->tail_len);
8689fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	hdr = (struct ieee80211_mgmt *) presp->data;
8699fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
8709fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen					 IEEE80211_STYPE_PROBE_RESP);
8719fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	memcpy(hdr->da, mgmt->sa, ETH_ALEN);
8729fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
8739fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	ieee80211_tx_skb(sdata, presp);
8749fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersenout:
8759fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	rcu_read_unlock();
8769fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen}
8779fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen
878472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
879472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					u16 stype,
880472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					struct ieee80211_mgmt *mgmt,
881472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					size_t len,
882472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					struct ieee80211_rx_status *rx_status)
883472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
884c6a1fa12d206882757264869f8e32d606b930e2aJohannes Berg	struct ieee80211_local *local = sdata->local;
885dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
886472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee802_11_elems elems;
887472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_channel *channel;
888472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	size_t baselen;
889472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	int freq;
890472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	enum ieee80211_band band = rx_status->band;
891472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
892472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	/* ignore ProbeResp to foreign address */
893472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (stype == IEEE80211_STYPE_PROBE_RESP &&
894b203ca39126bad99583c908be587df067820a1eaJoe Perches	    !ether_addr_equal(mgmt->da, sdata->vif.addr))
895472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
896472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
897472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
898472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (baselen > len)
899472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
900472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
901472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
902472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg			       &elems);
903472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
9049a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	/* ignore non-mesh or secure / unsecure mismatch */
9059a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	if ((!elems.mesh_id || !elems.mesh_config) ||
9069a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	    (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
9079a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	    (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
9085cff5e01e818029a5d2c3c31b7ae5e5e7ee70452Javier Cardona		return;
9095cff5e01e818029a5d2c3c31b7ae5e5e7ee70452Javier Cardona
910472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (elems.ds_params && elems.ds_params_len == 1)
91159eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
912472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	else
913472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		freq = rx_status->freq;
914472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
915472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	channel = ieee80211_get_channel(local->hw.wiphy, freq);
916472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
917472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
918472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
919472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
9209a90bc81914ee77edcd6eb7e881639b7f7bf1667Thomas Pedersen	if (mesh_matches_local(sdata, &elems))
921f743ff4907fa5bc2b460f48ace831a560806a9fbThomas Pedersen		mesh_neighbour_update(sdata, mgmt->sa, &elems);
922dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona
923dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	if (ifmsh->sync_ops)
924dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona		ifmsh->sync_ops->rx_bcn_presp(sdata,
925dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona			stype, mgmt, &elems, rx_status);
926472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
927472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
928472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
929472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct ieee80211_mgmt *mgmt,
930472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  size_t len,
931472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct ieee80211_rx_status *rx_status)
932472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
933472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (mgmt->u.action.category) {
9348db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen	case WLAN_CATEGORY_SELF_PROTECTED:
9358db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		switch (mgmt->u.action.u.self_prot.action_code) {
9368db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_OPEN:
9378db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_CLOSE:
9388db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		case WLAN_SP_MESH_PEERING_CONFIRM:
9398db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen			mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
9408db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen			break;
9418db098507c5cbe499061d0f6aea426a36e7c72d7Thomas Pedersen		}
942472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
94325d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen	case WLAN_CATEGORY_MESH_ACTION:
94425d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen		if (mesh_action_is_path_sel(mgmt))
94525d49e4d63564c7004a4d6735d1d8c3cc41a7394Thomas Pedersen			mesh_rx_path_sel_frame(sdata, mgmt, len);
946472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
947472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
948472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
949472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
9501fa57d017366fb26b58af110a38b36a4f0214a62Johannes Bergvoid ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
9511fa57d017366fb26b58af110a38b36a4f0214a62Johannes Berg				   struct sk_buff *skb)
952472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
953472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_rx_status *rx_status;
954472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_mgmt *mgmt;
955472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	u16 stype;
956472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
957f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg	rx_status = IEEE80211_SKB_RXCB(skb);
958472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mgmt = (struct ieee80211_mgmt *) skb->data;
959472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
960472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
961472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (stype) {
962472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_PROBE_RESP:
963472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_BEACON:
964472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
965472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					    rx_status);
966472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
9679fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen	case IEEE80211_STYPE_PROBE_REQ:
9689fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len);
9699fb04b501a57ad29fa989ab3cd2123482e7eac5fThomas Pedersen		break;
970472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_ACTION:
971472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
972472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
973472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
974472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
975472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
9761fa57d017366fb26b58af110a38b36a4f0214a62Johannes Bergvoid ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
977472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
978472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
979472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
980472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (ifmsh->preq_queue_len &&
981472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	    time_after(jiffies,
982472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		       ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
983472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		mesh_path_start_discovery(sdata);
984472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
98518889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
98618889231e4527dfe23145efe318e74744794a95dJavier Cardona		mesh_mpath_table_grow();
98718889231e4527dfe23145efe318e74744794a95dJavier Cardona
988dcac908babcd8ce21057e476c8df609b28ad2cd8Nick Ledovskikh	if (test_and_clear_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags))
98918889231e4527dfe23145efe318e74744794a95dJavier Cardona		mesh_mpp_table_grow();
99018889231e4527dfe23145efe318e74744794a95dJavier Cardona
99118889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
992bf7cd94dcc71682cd6af4a9028f95307b7db41c5Johannes Berg		ieee80211_mesh_housekeeping(sdata);
993e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
994e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
995e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		ieee80211_mesh_rootpath(sdata);
996dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona
997dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
998dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona		mesh_sync_adjust_tbtt(sdata);
999472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1000472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1001472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
1002472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
1003472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_sub_if_data *sdata;
1004472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1005472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	rcu_read_lock();
1006472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	list_for_each_entry_rcu(sdata, &local->interfaces, list)
1007472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		if (ieee80211_vif_is_mesh(&sdata->vif))
100864592c8fc0e99d445fc3fdedddeb6088e20086f1Johannes Berg			ieee80211_queue_work(&local->hw, &sdata->work);
1009472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	rcu_read_unlock();
1010472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1011472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1012902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Bergvoid ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
1013902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
1014472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1015ad2d223aa900179031feb40273881e212941573dJohannes Berg	static u8 zero_addr[ETH_ALEN] = {};
1016472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1017472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	setup_timer(&ifmsh->housekeeping_timer,
1018472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		    ieee80211_mesh_housekeeping_timer,
1019472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		    (unsigned long) sdata);
1020472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
1021472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->accepting_plinks = true;
1022472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->preq_id = 0;
1023d19b3bf6384e66ac6e11a61ee31ed2cfe149f4d8Rui Paulo	ifmsh->sn = 0;
10245ee68e5b39de5cefecf147c58711f8ab01c21231Javier Cardona	ifmsh->num_gates = 0;
1025472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	atomic_set(&ifmsh->mpaths, 0);
1026f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	mesh_rmc_init(sdata);
1027472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->last_preq = jiffies;
1028dca7e9430cb3e492437a5ce891b8b3e315c147caThomas Pedersen	ifmsh->next_perr = jiffies;
1029902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	/* Allocate all mesh structures when creating the first mesh interface. */
1030902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	if (!mesh_allocated)
1031902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		ieee80211s_init();
1032472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	setup_timer(&ifmsh->mesh_path_timer,
1033902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    ieee80211_mesh_path_timer,
1034902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    (unsigned long) sdata);
1035e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	setup_timer(&ifmsh->mesh_path_root_timer,
1036e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		    ieee80211_mesh_path_root_timer,
1037e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		    (unsigned long) sdata);
1038472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
10393f52b7e328c526fa7a592af9bf5772c591ed38a4Marco Porsch	skb_queue_head_init(&ifmsh->ps.bc_buf);
1040472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
1041dbf498fbafa2c23139d5a990e94ed78bafbbea19Javier Cardona	spin_lock_init(&ifmsh->sync_offset_lock);
10422b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	RCU_INIT_POINTER(ifmsh->beacon, NULL);
10432b5e19677592c167d012c2d129407f39d2bdeb8dThomas Pedersen	mutex_init(&ifmsh->mtx);
1044ad2d223aa900179031feb40273881e212941573dJohannes Berg
1045ad2d223aa900179031feb40273881e212941573dJohannes Berg	sdata->vif.bss_conf.bssid = zero_addr;
1046472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
1047