mesh.c revision 264d9b7d8a629620c8de84c614910c3164e935f8
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
1151ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo#include <asm/unaligned.h>
122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo#include "ieee80211_i.h"
132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo#include "mesh.h"
142e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
15472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
16472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
17e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo#define IEEE80211_MESH_RANN_INTERVAL	     (1 * HZ)
18472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
193491707a070c1183c709516b2f876f798c7a9a84Rui Paulo#define MESHCONF_PP_OFFSET 	0		/* Path Selection Protocol */
203491707a070c1183c709516b2f876f798c7a9a84Rui Paulo#define MESHCONF_PM_OFFSET	1		/* Path Selection Metric   */
213491707a070c1183c709516b2f876f798c7a9a84Rui Paulo#define MESHCONF_CC_OFFSET	2		/* Congestion Control Mode */
223491707a070c1183c709516b2f876f798c7a9a84Rui Paulo#define MESHCONF_SP_OFFSET	3		/* Synchronization Protocol */
233491707a070c1183c709516b2f876f798c7a9a84Rui Paulo#define MESHCONF_AUTH_OFFSET	4		/* Authentication Protocol */
243491707a070c1183c709516b2f876f798c7a9a84Rui Paulo#define MESHCONF_CAPAB_OFFSET 	6
253491707a070c1183c709516b2f876f798c7a9a84Rui Paulo#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
263491707a070c1183c709516b2f876f798c7a9a84Rui Paulo#define MESHCONF_CAPAB_FORWARDING    0x08
272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
285bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg#define TMR_RUNNING_HK	0
295bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg#define TMR_RUNNING_MP	1
30e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo#define TMR_RUNNING_MPR	2
315bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Coboint mesh_allocated;
332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic struct kmem_cache *rm_cache;
342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid ieee80211s_init(void)
362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_pathtbl_init();
382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_allocated = 1;
392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo				     0, 0, NULL);
412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid ieee80211s_stop(void)
442e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_pathtbl_unregister();
462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	kmem_cache_destroy(rm_cache);
472e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
482e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
49472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_housekeeping_timer(unsigned long data)
50472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
51472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_sub_if_data *sdata = (void *) data;
52472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
53472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
54472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
556b9ac4425d6ec871faf54540e0f1c5ff420a8f29Rui Paulo	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
565bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
575bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	if (local->quiescing) {
585bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg		set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
595bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg		return;
605bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	}
615bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
62c03e20fc9a6ec5741d9df561130ecba38ef50eb6Luis R. Rodriguez	ieee80211_queue_work(&local->hw, &ifmsh->work);
63472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
64472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
652e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
662e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_matches_local - check if the config of a mesh point matches ours
672e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
682e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @ie: information elements of a management frame from the mesh peer
69f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene * @sdata: local mesh subif
702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * This function checks if the mesh configuration of a mesh point matches the
722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * local mesh configuration, i.e. if both nodes belong to the same mesh network.
732e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
74f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenebool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
76472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
772e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/*
792e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * As support for each feature is added, check for matching
802e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * - On mesh config capabilities
812e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Power Save Support En
822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support enabled
832e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support active
842e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support required from peer
852e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - MDA enabled
862e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * - Power management control on fc
872e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 */
88472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (ifmsh->mesh_id_len == ie->mesh_id_len &&
89472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
903491707a070c1183c709516b2f876f798c7a9a84Rui Paulo		(ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&&
913491707a070c1183c709516b2f876f798c7a9a84Rui Paulo		(ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&&
923491707a070c1183c709516b2f876f798c7a9a84Rui Paulo		(ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&&
933491707a070c1183c709516b2f876f798c7a9a84Rui Paulo		(ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&&
943491707a070c1183c709516b2f876f798c7a9a84Rui Paulo		(ifmsh->mesh_auth_id == *(ie->mesh_config +
953491707a070c1183c709516b2f876f798c7a9a84Rui Paulo		    MESHCONF_AUTH_OFFSET)))
962e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return true;
972e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
982e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return false;
992e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1002e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1012e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
1022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links
1032e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
1042e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @ie: information elements of a management frame from the mesh peer
1052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
106f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenebool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
1072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1083491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) &
1093491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	    MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
1102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1112e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
1132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_accept_plinks_update: update accepting_plink in local mesh beacons
1142e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
115d0709a65181beb787ef3f58cfe45536a2bb254c8Johannes Berg * @sdata: mesh interface in which mesh beacons are going to be updated
1162e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
117d0709a65181beb787ef3f58cfe45536a2bb254c8Johannes Bergvoid mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
1182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	bool free_plinks;
1202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
1222e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * the mesh interface might be able to establish plinks with peers that
123b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * are already on the table but are not on PLINK_ESTAB state. However,
124b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * in general the mesh interface is not accepting peer link requests
125b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * from new peers, and that must be reflected in the beacon
1262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 */
1272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	free_plinks = mesh_plink_availables(sdata);
1282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
129472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (free_plinks != sdata->u.mesh.accepting_plinks)
130472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_housekeeping_timer((unsigned long) sdata);
1312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
133472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid mesh_ids_set_default(struct ieee80211_if_mesh *sta)
1342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1353491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	sta->mesh_pp_id = 0;	/* HWMP */
1363491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	sta->mesh_pm_id = 0;	/* Airtime */
1373491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	sta->mesh_cc_id = 0;	/* Disabled */
1383491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	sta->mesh_sp_id = 0;	/* Neighbor Offset */
1393491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	sta->mesh_auth_id = 0;	/* Disabled */
1402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
142f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greeneint mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
1432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1442e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
1452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
146472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
147472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!sdata->u.mesh.rmc)
1482e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return -ENOMEM;
149472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
1502e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i < RMC_BUCKETS; i++)
151472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list);
1522e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return 0;
1532e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1542e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
155f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenevoid mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
1562e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
157472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
1582e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct rmc_entry *p, *n;
1592e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
1602e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
161472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!sdata->u.mesh.rmc)
1622e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return;
1632e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1642e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i < RMC_BUCKETS; i++)
1652e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) {
1662e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			list_del(&p->list);
1672e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			kmem_cache_free(rm_cache, p);
1682e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		}
1692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	kfree(rmc);
171472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.rmc = NULL;
1722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1732e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
1752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
1762e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
1772e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @sa:		source address
1782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @mesh_hdr:	mesh_header
1792e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
1802e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Returns: 0 if the frame is not in the cache, nonzero otherwise.
1812e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
1822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Checks using the source address and the mesh sequence number if we have
1832e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * received this frame lately. If the frame is not in the cache, it is added to
1842e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * it.
1852e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
1862e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Coboint mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
187f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene		   struct ieee80211_sub_if_data *sdata)
1882e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
189472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
1902e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u32 seqnum = 0;
1912e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int entries = 0;
1922e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u8 idx;
1932e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct rmc_entry *p, *n;
1942e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1952e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Don't care about endianness since only match matters */
19651ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
19751ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
1982e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) {
1992e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		++entries;
2002e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		if (time_after(jiffies, p->exp_time) ||
2012e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo				(entries == RMC_QUEUE_MAX_LEN)) {
2022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			list_del(&p->list);
2032e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			kmem_cache_free(rm_cache, p);
2042e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			--entries;
2052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		} else if ((seqnum == p->seqnum)
2062e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo				&& (memcmp(sa, p->sa, ETH_ALEN) == 0))
2072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			return -1;
2082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
2112e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!p) {
2122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		printk(KERN_DEBUG "o11s: could not allocate RMC entry\n");
2132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return 0;
2142e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2152e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p->seqnum = seqnum;
2162e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p->exp_time = jiffies + RMC_TIMEOUT;
2172e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(p->sa, sa, ETH_ALEN);
2182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	list_add(&p->list, &rmc->bucket[idx].list);
2192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return 0;
2202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
222f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenevoid mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
2232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
224f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	struct ieee80211_local *local = sdata->local;
2252e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_supported_band *sband;
2262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u8 *pos;
2272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int len, i, rate;
2288f2fda9594f083981ad54c1994863875fe680925Rui Paulo	u8 neighbors;
2292e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
2312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	len = sband->n_bitrates;
2322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (len > 8)
2332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		len = 8;
2342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	pos = skb_put(skb, len + 2);
2352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = WLAN_EID_SUPP_RATES;
2362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = len;
2372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i < len; i++) {
2382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		rate = sband->bitrates[i].bitrate;
2392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		*pos++ = (u8) (rate / 5);
2402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (sband->n_bitrates > len) {
2432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		pos = skb_put(skb, sband->n_bitrates - len + 2);
2442e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		*pos++ = WLAN_EID_EXT_SUPP_RATES;
2452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		*pos++ = sband->n_bitrates - len;
2462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		for (i = len; i < sband->n_bitrates; i++) {
2472e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			rate = sband->bitrates[i].bitrate;
2482e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			*pos++ = (u8) (rate / 5);
2492e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		}
2502e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2512e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
252be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo	if (sband->band == IEEE80211_BAND_2GHZ) {
253be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo		pos = skb_put(skb, 2 + 1);
254be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo		*pos++ = WLAN_EID_DS_PARAMS;
255be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo		*pos++ = 1;
256be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo		*pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
257be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo	}
258be125c60e46e165fbfe33db36a4a9d943d560a5bRui Paulo
259472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len);
2602e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = WLAN_EID_MESH_ID;
261472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	*pos++ = sdata->u.mesh.mesh_id_len;
262472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (sdata->u.mesh.mesh_id_len)
263472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
2642e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2659e03fdfd05e733e1136d431973625b174029c5e6Javier Cardona	pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN);
2662e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = WLAN_EID_MESH_CONFIG;
2671239cd58d237fa6ad501acaec8776262a5784ec8Johannes Berg	*pos++ = IEEE80211_MESH_CONFIG_LEN;
2682e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Active path selection protocol ID */
2703491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	*pos++ = sdata->u.mesh.mesh_pp_id;
2712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Active path selection metric ID   */
2733491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	*pos++ = sdata->u.mesh.mesh_pm_id;
2742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Congestion control mode identifier */
2763491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	*pos++ = sdata->u.mesh.mesh_cc_id;
2772e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2789e03fdfd05e733e1136d431973625b174029c5e6Javier Cardona	/* Synchronization protocol identifier */
2793491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	*pos++ = sdata->u.mesh.mesh_sp_id;
2802e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2819e03fdfd05e733e1136d431973625b174029c5e6Javier Cardona	/* Authentication Protocol identifier */
2823491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	*pos++ = sdata->u.mesh.mesh_auth_id;
2839e03fdfd05e733e1136d431973625b174029c5e6Javier Cardona
2848f2fda9594f083981ad54c1994863875fe680925Rui Paulo	/* Mesh Formation Info - number of neighbors */
2858f2fda9594f083981ad54c1994863875fe680925Rui Paulo	neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
2868f2fda9594f083981ad54c1994863875fe680925Rui Paulo	/* Number of neighbor mesh STAs or 15 whichever is smaller */
2878f2fda9594f083981ad54c1994863875fe680925Rui Paulo	neighbors = (neighbors > 15) ? 15 : neighbors;
2888f2fda9594f083981ad54c1994863875fe680925Rui Paulo	*pos++ = neighbors << 1;
2899e03fdfd05e733e1136d431973625b174029c5e6Javier Cardona
2902e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Mesh capability */
291472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
2923491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	*pos = MESHCONF_CAPAB_FORWARDING;
2933491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	*pos++ |= sdata->u.mesh.accepting_plinks ?
2943491707a070c1183c709516b2f876f798c7a9a84Rui Paulo	    MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
2952e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = 0x00;
2962e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2972e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return;
2982e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2992e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
300f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greeneu32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl)
3012e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
3022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Use last four bytes of hw addr and interface index as hash index */
303f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd)
3042e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		& tbl->hash_mask;
3052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
3062e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostruct mesh_table *mesh_table_alloc(int size_order)
3082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
3092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
3102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct mesh_table *newtbl;
3112e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
3132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!newtbl)
3142e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return NULL;
3152e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3162e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
3172e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			(1 << size_order), GFP_KERNEL);
3182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!newtbl->hash_buckets) {
3202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		kfree(newtbl);
3212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return NULL;
3222e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
3232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3242e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
3252e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			(1 << size_order), GFP_KERNEL);
3262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!newtbl->hashwlock) {
3272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		kfree(newtbl->hash_buckets);
3282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		kfree(newtbl);
3292e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return NULL;
3302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
3312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->size_order = size_order;
3332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->hash_mask = (1 << size_order) - 1;
3342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	atomic_set(&newtbl->entries,  0);
3352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	get_random_bytes(&newtbl->hash_rnd,
3362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			sizeof(newtbl->hash_rnd));
3372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i <= newtbl->hash_mask; i++)
3382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		spin_lock_init(&newtbl->hashwlock[i]);
3392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return newtbl;
3412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
3422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3442e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic void ieee80211_mesh_path_timer(unsigned long data)
3452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
3462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_sub_if_data *sdata =
3472e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		(struct ieee80211_sub_if_data *) data;
348472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
349133b822638ff01eb1e32e1917b197c40ed095dddJohannes Berg	struct ieee80211_local *local = sdata->local;
3502e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3515bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	if (local->quiescing) {
3525bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg		set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
3535bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg		return;
3545bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	}
3555bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
356c03e20fc9a6ec5741d9df561130ecba38ef50eb6Luis R. Rodriguez	ieee80211_queue_work(&local->hw, &ifmsh->work);
3572e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
3582e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
359e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulostatic void ieee80211_mesh_path_root_timer(unsigned long data)
360e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo{
361e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_sub_if_data *sdata =
362e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		(struct ieee80211_sub_if_data *) data;
363e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
364e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_local *local = sdata->local;
365e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
366e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
367e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
368e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	if (local->quiescing) {
369e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
370e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		return;
371e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	}
372e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
373e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	ieee80211_queue_work(&local->hw, &ifmsh->work);
374e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo}
375e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
37663c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulovoid ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
37763c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo{
37863c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	if (ifmsh->mshcfg.dot11MeshHWMPRootMode)
37963c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
38063c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	else {
38163c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
38263c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		/* stop running timer */
38363c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo		del_timer_sync(&ifmsh->mesh_path_root_timer);
38463c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	}
38563c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo}
38663c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo
387902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg/**
3883c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
3893c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @hdr:    	802.11 frame header
3903c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @fc:		frame control field
3913c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @meshda:	destination address in the mesh
3923c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @meshsa:	source address address in the mesh.  Same as TA, as frame is
3933c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *              locally originated.
3943c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *
3953c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * Return the length of the 802.11 (does not include a mesh control header)
3963c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona */
3973c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardonaint ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char
3983c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		*meshda, char *meshsa) {
3993c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	if (is_multicast_ether_addr(meshda)) {
4003c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
4013c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		/* DA TA SA */
4023c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr1, meshda, ETH_ALEN);
4033c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr2, meshsa, ETH_ALEN);
4043c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr3, meshsa, ETH_ALEN);
4053c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		return 24;
4063c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	} else {
4073c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
4083c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona				IEEE80211_FCTL_TODS);
4093c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		/* RA TA DA SA */
4103c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memset(hdr->addr1, 0, ETH_ALEN);   /* RA is resolved later */
4113c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr2, meshsa, ETH_ALEN);
4123c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr3, meshda, ETH_ALEN);
4133c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(hdr->addr4, meshsa, ETH_ALEN);
4143c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		return 30;
4153c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
4163c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona}
4173c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona
4183c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona/**
419902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * ieee80211_new_mesh_header - create a new mesh header
420902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * @meshhdr:    uninitialized mesh header
421902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * @sdata:	mesh interface to be used
4223c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @addr4:	addr4 of the mesh frame (1st in ae header)
4233c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *              may be NULL
4243c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @addr5:	addr5 of the mesh frame (1st or 2nd in ae header)
4253c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona *              may be NULL unless addr6 is present
4263c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * @addr6:	addr6 of the mesh frame (2nd or 3rd in ae header)
4273c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona * 		may be NULL unless addr5 is present
428902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg *
429902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * Return the header length.
430902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg */
431902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Bergint ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
4323c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		struct ieee80211_sub_if_data *sdata, char *addr4,
4333c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		char *addr5, char *addr6)
434902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
4353c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	int aelen = 0;
4363c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	memset(meshhdr, 0, sizeof(meshhdr));
437472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
438472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
439472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	sdata->u.mesh.mesh_seqnum++;
4403c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	if (addr4) {
4413c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		meshhdr->flags |= MESH_FLAGS_AE_A4;
4423c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		aelen += ETH_ALEN;
4433c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		memcpy(meshhdr->eaddr1, addr4, ETH_ALEN);
4443c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
4453c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	if (addr5 && addr6) {
4463c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
4473c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		aelen += 2 * ETH_ALEN;
4483c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		if (!addr4) {
4493c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona			memcpy(meshhdr->eaddr1, addr5, ETH_ALEN);
4503c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona			memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
4513c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		} else {
4523c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona			memcpy(meshhdr->eaddr2, addr5, ETH_ALEN);
4533c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona			memcpy(meshhdr->eaddr3, addr6, ETH_ALEN);
4543c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona		}
4553c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	}
4563c5772a5279de9eadfff7adb5ddea08106495fffJavier Cardona	return 6 + aelen;
457902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg}
458902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg
459472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
460472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg			   struct ieee80211_if_mesh *ifmsh)
461472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
462472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	bool free_plinks;
463472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
464472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
465472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	printk(KERN_DEBUG "%s: running mesh housekeeping\n",
466472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	       sdata->dev->name);
467472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg#endif
468472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
469472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
470472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mesh_path_expire(sdata);
471472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
472472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	free_plinks = mesh_plink_availables(sdata);
473472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (free_plinks != sdata->u.mesh.accepting_plinks)
4742d0ddec5b2b859f06116f631fc0ffe94fbceb556Johannes Berg		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
475472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
476472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mod_timer(&ifmsh->housekeeping_timer,
477472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		  round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
478472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
479472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
480e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulostatic void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
481e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo{
482e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
483e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
484e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	mesh_path_tx_root_frame(sdata);
485e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	mod_timer(&ifmsh->mesh_path_root_timer,
486e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		  round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL));
487e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo}
488e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
4895bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg#ifdef CONFIG_PM
4905bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Bergvoid ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
4915bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg{
4925bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
4935bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
4945bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	/* might restart the timer but that doesn't matter */
4955bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	cancel_work_sync(&ifmsh->work);
4965bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
4975bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	/* use atomic bitops in case both timers fire at the same time */
4985bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
4995bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	if (del_timer_sync(&ifmsh->housekeeping_timer))
5005bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg		set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
5015bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	if (del_timer_sync(&ifmsh->mesh_path_timer))
5025bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg		set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
503e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	if (del_timer_sync(&ifmsh->mesh_path_root_timer))
504e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
5055bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg}
5065bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
5075bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Bergvoid ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
5085bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg{
5095bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
5105bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg
5115bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running))
5125bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg		add_timer(&ifmsh->housekeeping_timer);
5135bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg	if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running))
5145bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg		add_timer(&ifmsh->mesh_path_timer);
515e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running))
516e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		add_timer(&ifmsh->mesh_path_root_timer);
51763c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	ieee80211_mesh_root_setup(ifmsh);
5185bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg}
5195bb644a0fd25a5e083ecbfaa92a211db99aa6ef7Johannes Berg#endif
520472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
521472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
522472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
523472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
524472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
525472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
5266b9ac4425d6ec871faf54540e0f1c5ff420a8f29Rui Paulo	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
52763c5723bc3af8d4e86984dd4ff0c78218de418d0Rui Paulo	ieee80211_mesh_root_setup(ifmsh);
52818889231e4527dfe23145efe318e74744794a95dJavier Cardona	ieee80211_queue_work(&local->hw, &ifmsh->work);
5295b365834255d7c90fc724b032c814dfa297aacf9Javier Cardona	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
5302d0ddec5b2b859f06116f631fc0ffe94fbceb556Johannes Berg	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
5315b365834255d7c90fc724b032c814dfa297aacf9Javier Cardona						BSS_CHANGED_BEACON_ENABLED |
5325b365834255d7c90fc724b032c814dfa297aacf9Javier Cardona						BSS_CHANGED_BEACON_INT);
533472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
534472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
535472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
536472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
537472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
538e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
539472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	/*
540b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * If the timer fired while we waited for it, it will have
541b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * requeued the work. Now the work will be running again
542b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * but will not rearm the timer again because it checks
543b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * whether the interface is running, which, at this point,
544b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 * it no longer is.
545b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	 */
546b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	cancel_work_sync(&sdata->u.mesh.work);
547b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg
548b7413430d4d2a6168e68231d9f93763047b6d60cJohannes Berg	/*
549472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	 * When we get here, the interface is marked down.
550472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	 * Call synchronize_rcu() to wait for the RX path
551472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	 * should it be using the interface and enqueuing
552472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	 * frames at this very time on another CPU.
553472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	 */
5544a27096bbe2cad4c6e78802a0d9dfe0e598a1129Jesper Dangaard Brouer	rcu_barrier(); /* Wait for RX path and call_rcu()'s */
555472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	skb_queue_purge(&sdata->u.mesh.skb_queue);
556472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
557472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
558472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
559472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					u16 stype,
560472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					struct ieee80211_mgmt *mgmt,
561472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					size_t len,
562472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					struct ieee80211_rx_status *rx_status)
563472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
564c6a1fa12d206882757264869f8e32d606b930e2aJohannes Berg	struct ieee80211_local *local = sdata->local;
565472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee802_11_elems elems;
566472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_channel *channel;
567881d948c23442173a011f1adcfe4c95bf7f27515Johannes Berg	u32 supp_rates = 0;
568472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	size_t baselen;
569472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	int freq;
570472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	enum ieee80211_band band = rx_status->band;
571472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
572472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	/* ignore ProbeResp to foreign address */
573472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (stype == IEEE80211_STYPE_PROBE_RESP &&
574472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	    compare_ether_addr(mgmt->da, sdata->dev->dev_addr))
575472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
576472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
577472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
578472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (baselen > len)
579472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
580472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
581472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
582472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg			       &elems);
583472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
584472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (elems.ds_params && elems.ds_params_len == 1)
585472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
586472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	else
587472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		freq = rx_status->freq;
588472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
589472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	channel = ieee80211_get_channel(local->hw.wiphy, freq);
590472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
591472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
592472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
593472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
594472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (elems.mesh_id && elems.mesh_config &&
595472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	    mesh_matches_local(&elems, sdata)) {
596472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		supp_rates = ieee80211_sta_get_rates(local, &elems, band);
597472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
598472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
599472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg				      mesh_peer_accepts_plinks(&elems));
600472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
601472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
602472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
603472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
604472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct ieee80211_mgmt *mgmt,
605472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  size_t len,
606472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct ieee80211_rx_status *rx_status)
607472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
608472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (mgmt->u.action.category) {
6090938393f02c5a4db75a6e38ee31645c974169bb5Rui Paulo	case MESH_PLINK_CATEGORY:
610472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
611472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
612472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case MESH_PATH_SEL_CATEGORY:
613472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		mesh_rx_path_sel_frame(sdata, mgmt, len);
614472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
615472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
616472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
617472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
618472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
619472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					  struct sk_buff *skb)
620472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
621472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_rx_status *rx_status;
622472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh;
623472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_mgmt *mgmt;
624472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	u16 stype;
625472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
626472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh = &sdata->u.mesh;
627472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
628f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg	rx_status = IEEE80211_SKB_RXCB(skb);
629472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mgmt = (struct ieee80211_mgmt *) skb->data;
630472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
631472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
632472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (stype) {
633472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_PROBE_RESP:
634472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_BEACON:
635472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
636472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg					    rx_status);
637472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
638472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_ACTION:
639472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
640472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		break;
641472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
642472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
643472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	kfree_skb(skb);
644472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
645472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
646472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergstatic void ieee80211_mesh_work(struct work_struct *work)
647472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
648472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_sub_if_data *sdata =
649472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		container_of(work, struct ieee80211_sub_if_data, u.mesh.work);
650472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
651472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
652472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct sk_buff *skb;
653472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
654472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (!netif_running(sdata->dev))
655472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
656472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
657fbe9c429f195111bbf7f1630efa19aee295fd8e7Helmut Schaa	if (local->scanning)
658472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return;
659472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
660472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	while ((skb = skb_dequeue(&ifmsh->skb_queue)))
661472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_rx_queued_mgmt(sdata, skb);
662472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
663472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (ifmsh->preq_queue_len &&
664472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	    time_after(jiffies,
665472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		       ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
666472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		mesh_path_start_discovery(sdata);
667472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
66818889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
66918889231e4527dfe23145efe318e74744794a95dJavier Cardona		mesh_mpath_table_grow();
67018889231e4527dfe23145efe318e74744794a95dJavier Cardona
67118889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
67218889231e4527dfe23145efe318e74744794a95dJavier Cardona		mesh_mpp_table_grow();
67318889231e4527dfe23145efe318e74744794a95dJavier Cardona
67418889231e4527dfe23145efe318e74744794a95dJavier Cardona	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
675472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		ieee80211_mesh_housekeeping(sdata, ifmsh);
676e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo
677e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
678e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		ieee80211_mesh_rootpath(sdata);
679472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
680472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
681472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergvoid ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
682472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
683472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_sub_if_data *sdata;
684472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
685472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	rcu_read_lock();
686472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	list_for_each_entry_rcu(sdata, &local->interfaces, list)
687472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		if (ieee80211_vif_is_mesh(&sdata->vif))
688c03e20fc9a6ec5741d9df561130ecba38ef50eb6Luis R. Rodriguez			ieee80211_queue_work(&local->hw, &sdata->u.mesh.work);
689472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	rcu_read_unlock();
690472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
691472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
692902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Bergvoid ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
693902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
694472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
695472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
696472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	INIT_WORK(&ifmsh->work, ieee80211_mesh_work);
697472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	setup_timer(&ifmsh->housekeeping_timer,
698472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		    ieee80211_mesh_housekeeping_timer,
699472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		    (unsigned long) sdata);
700472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	skb_queue_head_init(&sdata->u.mesh.skb_queue);
701472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
702472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
703472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
704472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
705472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
706472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshTTL = MESH_TTL;
707472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.auto_open_plinks = true;
708472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshMaxPeerLinks =
709902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_MAX_ESTAB_PLINKS;
710472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout =
711902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_PATH_TIMEOUT;
712472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval =
713902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_PREQ_MIN_INT;
714472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
715902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_DIAM_TRAVERSAL_TIME;
716472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries =
717902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_MAX_PREQ_RETRIES;
718472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.path_refresh_time =
719902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_PATH_REFRESH_TIME;
720472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->mshcfg.min_discovery_timeout =
721902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_MIN_DISCOVERY_TIMEOUT;
722472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->accepting_plinks = true;
723472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->preq_id = 0;
724d19b3bf6384e66ac6e11a61ee31ed2cfe149f4d8Rui Paulo	ifmsh->sn = 0;
725472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	atomic_set(&ifmsh->mpaths, 0);
726f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	mesh_rmc_init(sdata);
727472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	ifmsh->last_preq = jiffies;
728902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	/* Allocate all mesh structures when creating the first mesh interface. */
729902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	if (!mesh_allocated)
730902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		ieee80211s_init();
731472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mesh_ids_set_default(ifmsh);
732472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	setup_timer(&ifmsh->mesh_path_timer,
733902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    ieee80211_mesh_path_timer,
734902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    (unsigned long) sdata);
735e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo	setup_timer(&ifmsh->mesh_path_root_timer,
736e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		    ieee80211_mesh_path_root_timer,
737e304bfd30f356f7b75d30cad0029ecca705fd590Rui Paulo		    (unsigned long) sdata);
738472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
739472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
740472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg}
741472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
742472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Bergieee80211_rx_result
743f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Bergieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
744472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg{
745472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_local *local = sdata->local;
746472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
747472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	struct ieee80211_mgmt *mgmt;
748472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	u16 fc;
749472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
750472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	if (skb->len < 24)
751472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return RX_DROP_MONITOR;
752472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
753472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	mgmt = (struct ieee80211_mgmt *) skb->data;
754472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	fc = le16_to_cpu(mgmt->frame_control);
755472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
756472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	switch (fc & IEEE80211_FCTL_STYPE) {
757a43816df2a1a61effcb701037bdf63621d066182Johannes Berg	case IEEE80211_STYPE_ACTION:
758a43816df2a1a61effcb701037bdf63621d066182Johannes Berg		if (skb->len < IEEE80211_MIN_ACTION_SIZE)
759a43816df2a1a61effcb701037bdf63621d066182Johannes Berg			return RX_DROP_MONITOR;
760a43816df2a1a61effcb701037bdf63621d066182Johannes Berg		/* fall through */
761472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_PROBE_RESP:
762472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	case IEEE80211_STYPE_BEACON:
763472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		skb_queue_tail(&ifmsh->skb_queue, skb);
764c03e20fc9a6ec5741d9df561130ecba38ef50eb6Luis R. Rodriguez		ieee80211_queue_work(&local->hw, &ifmsh->work);
765472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg		return RX_QUEUED;
766472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	}
767472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg
768472dbc45dc1966284de72d7de15690c17ed2cf33Johannes Berg	return RX_CONTINUE;
769902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg}
770