mesh.c revision f698d856f65c3fea091cc303a135967965c5b880
12e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/*
22e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Copyright (c) 2008 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
15247367016305637fb981db020679520e354c80c4John W. Linville#define PP_OFFSET 	1		/* Path Selection Protocol */
16247367016305637fb981db020679520e354c80c4John W. Linville#define PM_OFFSET	5		/* Path Selection Metric   */
17247367016305637fb981db020679520e354c80c4John W. Linville#define CC_OFFSET	9		/* Congestion Control Mode */
18247367016305637fb981db020679520e354c80c4John W. Linville#define CAPAB_OFFSET 17
192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo#define ACCEPT_PLINKS 0x80
202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Coboint mesh_allocated;
222e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic struct kmem_cache *rm_cache;
232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
242e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid ieee80211s_init(void)
252e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_pathtbl_init();
272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_allocated = 1;
282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
292e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo				     0, 0, NULL);
302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid ieee80211s_stop(void)
332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_pathtbl_unregister();
352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	kmem_cache_destroy(rm_cache);
362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_matches_local - check if the config of a mesh point matches ours
402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @ie: information elements of a management frame from the mesh peer
42f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene * @sdata: local mesh subif
432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
442e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * This function checks if the mesh configuration of a mesh point matches the
452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * local mesh configuration, i.e. if both nodes belong to the same mesh network.
462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
47f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenebool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
482e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
492e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_if_sta *sta = &sdata->u.sta;
502e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
512e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/*
522e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * As support for each feature is added, check for matching
532e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * - On mesh config capabilities
542e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Power Save Support En
552e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support enabled
562e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support active
572e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - Sync support required from peer
582e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 *   - MDA enabled
592e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * - Power management control on fc
602e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 */
613b091cd4941912081730ffa17948da6d148c822dLuis Carlos Cobo	if (sta->mesh_id_len == ie->mesh_id_len &&
623b091cd4941912081730ffa17948da6d148c822dLuis Carlos Cobo		memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
633b091cd4941912081730ffa17948da6d148c822dLuis Carlos Cobo		memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
643b091cd4941912081730ffa17948da6d148c822dLuis Carlos Cobo		memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
653b091cd4941912081730ffa17948da6d148c822dLuis Carlos Cobo		memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
662e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return true;
672e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
682e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return false;
692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links
732e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @ie: information elements of a management frame from the mesh peer
752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
76f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenebool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
772e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0;
792e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
802e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
812e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_accept_plinks_update: update accepting_plink in local mesh beacons
832e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
84d0709a65181beb787ef3f58cfe45536a2bb254c8Johannes Berg * @sdata: mesh interface in which mesh beacons are going to be updated
852e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
86d0709a65181beb787ef3f58cfe45536a2bb254c8Johannes Bergvoid mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
872e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
882e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	bool free_plinks;
892e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
902e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
912e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * the mesh interface might be able to establish plinks with peers that
92b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * are already on the table but are not on PLINK_ESTAB state. However,
93b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * in general the mesh interface is not accepting peer link requests
94b4e08ea141e6d663dec31b31d6289baeaaa2a3a2Luis Carlos Cobo	 * from new peers, and that must be reflected in the beacon
952e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 */
962e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	free_plinks = mesh_plink_availables(sdata);
972e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
982e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (free_plinks != sdata->u.sta.accepting_plinks)
992e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		ieee80211_sta_timer((unsigned long) sdata);
1002e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1012e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid mesh_ids_set_default(struct ieee80211_if_sta *sta)
1032e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1042e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff};
1052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1062e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(sta->mesh_pp_id, def_id, 4);
1072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(sta->mesh_pm_id, def_id, 4);
1082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(sta->mesh_cc_id, def_id, 4);
1092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
111f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greeneint mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
1122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
1142e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1152e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
1162e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!sdata->u.sta.rmc)
1172e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return -ENOMEM;
1182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1;
1192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i < RMC_BUCKETS; i++)
1202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list);
1212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return 0;
1222e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
124f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenevoid mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
1252e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct mesh_rmc *rmc = sdata->u.sta.rmc;
1272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct rmc_entry *p, *n;
1282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
1292e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!sdata->u.sta.rmc)
1312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return;
1322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i < RMC_BUCKETS; i++)
1342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) {
1352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			list_del(&p->list);
1362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			kmem_cache_free(rm_cache, p);
1372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		}
1382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	kfree(rmc);
1402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	sdata->u.sta.rmc = NULL;
1412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo/**
1442e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
1452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
1462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @sa:		source address
1472e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * @mesh_hdr:	mesh_header
1482e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
1492e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Returns: 0 if the frame is not in the cache, nonzero otherwise.
1502e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo *
1512e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * Checks using the source address and the mesh sequence number if we have
1522e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * received this frame lately. If the frame is not in the cache, it is added to
1532e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo * it.
1542e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo */
1552e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Coboint mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
156f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene		   struct ieee80211_sub_if_data *sdata)
1572e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
1582e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct mesh_rmc *rmc = sdata->u.sta.rmc;
1592e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u32 seqnum = 0;
1602e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int entries = 0;
1612e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u8 idx;
1622e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct rmc_entry *p, *n;
1632e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1642e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Don't care about endianness since only match matters */
16551ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
16651ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
1672e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) {
1682e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		++entries;
1692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		if (time_after(jiffies, p->exp_time) ||
1702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo				(entries == RMC_QUEUE_MAX_LEN)) {
1712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			list_del(&p->list);
1722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			kmem_cache_free(rm_cache, p);
1732e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			--entries;
1742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		} else if ((seqnum == p->seqnum)
1752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo				&& (memcmp(sa, p->sa, ETH_ALEN) == 0))
1762e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			return -1;
1772e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
1782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1792e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
1802e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!p) {
1812e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		printk(KERN_DEBUG "o11s: could not allocate RMC entry\n");
1822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return 0;
1832e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
1842e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p->seqnum = seqnum;
1852e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	p->exp_time = jiffies + RMC_TIMEOUT;
1862e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(p->sa, sa, ETH_ALEN);
1872e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	list_add(&p->list, &rmc->bucket[idx].list);
1882e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return 0;
1892e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
1902e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
191f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greenevoid mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
1922e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
193f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	struct ieee80211_local *local = sdata->local;
1942e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_supported_band *sband;
1952e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	u8 *pos;
1962e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int len, i, rate;
1972e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
1982e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
1992e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	len = sband->n_bitrates;
2002e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (len > 8)
2012e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		len = 8;
2022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	pos = skb_put(skb, len + 2);
2032e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = WLAN_EID_SUPP_RATES;
2042e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = len;
2052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i < len; i++) {
2062e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		rate = sband->bitrates[i].bitrate;
2072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		*pos++ = (u8) (rate / 5);
2082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (sband->n_bitrates > len) {
2112e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		pos = skb_put(skb, sband->n_bitrates - len + 2);
2122e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		*pos++ = WLAN_EID_EXT_SUPP_RATES;
2132e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		*pos++ = sband->n_bitrates - len;
2142e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		for (i = len; i < sband->n_bitrates; i++) {
2152e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			rate = sband->bitrates[i].bitrate;
2162e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			*pos++ = (u8) (rate / 5);
2172e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		}
2182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len);
2212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = WLAN_EID_MESH_ID;
2222e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = sdata->u.sta.mesh_id_len;
2232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (sdata->u.sta.mesh_id_len)
2242e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len);
2252e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	pos = skb_put(skb, 21);
2272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = WLAN_EID_MESH_CONFIG;
2282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = MESH_CFG_LEN;
2292e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Version */
2302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = 1;
2312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Active path selection protocol ID */
2332e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(pos, sdata->u.sta.mesh_pp_id, 4);
2342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	pos += 4;
2352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Active path selection metric ID   */
2372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(pos, sdata->u.sta.mesh_pm_id, 4);
2382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	pos += 4;
2392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Congestion control mode identifier */
2412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memcpy(pos, sdata->u.sta.mesh_cc_id, 4);
2422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	pos += 4;
2432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2442e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Channel precedence:
2452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 * Not running simple channel unification protocol
2462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	 */
2472e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	memset(pos, 0x00, 4);
2482e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	pos += 4;
2492e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2502e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Mesh capability */
2512e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata);
2522e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00;
2532e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	*pos++ = 0x00;
2542e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2552e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return;
2562e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2572e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
258f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greeneu32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl)
2592e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
2602e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	/* Use last four bytes of hw addr and interface index as hash index */
261f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd)
2622e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		& tbl->hash_mask;
2632e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2642e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2652e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobou8 mesh_id_hash(u8 *mesh_id, int mesh_id_len)
2662e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
2672e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!mesh_id_len)
2682e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return 1;
2692e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	else if (mesh_id_len == 1)
2702e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return (u8) mesh_id[0];
2712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	else
2722e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return (u8) (mesh_id[0] + 2 * mesh_id[1]);
2732e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
2742e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2752e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostruct mesh_table *mesh_table_alloc(int size_order)
2762e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
2772e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
2782e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct mesh_table *newtbl;
2792e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2802e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
2812e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!newtbl)
2822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return NULL;
2832e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2842e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
2852e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			(1 << size_order), GFP_KERNEL);
2862e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2872e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!newtbl->hash_buckets) {
2882e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		kfree(newtbl);
2892e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return NULL;
2902e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2912e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
2922e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
2932e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			(1 << size_order), GFP_KERNEL);
2942e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (!newtbl->hashwlock) {
2952e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		kfree(newtbl->hash_buckets);
2962e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		kfree(newtbl);
2972e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		return NULL;
2982e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
2992e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3002e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->size_order = size_order;
3012e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->hash_mask = (1 << size_order) - 1;
3022e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	atomic_set(&newtbl->entries,  0);
3032e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	get_random_bytes(&newtbl->hash_rnd,
3042e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			sizeof(newtbl->hash_rnd));
3052e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i <= newtbl->hash_mask; i++)
3062e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		spin_lock_init(&newtbl->hashwlock[i]);
3072e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3082e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	return newtbl;
3092e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
3102e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
311bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanovstatic void __mesh_table_free(struct mesh_table *tbl)
312bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanov{
313bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanov	kfree(tbl->hash_buckets);
314bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanov	kfree(tbl->hashwlock);
315bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanov	kfree(tbl);
316bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanov}
317bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanov
3182e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobovoid mesh_table_free(struct mesh_table *tbl, bool free_leafs)
3192e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
3202e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct hlist_head *mesh_hash;
3212e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct hlist_node *p, *q;
3222e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
3232e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3242e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	mesh_hash = tbl->hash_buckets;
3252e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i <= tbl->hash_mask; i++) {
3262e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		spin_lock(&tbl->hashwlock[i]);
3272e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		hlist_for_each_safe(p, q, &mesh_hash[i]) {
3282e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			tbl->free_node(p, free_leafs);
3292e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo			atomic_dec(&tbl->entries);
3302e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		}
3312e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		spin_unlock(&tbl->hashwlock[i]);
3322e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	}
333bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanov	__mesh_table_free(tbl);
3342e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
3352e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3362e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostatic void ieee80211_mesh_path_timer(unsigned long data)
3372e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
3382e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_sub_if_data *sdata =
3392e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		(struct ieee80211_sub_if_data *) data;
3402e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
3412e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct ieee80211_local *local = wdev_priv(&sdata->wdev);
3422e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3432e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	queue_work(local->hw.workqueue, &ifsta->work);
3442e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
3452e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3462e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobostruct mesh_table *mesh_table_grow(struct mesh_table *tbl)
3472e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo{
3482e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct mesh_table *newtbl;
3492e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	struct hlist_head *oldhash;
3504caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov	struct hlist_node *p, *q;
3512e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	int i;
3522e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3532e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	if (atomic_read(&tbl->entries)
354a3538b19a6d226f9d3d9b18865468370009dec55Pavel Emelyanov			< tbl->mean_chain_len * (tbl->hash_mask + 1))
3552e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		goto endgrow;
3562e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3572e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl = mesh_table_alloc(tbl->size_order + 1);
358a3538b19a6d226f9d3d9b18865468370009dec55Pavel Emelyanov	if (!newtbl)
3592e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		goto endgrow;
3602e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3612e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->free_node = tbl->free_node;
3622e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->mean_chain_len = tbl->mean_chain_len;
3632e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	newtbl->copy_node = tbl->copy_node;
3642e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
3652e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
3662e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	oldhash = tbl->hash_buckets;
3672e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo	for (i = 0; i <= tbl->hash_mask; i++)
3682e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo		hlist_for_each(p, &oldhash[i])
3694caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov			if (tbl->copy_node(p, newtbl) < 0)
3704caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov				goto errcopy;
3712e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo
372a3538b19a6d226f9d3d9b18865468370009dec55Pavel Emelyanov	return newtbl;
3734caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov
3744caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanoverrcopy:
3754caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov	for (i = 0; i <= newtbl->hash_mask; i++) {
3764caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov		hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
3774caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov			tbl->free_node(p, 0);
3784caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov	}
379bd9b448f4c0a514559bdae4ca18ca3e8cd999c6dPavel Emelyanov	__mesh_table_free(tbl);
380a3538b19a6d226f9d3d9b18865468370009dec55Pavel Emelyanovendgrow:
3814caf86c6928cfaca270327bc944f901c2e2a8f50Pavel Emelyanov	return NULL;
3822e3c8736820bf72a8ad10721c7e31d36d4fa7790Luis Carlos Cobo}
383902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg
384902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg/**
385902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * ieee80211_new_mesh_header - create a new mesh header
386902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * @meshhdr:    uninitialized mesh header
387902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * @sdata:	mesh interface to be used
388902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg *
389902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg * Return the header length.
390902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg */
391902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Bergint ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
392902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		struct ieee80211_sub_if_data *sdata)
393902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
394902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	meshhdr->flags = 0;
395902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
39651ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	put_unaligned(cpu_to_le32(sdata->u.sta.mesh_seqnum), &meshhdr->seqnum);
39751ceddade0fb1e15f080b2555f3b3e1d68c6707eLuis Carlos Cobo	sdata->u.sta.mesh_seqnum++;
398902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg
399ef269254772a0d2253c85cafe160e3f6528eb292Luis Carlos Cobo	return 6;
400902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg}
401902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg
402902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Bergvoid ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
403902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg{
404902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
405902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg
406902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
407902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
408902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
409902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
410902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
411902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.auto_open_plinks = true;
412902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshMaxPeerLinks =
413902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_MAX_ESTAB_PLINKS;
414902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
415902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_PATH_TIMEOUT;
416902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
417902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_PREQ_MIN_INT;
418902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
419902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_DIAM_TRAVERSAL_TIME;
420902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
421902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_MAX_PREQ_RETRIES;
422902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.path_refresh_time =
423902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_PATH_REFRESH_TIME;
424902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->mshcfg.min_discovery_timeout =
425902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		MESH_MIN_DISCOVERY_TIMEOUT;
426902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->accepting_plinks = true;
427902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->preq_id = 0;
428902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->dsn = 0;
429902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	atomic_set(&ifsta->mpaths, 0);
430f698d856f65c3fea091cc303a135967965c5b880Jasper Bryant-Greene	mesh_rmc_init(sdata);
431902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	ifsta->last_preq = jiffies;
432902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	/* Allocate all mesh structures when creating the first mesh interface. */
433902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	if (!mesh_allocated)
434902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		ieee80211s_init();
435902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	mesh_ids_set_default(ifsta);
436902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	setup_timer(&ifsta->mesh_path_timer,
437902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    ieee80211_mesh_path_timer,
438902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg		    (unsigned long) sdata);
439902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	INIT_LIST_HEAD(&ifsta->preq_queue.list);
440902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg	spin_lock_init(&ifsta->mesh_preq_queue_lock);
441902acc7896d7649fb30e4b22bd4e643c7f34b02cJohannes Berg}
442