18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (C) 2011-2020  B.A.T.M.A.N. contributors:
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Simon Wunderlich
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "bridge_loop_avoidance.h"
88c2ecf20Sopenharmony_ci#include "main.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/atomic.h>
118c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h>
128c2ecf20Sopenharmony_ci#include <linux/compiler.h>
138c2ecf20Sopenharmony_ci#include <linux/crc16.h>
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
168c2ecf20Sopenharmony_ci#include <linux/gfp.h>
178c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
188c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
198c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
208c2ecf20Sopenharmony_ci#include <linux/jhash.h>
218c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
228c2ecf20Sopenharmony_ci#include <linux/kernel.h>
238c2ecf20Sopenharmony_ci#include <linux/kref.h>
248c2ecf20Sopenharmony_ci#include <linux/list.h>
258c2ecf20Sopenharmony_ci#include <linux/lockdep.h>
268c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
278c2ecf20Sopenharmony_ci#include <linux/netlink.h>
288c2ecf20Sopenharmony_ci#include <linux/preempt.h>
298c2ecf20Sopenharmony_ci#include <linux/rculist.h>
308c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
318c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
328c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
338c2ecf20Sopenharmony_ci#include <linux/slab.h>
348c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
358c2ecf20Sopenharmony_ci#include <linux/stddef.h>
368c2ecf20Sopenharmony_ci#include <linux/string.h>
378c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
388c2ecf20Sopenharmony_ci#include <net/arp.h>
398c2ecf20Sopenharmony_ci#include <net/genetlink.h>
408c2ecf20Sopenharmony_ci#include <net/netlink.h>
418c2ecf20Sopenharmony_ci#include <net/sock.h>
428c2ecf20Sopenharmony_ci#include <uapi/linux/batadv_packet.h>
438c2ecf20Sopenharmony_ci#include <uapi/linux/batman_adv.h>
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#include "hard-interface.h"
468c2ecf20Sopenharmony_ci#include "hash.h"
478c2ecf20Sopenharmony_ci#include "log.h"
488c2ecf20Sopenharmony_ci#include "netlink.h"
498c2ecf20Sopenharmony_ci#include "originator.h"
508c2ecf20Sopenharmony_ci#include "soft-interface.h"
518c2ecf20Sopenharmony_ci#include "translation-table.h"
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic const u8 batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic void batadv_bla_periodic_work(struct work_struct *work);
568c2ecf20Sopenharmony_cistatic void
578c2ecf20Sopenharmony_cibatadv_bla_send_announce(struct batadv_priv *bat_priv,
588c2ecf20Sopenharmony_ci			 struct batadv_bla_backbone_gw *backbone_gw);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/**
618c2ecf20Sopenharmony_ci * batadv_choose_claim() - choose the right bucket for a claim.
628c2ecf20Sopenharmony_ci * @data: data to hash
638c2ecf20Sopenharmony_ci * @size: size of the hash table
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * Return: the hash index of the claim
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistatic inline u32 batadv_choose_claim(const void *data, u32 size)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim = (struct batadv_bla_claim *)data;
708c2ecf20Sopenharmony_ci	u32 hash = 0;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	hash = jhash(&claim->addr, sizeof(claim->addr), hash);
738c2ecf20Sopenharmony_ci	hash = jhash(&claim->vid, sizeof(claim->vid), hash);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return hash % size;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/**
798c2ecf20Sopenharmony_ci * batadv_choose_backbone_gw() - choose the right bucket for a backbone gateway.
808c2ecf20Sopenharmony_ci * @data: data to hash
818c2ecf20Sopenharmony_ci * @size: size of the hash table
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * Return: the hash index of the backbone gateway
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_cistatic inline u32 batadv_choose_backbone_gw(const void *data, u32 size)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	const struct batadv_bla_backbone_gw *gw;
888c2ecf20Sopenharmony_ci	u32 hash = 0;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	gw = (struct batadv_bla_backbone_gw *)data;
918c2ecf20Sopenharmony_ci	hash = jhash(&gw->orig, sizeof(gw->orig), hash);
928c2ecf20Sopenharmony_ci	hash = jhash(&gw->vid, sizeof(gw->vid), hash);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return hash % size;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/**
988c2ecf20Sopenharmony_ci * batadv_compare_backbone_gw() - compare address and vid of two backbone gws
998c2ecf20Sopenharmony_ci * @node: list node of the first entry to compare
1008c2ecf20Sopenharmony_ci * @data2: pointer to the second backbone gateway
1018c2ecf20Sopenharmony_ci *
1028c2ecf20Sopenharmony_ci * Return: true if the backbones have the same data, false otherwise
1038c2ecf20Sopenharmony_ci */
1048c2ecf20Sopenharmony_cistatic bool batadv_compare_backbone_gw(const struct hlist_node *node,
1058c2ecf20Sopenharmony_ci				       const void *data2)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	const void *data1 = container_of(node, struct batadv_bla_backbone_gw,
1088c2ecf20Sopenharmony_ci					 hash_entry);
1098c2ecf20Sopenharmony_ci	const struct batadv_bla_backbone_gw *gw1 = data1;
1108c2ecf20Sopenharmony_ci	const struct batadv_bla_backbone_gw *gw2 = data2;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (!batadv_compare_eth(gw1->orig, gw2->orig))
1138c2ecf20Sopenharmony_ci		return false;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (gw1->vid != gw2->vid)
1168c2ecf20Sopenharmony_ci		return false;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return true;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/**
1228c2ecf20Sopenharmony_ci * batadv_compare_claim() - compare address and vid of two claims
1238c2ecf20Sopenharmony_ci * @node: list node of the first entry to compare
1248c2ecf20Sopenharmony_ci * @data2: pointer to the second claims
1258c2ecf20Sopenharmony_ci *
1268c2ecf20Sopenharmony_ci * Return: true if the claim have the same data, 0 otherwise
1278c2ecf20Sopenharmony_ci */
1288c2ecf20Sopenharmony_cistatic bool batadv_compare_claim(const struct hlist_node *node,
1298c2ecf20Sopenharmony_ci				 const void *data2)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	const void *data1 = container_of(node, struct batadv_bla_claim,
1328c2ecf20Sopenharmony_ci					 hash_entry);
1338c2ecf20Sopenharmony_ci	const struct batadv_bla_claim *cl1 = data1;
1348c2ecf20Sopenharmony_ci	const struct batadv_bla_claim *cl2 = data2;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (!batadv_compare_eth(cl1->addr, cl2->addr))
1378c2ecf20Sopenharmony_ci		return false;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (cl1->vid != cl2->vid)
1408c2ecf20Sopenharmony_ci		return false;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	return true;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/**
1468c2ecf20Sopenharmony_ci * batadv_backbone_gw_release() - release backbone gw from lists and queue for
1478c2ecf20Sopenharmony_ci *  free after rcu grace period
1488c2ecf20Sopenharmony_ci * @ref: kref pointer of the backbone gw
1498c2ecf20Sopenharmony_ci */
1508c2ecf20Sopenharmony_cistatic void batadv_backbone_gw_release(struct kref *ref)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	backbone_gw = container_of(ref, struct batadv_bla_backbone_gw,
1558c2ecf20Sopenharmony_ci				   refcount);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	kfree_rcu(backbone_gw, rcu);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/**
1618c2ecf20Sopenharmony_ci * batadv_backbone_gw_put() - decrement the backbone gw refcounter and possibly
1628c2ecf20Sopenharmony_ci *  release it
1638c2ecf20Sopenharmony_ci * @backbone_gw: backbone gateway to be free'd
1648c2ecf20Sopenharmony_ci */
1658c2ecf20Sopenharmony_cistatic void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	if (!backbone_gw)
1688c2ecf20Sopenharmony_ci		return;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	kref_put(&backbone_gw->refcount, batadv_backbone_gw_release);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/**
1748c2ecf20Sopenharmony_ci * batadv_claim_release() - release claim from lists and queue for free after
1758c2ecf20Sopenharmony_ci *  rcu grace period
1768c2ecf20Sopenharmony_ci * @ref: kref pointer of the claim
1778c2ecf20Sopenharmony_ci */
1788c2ecf20Sopenharmony_cistatic void batadv_claim_release(struct kref *ref)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim;
1818c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *old_backbone_gw;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	claim = container_of(ref, struct batadv_bla_claim, refcount);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	spin_lock_bh(&claim->backbone_lock);
1868c2ecf20Sopenharmony_ci	old_backbone_gw = claim->backbone_gw;
1878c2ecf20Sopenharmony_ci	claim->backbone_gw = NULL;
1888c2ecf20Sopenharmony_ci	spin_unlock_bh(&claim->backbone_lock);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	spin_lock_bh(&old_backbone_gw->crc_lock);
1918c2ecf20Sopenharmony_ci	old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
1928c2ecf20Sopenharmony_ci	spin_unlock_bh(&old_backbone_gw->crc_lock);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(old_backbone_gw);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	kfree_rcu(claim, rcu);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/**
2008c2ecf20Sopenharmony_ci * batadv_claim_put() - decrement the claim refcounter and possibly release it
2018c2ecf20Sopenharmony_ci * @claim: claim to be free'd
2028c2ecf20Sopenharmony_ci */
2038c2ecf20Sopenharmony_cistatic void batadv_claim_put(struct batadv_bla_claim *claim)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	if (!claim)
2068c2ecf20Sopenharmony_ci		return;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	kref_put(&claim->refcount, batadv_claim_release);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci/**
2128c2ecf20Sopenharmony_ci * batadv_claim_hash_find() - looks for a claim in the claim hash
2138c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
2148c2ecf20Sopenharmony_ci * @data: search data (may be local/static data)
2158c2ecf20Sopenharmony_ci *
2168c2ecf20Sopenharmony_ci * Return: claim if found or NULL otherwise.
2178c2ecf20Sopenharmony_ci */
2188c2ecf20Sopenharmony_cistatic struct batadv_bla_claim *
2198c2ecf20Sopenharmony_cibatadv_claim_hash_find(struct batadv_priv *bat_priv,
2208c2ecf20Sopenharmony_ci		       struct batadv_bla_claim *data)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->bla.claim_hash;
2238c2ecf20Sopenharmony_ci	struct hlist_head *head;
2248c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim;
2258c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim_tmp = NULL;
2268c2ecf20Sopenharmony_ci	int index;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (!hash)
2298c2ecf20Sopenharmony_ci		return NULL;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	index = batadv_choose_claim(data, hash->size);
2328c2ecf20Sopenharmony_ci	head = &hash->table[index];
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	rcu_read_lock();
2358c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(claim, head, hash_entry) {
2368c2ecf20Sopenharmony_ci		if (!batadv_compare_claim(&claim->hash_entry, data))
2378c2ecf20Sopenharmony_ci			continue;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&claim->refcount))
2408c2ecf20Sopenharmony_ci			continue;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		claim_tmp = claim;
2438c2ecf20Sopenharmony_ci		break;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	rcu_read_unlock();
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return claim_tmp;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/**
2518c2ecf20Sopenharmony_ci * batadv_backbone_hash_find() - looks for a backbone gateway in the hash
2528c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
2538c2ecf20Sopenharmony_ci * @addr: the address of the originator
2548c2ecf20Sopenharmony_ci * @vid: the VLAN ID
2558c2ecf20Sopenharmony_ci *
2568c2ecf20Sopenharmony_ci * Return: backbone gateway if found or NULL otherwise
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_cistatic struct batadv_bla_backbone_gw *
2598c2ecf20Sopenharmony_cibatadv_backbone_hash_find(struct batadv_priv *bat_priv, u8 *addr,
2608c2ecf20Sopenharmony_ci			  unsigned short vid)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
2638c2ecf20Sopenharmony_ci	struct hlist_head *head;
2648c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw search_entry, *backbone_gw;
2658c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw_tmp = NULL;
2668c2ecf20Sopenharmony_ci	int index;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (!hash)
2698c2ecf20Sopenharmony_ci		return NULL;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	ether_addr_copy(search_entry.orig, addr);
2728c2ecf20Sopenharmony_ci	search_entry.vid = vid;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	index = batadv_choose_backbone_gw(&search_entry, hash->size);
2758c2ecf20Sopenharmony_ci	head = &hash->table[index];
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	rcu_read_lock();
2788c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
2798c2ecf20Sopenharmony_ci		if (!batadv_compare_backbone_gw(&backbone_gw->hash_entry,
2808c2ecf20Sopenharmony_ci						&search_entry))
2818c2ecf20Sopenharmony_ci			continue;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&backbone_gw->refcount))
2848c2ecf20Sopenharmony_ci			continue;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		backbone_gw_tmp = backbone_gw;
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	rcu_read_unlock();
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return backbone_gw_tmp;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/**
2958c2ecf20Sopenharmony_ci * batadv_bla_del_backbone_claims() - delete all claims for a backbone
2968c2ecf20Sopenharmony_ci * @backbone_gw: backbone gateway where the claims should be removed
2978c2ecf20Sopenharmony_ci */
2988c2ecf20Sopenharmony_cistatic void
2998c2ecf20Sopenharmony_cibatadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
3028c2ecf20Sopenharmony_ci	struct hlist_node *node_tmp;
3038c2ecf20Sopenharmony_ci	struct hlist_head *head;
3048c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim;
3058c2ecf20Sopenharmony_ci	int i;
3068c2ecf20Sopenharmony_ci	spinlock_t *list_lock;	/* protects write access to the hash lists */
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	hash = backbone_gw->bat_priv->bla.claim_hash;
3098c2ecf20Sopenharmony_ci	if (!hash)
3108c2ecf20Sopenharmony_ci		return;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
3138c2ecf20Sopenharmony_ci		head = &hash->table[i];
3148c2ecf20Sopenharmony_ci		list_lock = &hash->list_locks[i];
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		spin_lock_bh(list_lock);
3178c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(claim, node_tmp,
3188c2ecf20Sopenharmony_ci					  head, hash_entry) {
3198c2ecf20Sopenharmony_ci			if (claim->backbone_gw != backbone_gw)
3208c2ecf20Sopenharmony_ci				continue;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci			batadv_claim_put(claim);
3238c2ecf20Sopenharmony_ci			hlist_del_rcu(&claim->hash_entry);
3248c2ecf20Sopenharmony_ci		}
3258c2ecf20Sopenharmony_ci		spin_unlock_bh(list_lock);
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* all claims gone, initialize CRC */
3298c2ecf20Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
3308c2ecf20Sopenharmony_ci	backbone_gw->crc = BATADV_BLA_CRC_INIT;
3318c2ecf20Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci/**
3358c2ecf20Sopenharmony_ci * batadv_bla_send_claim() - sends a claim frame according to the provided info
3368c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
3378c2ecf20Sopenharmony_ci * @mac: the mac address to be announced within the claim
3388c2ecf20Sopenharmony_ci * @vid: the VLAN ID
3398c2ecf20Sopenharmony_ci * @claimtype: the type of the claim (CLAIM, UNCLAIM, ANNOUNCE, ...)
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_cistatic void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac,
3428c2ecf20Sopenharmony_ci				  unsigned short vid, int claimtype)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3458c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr;
3468c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
3478c2ecf20Sopenharmony_ci	struct net_device *soft_iface;
3488c2ecf20Sopenharmony_ci	u8 *hw_src;
3498c2ecf20Sopenharmony_ci	struct batadv_bla_claim_dst local_claim_dest;
3508c2ecf20Sopenharmony_ci	__be32 zeroip = 0;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
3538c2ecf20Sopenharmony_ci	if (!primary_if)
3548c2ecf20Sopenharmony_ci		return;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	memcpy(&local_claim_dest, &bat_priv->bla.claim_dest,
3578c2ecf20Sopenharmony_ci	       sizeof(local_claim_dest));
3588c2ecf20Sopenharmony_ci	local_claim_dest.type = claimtype;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	soft_iface = primary_if->soft_iface;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
3638c2ecf20Sopenharmony_ci			 /* IP DST: 0.0.0.0 */
3648c2ecf20Sopenharmony_ci			 zeroip,
3658c2ecf20Sopenharmony_ci			 primary_if->soft_iface,
3668c2ecf20Sopenharmony_ci			 /* IP SRC: 0.0.0.0 */
3678c2ecf20Sopenharmony_ci			 zeroip,
3688c2ecf20Sopenharmony_ci			 /* Ethernet DST: Broadcast */
3698c2ecf20Sopenharmony_ci			 NULL,
3708c2ecf20Sopenharmony_ci			 /* Ethernet SRC/HW SRC:  originator mac */
3718c2ecf20Sopenharmony_ci			 primary_if->net_dev->dev_addr,
3728c2ecf20Sopenharmony_ci			 /* HW DST: FF:43:05:XX:YY:YY
3738c2ecf20Sopenharmony_ci			  * with XX   = claim type
3748c2ecf20Sopenharmony_ci			  * and YY:YY = group id
3758c2ecf20Sopenharmony_ci			  */
3768c2ecf20Sopenharmony_ci			 (u8 *)&local_claim_dest);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (!skb)
3798c2ecf20Sopenharmony_ci		goto out;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	ethhdr = (struct ethhdr *)skb->data;
3828c2ecf20Sopenharmony_ci	hw_src = (u8 *)ethhdr + ETH_HLEN + sizeof(struct arphdr);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/* now we pretend that the client would have sent this ... */
3858c2ecf20Sopenharmony_ci	switch (claimtype) {
3868c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_CLAIM:
3878c2ecf20Sopenharmony_ci		/* normal claim frame
3888c2ecf20Sopenharmony_ci		 * set Ethernet SRC to the clients mac
3898c2ecf20Sopenharmony_ci		 */
3908c2ecf20Sopenharmony_ci		ether_addr_copy(ethhdr->h_source, mac);
3918c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
3928c2ecf20Sopenharmony_ci			   "%s(): CLAIM %pM on vid %d\n", __func__, mac,
3938c2ecf20Sopenharmony_ci			   batadv_print_vid(vid));
3948c2ecf20Sopenharmony_ci		break;
3958c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_UNCLAIM:
3968c2ecf20Sopenharmony_ci		/* unclaim frame
3978c2ecf20Sopenharmony_ci		 * set HW SRC to the clients mac
3988c2ecf20Sopenharmony_ci		 */
3998c2ecf20Sopenharmony_ci		ether_addr_copy(hw_src, mac);
4008c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
4018c2ecf20Sopenharmony_ci			   "%s(): UNCLAIM %pM on vid %d\n", __func__, mac,
4028c2ecf20Sopenharmony_ci			   batadv_print_vid(vid));
4038c2ecf20Sopenharmony_ci		break;
4048c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_ANNOUNCE:
4058c2ecf20Sopenharmony_ci		/* announcement frame
4068c2ecf20Sopenharmony_ci		 * set HW SRC to the special mac containg the crc
4078c2ecf20Sopenharmony_ci		 */
4088c2ecf20Sopenharmony_ci		ether_addr_copy(hw_src, mac);
4098c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
4108c2ecf20Sopenharmony_ci			   "%s(): ANNOUNCE of %pM on vid %d\n", __func__,
4118c2ecf20Sopenharmony_ci			   ethhdr->h_source, batadv_print_vid(vid));
4128c2ecf20Sopenharmony_ci		break;
4138c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_REQUEST:
4148c2ecf20Sopenharmony_ci		/* request frame
4158c2ecf20Sopenharmony_ci		 * set HW SRC and header destination to the receiving backbone
4168c2ecf20Sopenharmony_ci		 * gws mac
4178c2ecf20Sopenharmony_ci		 */
4188c2ecf20Sopenharmony_ci		ether_addr_copy(hw_src, mac);
4198c2ecf20Sopenharmony_ci		ether_addr_copy(ethhdr->h_dest, mac);
4208c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
4218c2ecf20Sopenharmony_ci			   "%s(): REQUEST of %pM to %pM on vid %d\n", __func__,
4228c2ecf20Sopenharmony_ci			   ethhdr->h_source, ethhdr->h_dest,
4238c2ecf20Sopenharmony_ci			   batadv_print_vid(vid));
4248c2ecf20Sopenharmony_ci		break;
4258c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_LOOPDETECT:
4268c2ecf20Sopenharmony_ci		ether_addr_copy(ethhdr->h_source, mac);
4278c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
4288c2ecf20Sopenharmony_ci			   "%s(): LOOPDETECT of %pM to %pM on vid %d\n",
4298c2ecf20Sopenharmony_ci			   __func__, ethhdr->h_source, ethhdr->h_dest,
4308c2ecf20Sopenharmony_ci			   batadv_print_vid(vid));
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		break;
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (vid & BATADV_VLAN_HAS_TAG) {
4368c2ecf20Sopenharmony_ci		skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),
4378c2ecf20Sopenharmony_ci				      vid & VLAN_VID_MASK);
4388c2ecf20Sopenharmony_ci		if (!skb)
4398c2ecf20Sopenharmony_ci			goto out;
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	skb_reset_mac_header(skb);
4438c2ecf20Sopenharmony_ci	skb->protocol = eth_type_trans(skb, soft_iface);
4448c2ecf20Sopenharmony_ci	batadv_inc_counter(bat_priv, BATADV_CNT_RX);
4458c2ecf20Sopenharmony_ci	batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
4468c2ecf20Sopenharmony_ci			   skb->len + ETH_HLEN);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (in_interrupt())
4498c2ecf20Sopenharmony_ci		netif_rx(skb);
4508c2ecf20Sopenharmony_ci	else
4518c2ecf20Sopenharmony_ci		netif_rx_ni(skb);
4528c2ecf20Sopenharmony_ciout:
4538c2ecf20Sopenharmony_ci	if (primary_if)
4548c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci/**
4588c2ecf20Sopenharmony_ci * batadv_bla_loopdetect_report() - worker for reporting the loop
4598c2ecf20Sopenharmony_ci * @work: work queue item
4608c2ecf20Sopenharmony_ci *
4618c2ecf20Sopenharmony_ci * Throws an uevent, as the loopdetect check function can't do that itself
4628c2ecf20Sopenharmony_ci * since the kernel may sleep while throwing uevents.
4638c2ecf20Sopenharmony_ci */
4648c2ecf20Sopenharmony_cistatic void batadv_bla_loopdetect_report(struct work_struct *work)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
4678c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
4688c2ecf20Sopenharmony_ci	char vid_str[6] = { '\0' };
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	backbone_gw = container_of(work, struct batadv_bla_backbone_gw,
4718c2ecf20Sopenharmony_ci				   report_work);
4728c2ecf20Sopenharmony_ci	bat_priv = backbone_gw->bat_priv;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	batadv_info(bat_priv->soft_iface,
4758c2ecf20Sopenharmony_ci		    "Possible loop on VLAN %d detected which can't be handled by BLA - please check your network setup!\n",
4768c2ecf20Sopenharmony_ci		    batadv_print_vid(backbone_gw->vid));
4778c2ecf20Sopenharmony_ci	snprintf(vid_str, sizeof(vid_str), "%d",
4788c2ecf20Sopenharmony_ci		 batadv_print_vid(backbone_gw->vid));
4798c2ecf20Sopenharmony_ci	vid_str[sizeof(vid_str) - 1] = 0;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	batadv_throw_uevent(bat_priv, BATADV_UEV_BLA, BATADV_UEV_LOOPDETECT,
4828c2ecf20Sopenharmony_ci			    vid_str);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci/**
4888c2ecf20Sopenharmony_ci * batadv_bla_get_backbone_gw() - finds or creates a backbone gateway
4898c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
4908c2ecf20Sopenharmony_ci * @orig: the mac address of the originator
4918c2ecf20Sopenharmony_ci * @vid: the VLAN ID
4928c2ecf20Sopenharmony_ci * @own_backbone: set if the requested backbone is local
4938c2ecf20Sopenharmony_ci *
4948c2ecf20Sopenharmony_ci * Return: the (possibly created) backbone gateway or NULL on error
4958c2ecf20Sopenharmony_ci */
4968c2ecf20Sopenharmony_cistatic struct batadv_bla_backbone_gw *
4978c2ecf20Sopenharmony_cibatadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, u8 *orig,
4988c2ecf20Sopenharmony_ci			   unsigned short vid, bool own_backbone)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *entry;
5018c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
5028c2ecf20Sopenharmony_ci	int hash_added;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	entry = batadv_backbone_hash_find(bat_priv, orig, vid);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (entry)
5078c2ecf20Sopenharmony_ci		return entry;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
5108c2ecf20Sopenharmony_ci		   "%s(): not found (%pM, %d), creating new entry\n", __func__,
5118c2ecf20Sopenharmony_ci		   orig, batadv_print_vid(vid));
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
5148c2ecf20Sopenharmony_ci	if (!entry)
5158c2ecf20Sopenharmony_ci		return NULL;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	entry->vid = vid;
5188c2ecf20Sopenharmony_ci	entry->lasttime = jiffies;
5198c2ecf20Sopenharmony_ci	entry->crc = BATADV_BLA_CRC_INIT;
5208c2ecf20Sopenharmony_ci	entry->bat_priv = bat_priv;
5218c2ecf20Sopenharmony_ci	spin_lock_init(&entry->crc_lock);
5228c2ecf20Sopenharmony_ci	atomic_set(&entry->request_sent, 0);
5238c2ecf20Sopenharmony_ci	atomic_set(&entry->wait_periods, 0);
5248c2ecf20Sopenharmony_ci	ether_addr_copy(entry->orig, orig);
5258c2ecf20Sopenharmony_ci	INIT_WORK(&entry->report_work, batadv_bla_loopdetect_report);
5268c2ecf20Sopenharmony_ci	kref_init(&entry->refcount);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	kref_get(&entry->refcount);
5298c2ecf20Sopenharmony_ci	hash_added = batadv_hash_add(bat_priv->bla.backbone_hash,
5308c2ecf20Sopenharmony_ci				     batadv_compare_backbone_gw,
5318c2ecf20Sopenharmony_ci				     batadv_choose_backbone_gw, entry,
5328c2ecf20Sopenharmony_ci				     &entry->hash_entry);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (unlikely(hash_added != 0)) {
5358c2ecf20Sopenharmony_ci		/* hash failed, free the structure */
5368c2ecf20Sopenharmony_ci		kfree(entry);
5378c2ecf20Sopenharmony_ci		return NULL;
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	/* this is a gateway now, remove any TT entry on this VLAN */
5418c2ecf20Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, orig);
5428c2ecf20Sopenharmony_ci	if (orig_node) {
5438c2ecf20Sopenharmony_ci		batadv_tt_global_del_orig(bat_priv, orig_node, vid,
5448c2ecf20Sopenharmony_ci					  "became a backbone gateway");
5458c2ecf20Sopenharmony_ci		batadv_orig_node_put(orig_node);
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (own_backbone) {
5498c2ecf20Sopenharmony_ci		batadv_bla_send_announce(bat_priv, entry);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		/* this will be decreased in the worker thread */
5528c2ecf20Sopenharmony_ci		atomic_inc(&entry->request_sent);
5538c2ecf20Sopenharmony_ci		atomic_set(&entry->wait_periods, BATADV_BLA_WAIT_PERIODS);
5548c2ecf20Sopenharmony_ci		atomic_inc(&bat_priv->bla.num_requests);
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return entry;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci/**
5618c2ecf20Sopenharmony_ci * batadv_bla_update_own_backbone_gw() - updates the own backbone gw for a VLAN
5628c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
5638c2ecf20Sopenharmony_ci * @primary_if: the selected primary interface
5648c2ecf20Sopenharmony_ci * @vid: VLAN identifier
5658c2ecf20Sopenharmony_ci *
5668c2ecf20Sopenharmony_ci * update or add the own backbone gw to make sure we announce
5678c2ecf20Sopenharmony_ci * where we receive other backbone gws
5688c2ecf20Sopenharmony_ci */
5698c2ecf20Sopenharmony_cistatic void
5708c2ecf20Sopenharmony_cibatadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv,
5718c2ecf20Sopenharmony_ci				  struct batadv_hard_iface *primary_if,
5728c2ecf20Sopenharmony_ci				  unsigned short vid)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	backbone_gw = batadv_bla_get_backbone_gw(bat_priv,
5778c2ecf20Sopenharmony_ci						 primary_if->net_dev->dev_addr,
5788c2ecf20Sopenharmony_ci						 vid, true);
5798c2ecf20Sopenharmony_ci	if (unlikely(!backbone_gw))
5808c2ecf20Sopenharmony_ci		return;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	backbone_gw->lasttime = jiffies;
5838c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci/**
5878c2ecf20Sopenharmony_ci * batadv_bla_answer_request() - answer a bla request by sending own claims
5888c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
5898c2ecf20Sopenharmony_ci * @primary_if: interface where the request came on
5908c2ecf20Sopenharmony_ci * @vid: the vid where the request came on
5918c2ecf20Sopenharmony_ci *
5928c2ecf20Sopenharmony_ci * Repeat all of our own claims, and finally send an ANNOUNCE frame
5938c2ecf20Sopenharmony_ci * to allow the requester another check if the CRC is correct now.
5948c2ecf20Sopenharmony_ci */
5958c2ecf20Sopenharmony_cistatic void batadv_bla_answer_request(struct batadv_priv *bat_priv,
5968c2ecf20Sopenharmony_ci				      struct batadv_hard_iface *primary_if,
5978c2ecf20Sopenharmony_ci				      unsigned short vid)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	struct hlist_head *head;
6008c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
6018c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim;
6028c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
6038c2ecf20Sopenharmony_ci	int i;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
6068c2ecf20Sopenharmony_ci		   "%s(): received a claim request, send all of our own claims again\n",
6078c2ecf20Sopenharmony_ci		   __func__);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	backbone_gw = batadv_backbone_hash_find(bat_priv,
6108c2ecf20Sopenharmony_ci						primary_if->net_dev->dev_addr,
6118c2ecf20Sopenharmony_ci						vid);
6128c2ecf20Sopenharmony_ci	if (!backbone_gw)
6138c2ecf20Sopenharmony_ci		return;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	hash = bat_priv->bla.claim_hash;
6168c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
6178c2ecf20Sopenharmony_ci		head = &hash->table[i];
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		rcu_read_lock();
6208c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(claim, head, hash_entry) {
6218c2ecf20Sopenharmony_ci			/* only own claims are interesting */
6228c2ecf20Sopenharmony_ci			if (claim->backbone_gw != backbone_gw)
6238c2ecf20Sopenharmony_ci				continue;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci			batadv_bla_send_claim(bat_priv, claim->addr, claim->vid,
6268c2ecf20Sopenharmony_ci					      BATADV_CLAIM_TYPE_CLAIM);
6278c2ecf20Sopenharmony_ci		}
6288c2ecf20Sopenharmony_ci		rcu_read_unlock();
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	/* finally, send an announcement frame */
6328c2ecf20Sopenharmony_ci	batadv_bla_send_announce(bat_priv, backbone_gw);
6338c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci/**
6378c2ecf20Sopenharmony_ci * batadv_bla_send_request() - send a request to repeat claims
6388c2ecf20Sopenharmony_ci * @backbone_gw: the backbone gateway from whom we are out of sync
6398c2ecf20Sopenharmony_ci *
6408c2ecf20Sopenharmony_ci * When the crc is wrong, ask the backbone gateway for a full table update.
6418c2ecf20Sopenharmony_ci * After the request, it will repeat all of his own claims and finally
6428c2ecf20Sopenharmony_ci * send an announcement claim with which we can check again.
6438c2ecf20Sopenharmony_ci */
6448c2ecf20Sopenharmony_cistatic void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	/* first, remove all old entries */
6478c2ecf20Sopenharmony_ci	batadv_bla_del_backbone_claims(backbone_gw);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
6508c2ecf20Sopenharmony_ci		   "Sending REQUEST to %pM\n", backbone_gw->orig);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	/* send request */
6538c2ecf20Sopenharmony_ci	batadv_bla_send_claim(backbone_gw->bat_priv, backbone_gw->orig,
6548c2ecf20Sopenharmony_ci			      backbone_gw->vid, BATADV_CLAIM_TYPE_REQUEST);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/* no local broadcasts should be sent or received, for now. */
6578c2ecf20Sopenharmony_ci	if (!atomic_read(&backbone_gw->request_sent)) {
6588c2ecf20Sopenharmony_ci		atomic_inc(&backbone_gw->bat_priv->bla.num_requests);
6598c2ecf20Sopenharmony_ci		atomic_set(&backbone_gw->request_sent, 1);
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci/**
6648c2ecf20Sopenharmony_ci * batadv_bla_send_announce() - Send an announcement frame
6658c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
6668c2ecf20Sopenharmony_ci * @backbone_gw: our backbone gateway which should be announced
6678c2ecf20Sopenharmony_ci */
6688c2ecf20Sopenharmony_cistatic void batadv_bla_send_announce(struct batadv_priv *bat_priv,
6698c2ecf20Sopenharmony_ci				     struct batadv_bla_backbone_gw *backbone_gw)
6708c2ecf20Sopenharmony_ci{
6718c2ecf20Sopenharmony_ci	u8 mac[ETH_ALEN];
6728c2ecf20Sopenharmony_ci	__be16 crc;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	memcpy(mac, batadv_announce_mac, 4);
6758c2ecf20Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
6768c2ecf20Sopenharmony_ci	crc = htons(backbone_gw->crc);
6778c2ecf20Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
6788c2ecf20Sopenharmony_ci	memcpy(&mac[4], &crc, 2);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	batadv_bla_send_claim(bat_priv, mac, backbone_gw->vid,
6818c2ecf20Sopenharmony_ci			      BATADV_CLAIM_TYPE_ANNOUNCE);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci/**
6858c2ecf20Sopenharmony_ci * batadv_bla_add_claim() - Adds a claim in the claim hash
6868c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
6878c2ecf20Sopenharmony_ci * @mac: the mac address of the claim
6888c2ecf20Sopenharmony_ci * @vid: the VLAN ID of the frame
6898c2ecf20Sopenharmony_ci * @backbone_gw: the backbone gateway which claims it
6908c2ecf20Sopenharmony_ci */
6918c2ecf20Sopenharmony_cistatic void batadv_bla_add_claim(struct batadv_priv *bat_priv,
6928c2ecf20Sopenharmony_ci				 const u8 *mac, const unsigned short vid,
6938c2ecf20Sopenharmony_ci				 struct batadv_bla_backbone_gw *backbone_gw)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *old_backbone_gw;
6968c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim;
6978c2ecf20Sopenharmony_ci	struct batadv_bla_claim search_claim;
6988c2ecf20Sopenharmony_ci	bool remove_crc = false;
6998c2ecf20Sopenharmony_ci	int hash_added;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	ether_addr_copy(search_claim.addr, mac);
7028c2ecf20Sopenharmony_ci	search_claim.vid = vid;
7038c2ecf20Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	/* create a new claim entry if it does not exist yet. */
7068c2ecf20Sopenharmony_ci	if (!claim) {
7078c2ecf20Sopenharmony_ci		claim = kzalloc(sizeof(*claim), GFP_ATOMIC);
7088c2ecf20Sopenharmony_ci		if (!claim)
7098c2ecf20Sopenharmony_ci			return;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci		ether_addr_copy(claim->addr, mac);
7128c2ecf20Sopenharmony_ci		spin_lock_init(&claim->backbone_lock);
7138c2ecf20Sopenharmony_ci		claim->vid = vid;
7148c2ecf20Sopenharmony_ci		claim->lasttime = jiffies;
7158c2ecf20Sopenharmony_ci		kref_get(&backbone_gw->refcount);
7168c2ecf20Sopenharmony_ci		claim->backbone_gw = backbone_gw;
7178c2ecf20Sopenharmony_ci		kref_init(&claim->refcount);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
7208c2ecf20Sopenharmony_ci			   "%s(): adding new entry %pM, vid %d to hash ...\n",
7218c2ecf20Sopenharmony_ci			   __func__, mac, batadv_print_vid(vid));
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci		kref_get(&claim->refcount);
7248c2ecf20Sopenharmony_ci		hash_added = batadv_hash_add(bat_priv->bla.claim_hash,
7258c2ecf20Sopenharmony_ci					     batadv_compare_claim,
7268c2ecf20Sopenharmony_ci					     batadv_choose_claim, claim,
7278c2ecf20Sopenharmony_ci					     &claim->hash_entry);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci		if (unlikely(hash_added != 0)) {
7308c2ecf20Sopenharmony_ci			/* only local changes happened. */
7318c2ecf20Sopenharmony_ci			kfree(claim);
7328c2ecf20Sopenharmony_ci			return;
7338c2ecf20Sopenharmony_ci		}
7348c2ecf20Sopenharmony_ci	} else {
7358c2ecf20Sopenharmony_ci		claim->lasttime = jiffies;
7368c2ecf20Sopenharmony_ci		if (claim->backbone_gw == backbone_gw)
7378c2ecf20Sopenharmony_ci			/* no need to register a new backbone */
7388c2ecf20Sopenharmony_ci			goto claim_free_ref;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
7418c2ecf20Sopenharmony_ci			   "%s(): changing ownership for %pM, vid %d to gw %pM\n",
7428c2ecf20Sopenharmony_ci			   __func__, mac, batadv_print_vid(vid),
7438c2ecf20Sopenharmony_ci			   backbone_gw->orig);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		remove_crc = true;
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* replace backbone_gw atomically and adjust reference counters */
7498c2ecf20Sopenharmony_ci	spin_lock_bh(&claim->backbone_lock);
7508c2ecf20Sopenharmony_ci	old_backbone_gw = claim->backbone_gw;
7518c2ecf20Sopenharmony_ci	kref_get(&backbone_gw->refcount);
7528c2ecf20Sopenharmony_ci	claim->backbone_gw = backbone_gw;
7538c2ecf20Sopenharmony_ci	spin_unlock_bh(&claim->backbone_lock);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	if (remove_crc) {
7568c2ecf20Sopenharmony_ci		/* remove claim address from old backbone_gw */
7578c2ecf20Sopenharmony_ci		spin_lock_bh(&old_backbone_gw->crc_lock);
7588c2ecf20Sopenharmony_ci		old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
7598c2ecf20Sopenharmony_ci		spin_unlock_bh(&old_backbone_gw->crc_lock);
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(old_backbone_gw);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	/* add claim address to new backbone_gw */
7658c2ecf20Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
7668c2ecf20Sopenharmony_ci	backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
7678c2ecf20Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
7688c2ecf20Sopenharmony_ci	backbone_gw->lasttime = jiffies;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ciclaim_free_ref:
7718c2ecf20Sopenharmony_ci	batadv_claim_put(claim);
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci/**
7758c2ecf20Sopenharmony_ci * batadv_bla_claim_get_backbone_gw() - Get valid reference for backbone_gw of
7768c2ecf20Sopenharmony_ci *  claim
7778c2ecf20Sopenharmony_ci * @claim: claim whose backbone_gw should be returned
7788c2ecf20Sopenharmony_ci *
7798c2ecf20Sopenharmony_ci * Return: valid reference to claim::backbone_gw
7808c2ecf20Sopenharmony_ci */
7818c2ecf20Sopenharmony_cistatic struct batadv_bla_backbone_gw *
7828c2ecf20Sopenharmony_cibatadv_bla_claim_get_backbone_gw(struct batadv_bla_claim *claim)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	spin_lock_bh(&claim->backbone_lock);
7878c2ecf20Sopenharmony_ci	backbone_gw = claim->backbone_gw;
7888c2ecf20Sopenharmony_ci	kref_get(&backbone_gw->refcount);
7898c2ecf20Sopenharmony_ci	spin_unlock_bh(&claim->backbone_lock);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	return backbone_gw;
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci/**
7958c2ecf20Sopenharmony_ci * batadv_bla_del_claim() - delete a claim from the claim hash
7968c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
7978c2ecf20Sopenharmony_ci * @mac: mac address of the claim to be removed
7988c2ecf20Sopenharmony_ci * @vid: VLAN id for the claim to be removed
7998c2ecf20Sopenharmony_ci */
8008c2ecf20Sopenharmony_cistatic void batadv_bla_del_claim(struct batadv_priv *bat_priv,
8018c2ecf20Sopenharmony_ci				 const u8 *mac, const unsigned short vid)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	struct batadv_bla_claim search_claim, *claim;
8048c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim_removed_entry;
8058c2ecf20Sopenharmony_ci	struct hlist_node *claim_removed_node;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	ether_addr_copy(search_claim.addr, mac);
8088c2ecf20Sopenharmony_ci	search_claim.vid = vid;
8098c2ecf20Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
8108c2ecf20Sopenharmony_ci	if (!claim)
8118c2ecf20Sopenharmony_ci		return;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): %pM, vid %d\n", __func__,
8148c2ecf20Sopenharmony_ci		   mac, batadv_print_vid(vid));
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	claim_removed_node = batadv_hash_remove(bat_priv->bla.claim_hash,
8178c2ecf20Sopenharmony_ci						batadv_compare_claim,
8188c2ecf20Sopenharmony_ci						batadv_choose_claim, claim);
8198c2ecf20Sopenharmony_ci	if (!claim_removed_node)
8208c2ecf20Sopenharmony_ci		goto free_claim;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	/* reference from the hash is gone */
8238c2ecf20Sopenharmony_ci	claim_removed_entry = hlist_entry(claim_removed_node,
8248c2ecf20Sopenharmony_ci					  struct batadv_bla_claim, hash_entry);
8258c2ecf20Sopenharmony_ci	batadv_claim_put(claim_removed_entry);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cifree_claim:
8288c2ecf20Sopenharmony_ci	/* don't need the reference from hash_find() anymore */
8298c2ecf20Sopenharmony_ci	batadv_claim_put(claim);
8308c2ecf20Sopenharmony_ci}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci/**
8338c2ecf20Sopenharmony_ci * batadv_handle_announce() - check for ANNOUNCE frame
8348c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
8358c2ecf20Sopenharmony_ci * @an_addr: announcement mac address (ARP Sender HW address)
8368c2ecf20Sopenharmony_ci * @backbone_addr: originator address of the sender (Ethernet source MAC)
8378c2ecf20Sopenharmony_ci * @vid: the VLAN ID of the frame
8388c2ecf20Sopenharmony_ci *
8398c2ecf20Sopenharmony_ci * Return: true if handled
8408c2ecf20Sopenharmony_ci */
8418c2ecf20Sopenharmony_cistatic bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
8428c2ecf20Sopenharmony_ci				   u8 *backbone_addr, unsigned short vid)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
8458c2ecf20Sopenharmony_ci	u16 backbone_crc, crc;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	if (memcmp(an_addr, batadv_announce_mac, 4) != 0)
8488c2ecf20Sopenharmony_ci		return false;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid,
8518c2ecf20Sopenharmony_ci						 false);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	if (unlikely(!backbone_gw))
8548c2ecf20Sopenharmony_ci		return true;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	/* handle as ANNOUNCE frame */
8578c2ecf20Sopenharmony_ci	backbone_gw->lasttime = jiffies;
8588c2ecf20Sopenharmony_ci	crc = ntohs(*((__force __be16 *)(&an_addr[4])));
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
8618c2ecf20Sopenharmony_ci		   "%s(): ANNOUNCE vid %d (sent by %pM)... CRC = %#.4x\n",
8628c2ecf20Sopenharmony_ci		   __func__, batadv_print_vid(vid), backbone_gw->orig, crc);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
8658c2ecf20Sopenharmony_ci	backbone_crc = backbone_gw->crc;
8668c2ecf20Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	if (backbone_crc != crc) {
8698c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
8708c2ecf20Sopenharmony_ci			   "%s(): CRC FAILED for %pM/%d (my = %#.4x, sent = %#.4x)\n",
8718c2ecf20Sopenharmony_ci			   __func__, backbone_gw->orig,
8728c2ecf20Sopenharmony_ci			   batadv_print_vid(backbone_gw->vid),
8738c2ecf20Sopenharmony_ci			   backbone_crc, crc);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		batadv_bla_send_request(backbone_gw);
8768c2ecf20Sopenharmony_ci	} else {
8778c2ecf20Sopenharmony_ci		/* if we have sent a request and the crc was OK,
8788c2ecf20Sopenharmony_ci		 * we can allow traffic again.
8798c2ecf20Sopenharmony_ci		 */
8808c2ecf20Sopenharmony_ci		if (atomic_read(&backbone_gw->request_sent)) {
8818c2ecf20Sopenharmony_ci			atomic_dec(&backbone_gw->bat_priv->bla.num_requests);
8828c2ecf20Sopenharmony_ci			atomic_set(&backbone_gw->request_sent, 0);
8838c2ecf20Sopenharmony_ci		}
8848c2ecf20Sopenharmony_ci	}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
8878c2ecf20Sopenharmony_ci	return true;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci/**
8918c2ecf20Sopenharmony_ci * batadv_handle_request() - check for REQUEST frame
8928c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
8938c2ecf20Sopenharmony_ci * @primary_if: the primary hard interface of this batman soft interface
8948c2ecf20Sopenharmony_ci * @backbone_addr: backbone address to be requested (ARP sender HW MAC)
8958c2ecf20Sopenharmony_ci * @ethhdr: ethernet header of a packet
8968c2ecf20Sopenharmony_ci * @vid: the VLAN ID of the frame
8978c2ecf20Sopenharmony_ci *
8988c2ecf20Sopenharmony_ci * Return: true if handled
8998c2ecf20Sopenharmony_ci */
9008c2ecf20Sopenharmony_cistatic bool batadv_handle_request(struct batadv_priv *bat_priv,
9018c2ecf20Sopenharmony_ci				  struct batadv_hard_iface *primary_if,
9028c2ecf20Sopenharmony_ci				  u8 *backbone_addr, struct ethhdr *ethhdr,
9038c2ecf20Sopenharmony_ci				  unsigned short vid)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	/* check for REQUEST frame */
9068c2ecf20Sopenharmony_ci	if (!batadv_compare_eth(backbone_addr, ethhdr->h_dest))
9078c2ecf20Sopenharmony_ci		return false;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* sanity check, this should not happen on a normal switch,
9108c2ecf20Sopenharmony_ci	 * we ignore it in this case.
9118c2ecf20Sopenharmony_ci	 */
9128c2ecf20Sopenharmony_ci	if (!batadv_compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr))
9138c2ecf20Sopenharmony_ci		return true;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
9168c2ecf20Sopenharmony_ci		   "%s(): REQUEST vid %d (sent by %pM)...\n",
9178c2ecf20Sopenharmony_ci		   __func__, batadv_print_vid(vid), ethhdr->h_source);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	batadv_bla_answer_request(bat_priv, primary_if, vid);
9208c2ecf20Sopenharmony_ci	return true;
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci/**
9248c2ecf20Sopenharmony_ci * batadv_handle_unclaim() - check for UNCLAIM frame
9258c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
9268c2ecf20Sopenharmony_ci * @primary_if: the primary hard interface of this batman soft interface
9278c2ecf20Sopenharmony_ci * @backbone_addr: originator address of the backbone (Ethernet source)
9288c2ecf20Sopenharmony_ci * @claim_addr: Client to be unclaimed (ARP sender HW MAC)
9298c2ecf20Sopenharmony_ci * @vid: the VLAN ID of the frame
9308c2ecf20Sopenharmony_ci *
9318c2ecf20Sopenharmony_ci * Return: true if handled
9328c2ecf20Sopenharmony_ci */
9338c2ecf20Sopenharmony_cistatic bool batadv_handle_unclaim(struct batadv_priv *bat_priv,
9348c2ecf20Sopenharmony_ci				  struct batadv_hard_iface *primary_if,
9358c2ecf20Sopenharmony_ci				  u8 *backbone_addr, u8 *claim_addr,
9368c2ecf20Sopenharmony_ci				  unsigned short vid)
9378c2ecf20Sopenharmony_ci{
9388c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	/* unclaim in any case if it is our own */
9418c2ecf20Sopenharmony_ci	if (primary_if && batadv_compare_eth(backbone_addr,
9428c2ecf20Sopenharmony_ci					     primary_if->net_dev->dev_addr))
9438c2ecf20Sopenharmony_ci		batadv_bla_send_claim(bat_priv, claim_addr, vid,
9448c2ecf20Sopenharmony_ci				      BATADV_CLAIM_TYPE_UNCLAIM);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	if (!backbone_gw)
9498c2ecf20Sopenharmony_ci		return true;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	/* this must be an UNCLAIM frame */
9528c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
9538c2ecf20Sopenharmony_ci		   "%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n", __func__,
9548c2ecf20Sopenharmony_ci		   claim_addr, batadv_print_vid(vid), backbone_gw->orig);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	batadv_bla_del_claim(bat_priv, claim_addr, vid);
9578c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
9588c2ecf20Sopenharmony_ci	return true;
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci/**
9628c2ecf20Sopenharmony_ci * batadv_handle_claim() - check for CLAIM frame
9638c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
9648c2ecf20Sopenharmony_ci * @primary_if: the primary hard interface of this batman soft interface
9658c2ecf20Sopenharmony_ci * @backbone_addr: originator address of the backbone (Ethernet Source)
9668c2ecf20Sopenharmony_ci * @claim_addr: client mac address to be claimed (ARP sender HW MAC)
9678c2ecf20Sopenharmony_ci * @vid: the VLAN ID of the frame
9688c2ecf20Sopenharmony_ci *
9698c2ecf20Sopenharmony_ci * Return: true if handled
9708c2ecf20Sopenharmony_ci */
9718c2ecf20Sopenharmony_cistatic bool batadv_handle_claim(struct batadv_priv *bat_priv,
9728c2ecf20Sopenharmony_ci				struct batadv_hard_iface *primary_if,
9738c2ecf20Sopenharmony_ci				u8 *backbone_addr, u8 *claim_addr,
9748c2ecf20Sopenharmony_ci				unsigned short vid)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	/* register the gateway if not yet available, and add the claim. */
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid,
9818c2ecf20Sopenharmony_ci						 false);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	if (unlikely(!backbone_gw))
9848c2ecf20Sopenharmony_ci		return true;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	/* this must be a CLAIM frame */
9878c2ecf20Sopenharmony_ci	batadv_bla_add_claim(bat_priv, claim_addr, vid, backbone_gw);
9888c2ecf20Sopenharmony_ci	if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
9898c2ecf20Sopenharmony_ci		batadv_bla_send_claim(bat_priv, claim_addr, vid,
9908c2ecf20Sopenharmony_ci				      BATADV_CLAIM_TYPE_CLAIM);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	/* TODO: we could call something like tt_local_del() here. */
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
9958c2ecf20Sopenharmony_ci	return true;
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci/**
9998c2ecf20Sopenharmony_ci * batadv_check_claim_group() - check for claim group membership
10008c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
10018c2ecf20Sopenharmony_ci * @primary_if: the primary interface of this batman interface
10028c2ecf20Sopenharmony_ci * @hw_src: the Hardware source in the ARP Header
10038c2ecf20Sopenharmony_ci * @hw_dst: the Hardware destination in the ARP Header
10048c2ecf20Sopenharmony_ci * @ethhdr: pointer to the Ethernet header of the claim frame
10058c2ecf20Sopenharmony_ci *
10068c2ecf20Sopenharmony_ci * checks if it is a claim packet and if it's on the same group.
10078c2ecf20Sopenharmony_ci * This function also applies the group ID of the sender
10088c2ecf20Sopenharmony_ci * if it is in the same mesh.
10098c2ecf20Sopenharmony_ci *
10108c2ecf20Sopenharmony_ci * Return:
10118c2ecf20Sopenharmony_ci *	2  - if it is a claim packet and on the same group
10128c2ecf20Sopenharmony_ci *	1  - if is a claim packet from another group
10138c2ecf20Sopenharmony_ci *	0  - if it is not a claim packet
10148c2ecf20Sopenharmony_ci */
10158c2ecf20Sopenharmony_cistatic int batadv_check_claim_group(struct batadv_priv *bat_priv,
10168c2ecf20Sopenharmony_ci				    struct batadv_hard_iface *primary_if,
10178c2ecf20Sopenharmony_ci				    u8 *hw_src, u8 *hw_dst,
10188c2ecf20Sopenharmony_ci				    struct ethhdr *ethhdr)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	u8 *backbone_addr;
10218c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
10228c2ecf20Sopenharmony_ci	struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	bla_dst = (struct batadv_bla_claim_dst *)hw_dst;
10258c2ecf20Sopenharmony_ci	bla_dst_own = &bat_priv->bla.claim_dest;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	/* if announcement packet, use the source,
10288c2ecf20Sopenharmony_ci	 * otherwise assume it is in the hw_src
10298c2ecf20Sopenharmony_ci	 */
10308c2ecf20Sopenharmony_ci	switch (bla_dst->type) {
10318c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_CLAIM:
10328c2ecf20Sopenharmony_ci		backbone_addr = hw_src;
10338c2ecf20Sopenharmony_ci		break;
10348c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_REQUEST:
10358c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_ANNOUNCE:
10368c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_UNCLAIM:
10378c2ecf20Sopenharmony_ci		backbone_addr = ethhdr->h_source;
10388c2ecf20Sopenharmony_ci		break;
10398c2ecf20Sopenharmony_ci	default:
10408c2ecf20Sopenharmony_ci		return 0;
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	/* don't accept claim frames from ourselves */
10448c2ecf20Sopenharmony_ci	if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
10458c2ecf20Sopenharmony_ci		return 0;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	/* if its already the same group, it is fine. */
10488c2ecf20Sopenharmony_ci	if (bla_dst->group == bla_dst_own->group)
10498c2ecf20Sopenharmony_ci		return 2;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	/* lets see if this originator is in our mesh */
10528c2ecf20Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, backbone_addr);
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	/* dont accept claims from gateways which are not in
10558c2ecf20Sopenharmony_ci	 * the same mesh or group.
10568c2ecf20Sopenharmony_ci	 */
10578c2ecf20Sopenharmony_ci	if (!orig_node)
10588c2ecf20Sopenharmony_ci		return 1;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	/* if our mesh friends mac is bigger, use it for ourselves. */
10618c2ecf20Sopenharmony_ci	if (ntohs(bla_dst->group) > ntohs(bla_dst_own->group)) {
10628c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
10638c2ecf20Sopenharmony_ci			   "taking other backbones claim group: %#.4x\n",
10648c2ecf20Sopenharmony_ci			   ntohs(bla_dst->group));
10658c2ecf20Sopenharmony_ci		bla_dst_own->group = bla_dst->group;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	batadv_orig_node_put(orig_node);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	return 2;
10718c2ecf20Sopenharmony_ci}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci/**
10748c2ecf20Sopenharmony_ci * batadv_bla_process_claim() - Check if this is a claim frame, and process it
10758c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
10768c2ecf20Sopenharmony_ci * @primary_if: the primary hard interface of this batman soft interface
10778c2ecf20Sopenharmony_ci * @skb: the frame to be checked
10788c2ecf20Sopenharmony_ci *
10798c2ecf20Sopenharmony_ci * Return: true if it was a claim frame, otherwise return false to
10808c2ecf20Sopenharmony_ci * tell the callee that it can use the frame on its own.
10818c2ecf20Sopenharmony_ci */
10828c2ecf20Sopenharmony_cistatic bool batadv_bla_process_claim(struct batadv_priv *bat_priv,
10838c2ecf20Sopenharmony_ci				     struct batadv_hard_iface *primary_if,
10848c2ecf20Sopenharmony_ci				     struct sk_buff *skb)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;
10878c2ecf20Sopenharmony_ci	u8 *hw_src, *hw_dst;
10888c2ecf20Sopenharmony_ci	struct vlan_hdr *vhdr, vhdr_buf;
10898c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr;
10908c2ecf20Sopenharmony_ci	struct arphdr *arphdr;
10918c2ecf20Sopenharmony_ci	unsigned short vid;
10928c2ecf20Sopenharmony_ci	int vlan_depth = 0;
10938c2ecf20Sopenharmony_ci	__be16 proto;
10948c2ecf20Sopenharmony_ci	int headlen;
10958c2ecf20Sopenharmony_ci	int ret;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	vid = batadv_get_vid(skb, 0);
10988c2ecf20Sopenharmony_ci	ethhdr = eth_hdr(skb);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	proto = ethhdr->h_proto;
11018c2ecf20Sopenharmony_ci	headlen = ETH_HLEN;
11028c2ecf20Sopenharmony_ci	if (vid & BATADV_VLAN_HAS_TAG) {
11038c2ecf20Sopenharmony_ci		/* Traverse the VLAN/Ethertypes.
11048c2ecf20Sopenharmony_ci		 *
11058c2ecf20Sopenharmony_ci		 * At this point it is known that the first protocol is a VLAN
11068c2ecf20Sopenharmony_ci		 * header, so start checking at the encapsulated protocol.
11078c2ecf20Sopenharmony_ci		 *
11088c2ecf20Sopenharmony_ci		 * The depth of the VLAN headers is recorded to drop BLA claim
11098c2ecf20Sopenharmony_ci		 * frames encapsulated into multiple VLAN headers (QinQ).
11108c2ecf20Sopenharmony_ci		 */
11118c2ecf20Sopenharmony_ci		do {
11128c2ecf20Sopenharmony_ci			vhdr = skb_header_pointer(skb, headlen, VLAN_HLEN,
11138c2ecf20Sopenharmony_ci						  &vhdr_buf);
11148c2ecf20Sopenharmony_ci			if (!vhdr)
11158c2ecf20Sopenharmony_ci				return false;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci			proto = vhdr->h_vlan_encapsulated_proto;
11188c2ecf20Sopenharmony_ci			headlen += VLAN_HLEN;
11198c2ecf20Sopenharmony_ci			vlan_depth++;
11208c2ecf20Sopenharmony_ci		} while (proto == htons(ETH_P_8021Q));
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	if (proto != htons(ETH_P_ARP))
11248c2ecf20Sopenharmony_ci		return false; /* not a claim frame */
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	/* this must be a ARP frame. check if it is a claim. */
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	if (unlikely(!pskb_may_pull(skb, headlen + arp_hdr_len(skb->dev))))
11298c2ecf20Sopenharmony_ci		return false;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	/* pskb_may_pull() may have modified the pointers, get ethhdr again */
11328c2ecf20Sopenharmony_ci	ethhdr = eth_hdr(skb);
11338c2ecf20Sopenharmony_ci	arphdr = (struct arphdr *)((u8 *)ethhdr + headlen);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	/* Check whether the ARP frame carries a valid
11368c2ecf20Sopenharmony_ci	 * IP information
11378c2ecf20Sopenharmony_ci	 */
11388c2ecf20Sopenharmony_ci	if (arphdr->ar_hrd != htons(ARPHRD_ETHER))
11398c2ecf20Sopenharmony_ci		return false;
11408c2ecf20Sopenharmony_ci	if (arphdr->ar_pro != htons(ETH_P_IP))
11418c2ecf20Sopenharmony_ci		return false;
11428c2ecf20Sopenharmony_ci	if (arphdr->ar_hln != ETH_ALEN)
11438c2ecf20Sopenharmony_ci		return false;
11448c2ecf20Sopenharmony_ci	if (arphdr->ar_pln != 4)
11458c2ecf20Sopenharmony_ci		return false;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	hw_src = (u8 *)arphdr + sizeof(struct arphdr);
11488c2ecf20Sopenharmony_ci	hw_dst = hw_src + ETH_ALEN + 4;
11498c2ecf20Sopenharmony_ci	bla_dst = (struct batadv_bla_claim_dst *)hw_dst;
11508c2ecf20Sopenharmony_ci	bla_dst_own = &bat_priv->bla.claim_dest;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	/* check if it is a claim frame in general */
11538c2ecf20Sopenharmony_ci	if (memcmp(bla_dst->magic, bla_dst_own->magic,
11548c2ecf20Sopenharmony_ci		   sizeof(bla_dst->magic)) != 0)
11558c2ecf20Sopenharmony_ci		return false;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	/* check if there is a claim frame encapsulated deeper in (QinQ) and
11588c2ecf20Sopenharmony_ci	 * drop that, as this is not supported by BLA but should also not be
11598c2ecf20Sopenharmony_ci	 * sent via the mesh.
11608c2ecf20Sopenharmony_ci	 */
11618c2ecf20Sopenharmony_ci	if (vlan_depth > 1)
11628c2ecf20Sopenharmony_ci		return true;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	/* Let the loopdetect frames on the mesh in any case. */
11658c2ecf20Sopenharmony_ci	if (bla_dst->type == BATADV_CLAIM_TYPE_LOOPDETECT)
11668c2ecf20Sopenharmony_ci		return false;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	/* check if it is a claim frame. */
11698c2ecf20Sopenharmony_ci	ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst,
11708c2ecf20Sopenharmony_ci				       ethhdr);
11718c2ecf20Sopenharmony_ci	if (ret == 1)
11728c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
11738c2ecf20Sopenharmony_ci			   "%s(): received a claim frame from another group. From: %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
11748c2ecf20Sopenharmony_ci			   __func__, ethhdr->h_source, batadv_print_vid(vid),
11758c2ecf20Sopenharmony_ci			   hw_src, hw_dst);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	if (ret < 2)
11788c2ecf20Sopenharmony_ci		return !!ret;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	/* become a backbone gw ourselves on this vlan if not happened yet */
11818c2ecf20Sopenharmony_ci	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	/* check for the different types of claim frames ... */
11848c2ecf20Sopenharmony_ci	switch (bla_dst->type) {
11858c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_CLAIM:
11868c2ecf20Sopenharmony_ci		if (batadv_handle_claim(bat_priv, primary_if, hw_src,
11878c2ecf20Sopenharmony_ci					ethhdr->h_source, vid))
11888c2ecf20Sopenharmony_ci			return true;
11898c2ecf20Sopenharmony_ci		break;
11908c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_UNCLAIM:
11918c2ecf20Sopenharmony_ci		if (batadv_handle_unclaim(bat_priv, primary_if,
11928c2ecf20Sopenharmony_ci					  ethhdr->h_source, hw_src, vid))
11938c2ecf20Sopenharmony_ci			return true;
11948c2ecf20Sopenharmony_ci		break;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_ANNOUNCE:
11978c2ecf20Sopenharmony_ci		if (batadv_handle_announce(bat_priv, hw_src, ethhdr->h_source,
11988c2ecf20Sopenharmony_ci					   vid))
11998c2ecf20Sopenharmony_ci			return true;
12008c2ecf20Sopenharmony_ci		break;
12018c2ecf20Sopenharmony_ci	case BATADV_CLAIM_TYPE_REQUEST:
12028c2ecf20Sopenharmony_ci		if (batadv_handle_request(bat_priv, primary_if, hw_src, ethhdr,
12038c2ecf20Sopenharmony_ci					  vid))
12048c2ecf20Sopenharmony_ci			return true;
12058c2ecf20Sopenharmony_ci		break;
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
12098c2ecf20Sopenharmony_ci		   "%s(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
12108c2ecf20Sopenharmony_ci		   __func__, ethhdr->h_source, batadv_print_vid(vid), hw_src,
12118c2ecf20Sopenharmony_ci		   hw_dst);
12128c2ecf20Sopenharmony_ci	return true;
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci/**
12168c2ecf20Sopenharmony_ci * batadv_bla_purge_backbone_gw() - Remove backbone gateways after a timeout or
12178c2ecf20Sopenharmony_ci *  immediately
12188c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
12198c2ecf20Sopenharmony_ci * @now: whether the whole hash shall be wiped now
12208c2ecf20Sopenharmony_ci *
12218c2ecf20Sopenharmony_ci * Check when we last heard from other nodes, and remove them in case of
12228c2ecf20Sopenharmony_ci * a time out, or clean all backbone gws if now is set.
12238c2ecf20Sopenharmony_ci */
12248c2ecf20Sopenharmony_cistatic void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
12278c2ecf20Sopenharmony_ci	struct hlist_node *node_tmp;
12288c2ecf20Sopenharmony_ci	struct hlist_head *head;
12298c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
12308c2ecf20Sopenharmony_ci	spinlock_t *list_lock;	/* protects write access to the hash lists */
12318c2ecf20Sopenharmony_ci	int i;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	hash = bat_priv->bla.backbone_hash;
12348c2ecf20Sopenharmony_ci	if (!hash)
12358c2ecf20Sopenharmony_ci		return;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
12388c2ecf20Sopenharmony_ci		head = &hash->table[i];
12398c2ecf20Sopenharmony_ci		list_lock = &hash->list_locks[i];
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci		spin_lock_bh(list_lock);
12428c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(backbone_gw, node_tmp,
12438c2ecf20Sopenharmony_ci					  head, hash_entry) {
12448c2ecf20Sopenharmony_ci			if (now)
12458c2ecf20Sopenharmony_ci				goto purge_now;
12468c2ecf20Sopenharmony_ci			if (!batadv_has_timed_out(backbone_gw->lasttime,
12478c2ecf20Sopenharmony_ci						  BATADV_BLA_BACKBONE_TIMEOUT))
12488c2ecf20Sopenharmony_ci				continue;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
12518c2ecf20Sopenharmony_ci				   "%s(): backbone gw %pM timed out\n",
12528c2ecf20Sopenharmony_ci				   __func__, backbone_gw->orig);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_cipurge_now:
12558c2ecf20Sopenharmony_ci			/* don't wait for the pending request anymore */
12568c2ecf20Sopenharmony_ci			if (atomic_read(&backbone_gw->request_sent))
12578c2ecf20Sopenharmony_ci				atomic_dec(&bat_priv->bla.num_requests);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci			batadv_bla_del_backbone_claims(backbone_gw);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci			hlist_del_rcu(&backbone_gw->hash_entry);
12628c2ecf20Sopenharmony_ci			batadv_backbone_gw_put(backbone_gw);
12638c2ecf20Sopenharmony_ci		}
12648c2ecf20Sopenharmony_ci		spin_unlock_bh(list_lock);
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci/**
12698c2ecf20Sopenharmony_ci * batadv_bla_purge_claims() - Remove claims after a timeout or immediately
12708c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
12718c2ecf20Sopenharmony_ci * @primary_if: the selected primary interface, may be NULL if now is set
12728c2ecf20Sopenharmony_ci * @now: whether the whole hash shall be wiped now
12738c2ecf20Sopenharmony_ci *
12748c2ecf20Sopenharmony_ci * Check when we heard last time from our own claims, and remove them in case of
12758c2ecf20Sopenharmony_ci * a time out, or clean all claims if now is set
12768c2ecf20Sopenharmony_ci */
12778c2ecf20Sopenharmony_cistatic void batadv_bla_purge_claims(struct batadv_priv *bat_priv,
12788c2ecf20Sopenharmony_ci				    struct batadv_hard_iface *primary_if,
12798c2ecf20Sopenharmony_ci				    int now)
12808c2ecf20Sopenharmony_ci{
12818c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
12828c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim;
12838c2ecf20Sopenharmony_ci	struct hlist_head *head;
12848c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
12858c2ecf20Sopenharmony_ci	int i;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	hash = bat_priv->bla.claim_hash;
12888c2ecf20Sopenharmony_ci	if (!hash)
12898c2ecf20Sopenharmony_ci		return;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
12928c2ecf20Sopenharmony_ci		head = &hash->table[i];
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		rcu_read_lock();
12958c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(claim, head, hash_entry) {
12968c2ecf20Sopenharmony_ci			backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
12978c2ecf20Sopenharmony_ci			if (now)
12988c2ecf20Sopenharmony_ci				goto purge_now;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci			if (!batadv_compare_eth(backbone_gw->orig,
13018c2ecf20Sopenharmony_ci						primary_if->net_dev->dev_addr))
13028c2ecf20Sopenharmony_ci				goto skip;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci			if (!batadv_has_timed_out(claim->lasttime,
13058c2ecf20Sopenharmony_ci						  BATADV_BLA_CLAIM_TIMEOUT))
13068c2ecf20Sopenharmony_ci				goto skip;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, bat_priv,
13098c2ecf20Sopenharmony_ci				   "%s(): timed out.\n", __func__);
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_cipurge_now:
13128c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, bat_priv,
13138c2ecf20Sopenharmony_ci				   "%s(): %pM, vid %d\n", __func__,
13148c2ecf20Sopenharmony_ci				   claim->addr, claim->vid);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci			batadv_handle_unclaim(bat_priv, primary_if,
13178c2ecf20Sopenharmony_ci					      backbone_gw->orig,
13188c2ecf20Sopenharmony_ci					      claim->addr, claim->vid);
13198c2ecf20Sopenharmony_ciskip:
13208c2ecf20Sopenharmony_ci			batadv_backbone_gw_put(backbone_gw);
13218c2ecf20Sopenharmony_ci		}
13228c2ecf20Sopenharmony_ci		rcu_read_unlock();
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci/**
13278c2ecf20Sopenharmony_ci * batadv_bla_update_orig_address() - Update the backbone gateways when the own
13288c2ecf20Sopenharmony_ci *  originator address changes
13298c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
13308c2ecf20Sopenharmony_ci * @primary_if: the new selected primary_if
13318c2ecf20Sopenharmony_ci * @oldif: the old primary interface, may be NULL
13328c2ecf20Sopenharmony_ci */
13338c2ecf20Sopenharmony_civoid batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
13348c2ecf20Sopenharmony_ci				    struct batadv_hard_iface *primary_if,
13358c2ecf20Sopenharmony_ci				    struct batadv_hard_iface *oldif)
13368c2ecf20Sopenharmony_ci{
13378c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
13388c2ecf20Sopenharmony_ci	struct hlist_head *head;
13398c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
13408c2ecf20Sopenharmony_ci	__be16 group;
13418c2ecf20Sopenharmony_ci	int i;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	/* reset bridge loop avoidance group id */
13448c2ecf20Sopenharmony_ci	group = htons(crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN));
13458c2ecf20Sopenharmony_ci	bat_priv->bla.claim_dest.group = group;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	/* purge everything when bridge loop avoidance is turned off */
13488c2ecf20Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
13498c2ecf20Sopenharmony_ci		oldif = NULL;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	if (!oldif) {
13528c2ecf20Sopenharmony_ci		batadv_bla_purge_claims(bat_priv, NULL, 1);
13538c2ecf20Sopenharmony_ci		batadv_bla_purge_backbone_gw(bat_priv, 1);
13548c2ecf20Sopenharmony_ci		return;
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	hash = bat_priv->bla.backbone_hash;
13588c2ecf20Sopenharmony_ci	if (!hash)
13598c2ecf20Sopenharmony_ci		return;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
13628c2ecf20Sopenharmony_ci		head = &hash->table[i];
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci		rcu_read_lock();
13658c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
13668c2ecf20Sopenharmony_ci			/* own orig still holds the old value. */
13678c2ecf20Sopenharmony_ci			if (!batadv_compare_eth(backbone_gw->orig,
13688c2ecf20Sopenharmony_ci						oldif->net_dev->dev_addr))
13698c2ecf20Sopenharmony_ci				continue;
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci			ether_addr_copy(backbone_gw->orig,
13728c2ecf20Sopenharmony_ci					primary_if->net_dev->dev_addr);
13738c2ecf20Sopenharmony_ci			/* send an announce frame so others will ask for our
13748c2ecf20Sopenharmony_ci			 * claims and update their tables.
13758c2ecf20Sopenharmony_ci			 */
13768c2ecf20Sopenharmony_ci			batadv_bla_send_announce(bat_priv, backbone_gw);
13778c2ecf20Sopenharmony_ci		}
13788c2ecf20Sopenharmony_ci		rcu_read_unlock();
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci}
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci/**
13838c2ecf20Sopenharmony_ci * batadv_bla_send_loopdetect() - send a loopdetect frame
13848c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
13858c2ecf20Sopenharmony_ci * @backbone_gw: the backbone gateway for which a loop should be detected
13868c2ecf20Sopenharmony_ci *
13878c2ecf20Sopenharmony_ci * To detect loops that the bridge loop avoidance can't handle, send a loop
13888c2ecf20Sopenharmony_ci * detection packet on the backbone. Unlike other BLA frames, this frame will
13898c2ecf20Sopenharmony_ci * be allowed on the mesh by other nodes. If it is received on the mesh, this
13908c2ecf20Sopenharmony_ci * indicates that there is a loop.
13918c2ecf20Sopenharmony_ci */
13928c2ecf20Sopenharmony_cistatic void
13938c2ecf20Sopenharmony_cibatadv_bla_send_loopdetect(struct batadv_priv *bat_priv,
13948c2ecf20Sopenharmony_ci			   struct batadv_bla_backbone_gw *backbone_gw)
13958c2ecf20Sopenharmony_ci{
13968c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv, "Send loopdetect frame for vid %d\n",
13978c2ecf20Sopenharmony_ci		   backbone_gw->vid);
13988c2ecf20Sopenharmony_ci	batadv_bla_send_claim(bat_priv, bat_priv->bla.loopdetect_addr,
13998c2ecf20Sopenharmony_ci			      backbone_gw->vid, BATADV_CLAIM_TYPE_LOOPDETECT);
14008c2ecf20Sopenharmony_ci}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci/**
14038c2ecf20Sopenharmony_ci * batadv_bla_status_update() - purge bla interfaces if necessary
14048c2ecf20Sopenharmony_ci * @net_dev: the soft interface net device
14058c2ecf20Sopenharmony_ci */
14068c2ecf20Sopenharmony_civoid batadv_bla_status_update(struct net_device *net_dev)
14078c2ecf20Sopenharmony_ci{
14088c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(net_dev);
14098c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
14128c2ecf20Sopenharmony_ci	if (!primary_if)
14138c2ecf20Sopenharmony_ci		return;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	/* this function already purges everything when bla is disabled,
14168c2ecf20Sopenharmony_ci	 * so just call that one.
14178c2ecf20Sopenharmony_ci	 */
14188c2ecf20Sopenharmony_ci	batadv_bla_update_orig_address(bat_priv, primary_if, primary_if);
14198c2ecf20Sopenharmony_ci	batadv_hardif_put(primary_if);
14208c2ecf20Sopenharmony_ci}
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci/**
14238c2ecf20Sopenharmony_ci * batadv_bla_periodic_work() - performs periodic bla work
14248c2ecf20Sopenharmony_ci * @work: kernel work struct
14258c2ecf20Sopenharmony_ci *
14268c2ecf20Sopenharmony_ci * periodic work to do:
14278c2ecf20Sopenharmony_ci *  * purge structures when they are too old
14288c2ecf20Sopenharmony_ci *  * send announcements
14298c2ecf20Sopenharmony_ci */
14308c2ecf20Sopenharmony_cistatic void batadv_bla_periodic_work(struct work_struct *work)
14318c2ecf20Sopenharmony_ci{
14328c2ecf20Sopenharmony_ci	struct delayed_work *delayed_work;
14338c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
14348c2ecf20Sopenharmony_ci	struct batadv_priv_bla *priv_bla;
14358c2ecf20Sopenharmony_ci	struct hlist_head *head;
14368c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
14378c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
14388c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
14398c2ecf20Sopenharmony_ci	bool send_loopdetect = false;
14408c2ecf20Sopenharmony_ci	int i;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	delayed_work = to_delayed_work(work);
14438c2ecf20Sopenharmony_ci	priv_bla = container_of(delayed_work, struct batadv_priv_bla, work);
14448c2ecf20Sopenharmony_ci	bat_priv = container_of(priv_bla, struct batadv_priv, bla);
14458c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
14468c2ecf20Sopenharmony_ci	if (!primary_if)
14478c2ecf20Sopenharmony_ci		goto out;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	batadv_bla_purge_claims(bat_priv, primary_if, 0);
14508c2ecf20Sopenharmony_ci	batadv_bla_purge_backbone_gw(bat_priv, 0);
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
14538c2ecf20Sopenharmony_ci		goto out;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&bat_priv->bla.loopdetect_next)) {
14568c2ecf20Sopenharmony_ci		/* set a new random mac address for the next bridge loop
14578c2ecf20Sopenharmony_ci		 * detection frames. Set the locally administered bit to avoid
14588c2ecf20Sopenharmony_ci		 * collisions with users mac addresses.
14598c2ecf20Sopenharmony_ci		 */
14608c2ecf20Sopenharmony_ci		eth_random_addr(bat_priv->bla.loopdetect_addr);
14618c2ecf20Sopenharmony_ci		bat_priv->bla.loopdetect_addr[0] = 0xba;
14628c2ecf20Sopenharmony_ci		bat_priv->bla.loopdetect_addr[1] = 0xbe;
14638c2ecf20Sopenharmony_ci		bat_priv->bla.loopdetect_lasttime = jiffies;
14648c2ecf20Sopenharmony_ci		atomic_set(&bat_priv->bla.loopdetect_next,
14658c2ecf20Sopenharmony_ci			   BATADV_BLA_LOOPDETECT_PERIODS);
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci		/* mark for sending loop detect on all VLANs */
14688c2ecf20Sopenharmony_ci		send_loopdetect = true;
14698c2ecf20Sopenharmony_ci	}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	hash = bat_priv->bla.backbone_hash;
14728c2ecf20Sopenharmony_ci	if (!hash)
14738c2ecf20Sopenharmony_ci		goto out;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
14768c2ecf20Sopenharmony_ci		head = &hash->table[i];
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci		rcu_read_lock();
14798c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
14808c2ecf20Sopenharmony_ci			if (!batadv_compare_eth(backbone_gw->orig,
14818c2ecf20Sopenharmony_ci						primary_if->net_dev->dev_addr))
14828c2ecf20Sopenharmony_ci				continue;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci			backbone_gw->lasttime = jiffies;
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci			batadv_bla_send_announce(bat_priv, backbone_gw);
14878c2ecf20Sopenharmony_ci			if (send_loopdetect)
14888c2ecf20Sopenharmony_ci				batadv_bla_send_loopdetect(bat_priv,
14898c2ecf20Sopenharmony_ci							   backbone_gw);
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci			/* request_sent is only set after creation to avoid
14928c2ecf20Sopenharmony_ci			 * problems when we are not yet known as backbone gw
14938c2ecf20Sopenharmony_ci			 * in the backbone.
14948c2ecf20Sopenharmony_ci			 *
14958c2ecf20Sopenharmony_ci			 * We can reset this now after we waited some periods
14968c2ecf20Sopenharmony_ci			 * to give bridge forward delays and bla group forming
14978c2ecf20Sopenharmony_ci			 * some grace time.
14988c2ecf20Sopenharmony_ci			 */
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci			if (atomic_read(&backbone_gw->request_sent) == 0)
15018c2ecf20Sopenharmony_ci				continue;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci			if (!atomic_dec_and_test(&backbone_gw->wait_periods))
15048c2ecf20Sopenharmony_ci				continue;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci			atomic_dec(&backbone_gw->bat_priv->bla.num_requests);
15078c2ecf20Sopenharmony_ci			atomic_set(&backbone_gw->request_sent, 0);
15088c2ecf20Sopenharmony_ci		}
15098c2ecf20Sopenharmony_ci		rcu_read_unlock();
15108c2ecf20Sopenharmony_ci	}
15118c2ecf20Sopenharmony_ciout:
15128c2ecf20Sopenharmony_ci	if (primary_if)
15138c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
15168c2ecf20Sopenharmony_ci			   msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
15178c2ecf20Sopenharmony_ci}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci/* The hash for claim and backbone hash receive the same key because they
15208c2ecf20Sopenharmony_ci * are getting initialized by hash_new with the same key. Reinitializing
15218c2ecf20Sopenharmony_ci * them with to different keys to allow nested locking without generating
15228c2ecf20Sopenharmony_ci * lockdep warnings
15238c2ecf20Sopenharmony_ci */
15248c2ecf20Sopenharmony_cistatic struct lock_class_key batadv_claim_hash_lock_class_key;
15258c2ecf20Sopenharmony_cistatic struct lock_class_key batadv_backbone_hash_lock_class_key;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci/**
15288c2ecf20Sopenharmony_ci * batadv_bla_init() - initialize all bla structures
15298c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
15308c2ecf20Sopenharmony_ci *
15318c2ecf20Sopenharmony_ci * Return: 0 on success, < 0 on error.
15328c2ecf20Sopenharmony_ci */
15338c2ecf20Sopenharmony_ciint batadv_bla_init(struct batadv_priv *bat_priv)
15348c2ecf20Sopenharmony_ci{
15358c2ecf20Sopenharmony_ci	int i;
15368c2ecf20Sopenharmony_ci	u8 claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00};
15378c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
15388c2ecf20Sopenharmony_ci	u16 crc;
15398c2ecf20Sopenharmony_ci	unsigned long entrytime;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	spin_lock_init(&bat_priv->bla.bcast_duplist_lock);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hash registering\n");
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	/* setting claim destination address */
15468c2ecf20Sopenharmony_ci	memcpy(&bat_priv->bla.claim_dest.magic, claim_dest, 3);
15478c2ecf20Sopenharmony_ci	bat_priv->bla.claim_dest.type = 0;
15488c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
15498c2ecf20Sopenharmony_ci	if (primary_if) {
15508c2ecf20Sopenharmony_ci		crc = crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN);
15518c2ecf20Sopenharmony_ci		bat_priv->bla.claim_dest.group = htons(crc);
15528c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
15538c2ecf20Sopenharmony_ci	} else {
15548c2ecf20Sopenharmony_ci		bat_priv->bla.claim_dest.group = 0; /* will be set later */
15558c2ecf20Sopenharmony_ci	}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	/* initialize the duplicate list */
15588c2ecf20Sopenharmony_ci	entrytime = jiffies - msecs_to_jiffies(BATADV_DUPLIST_TIMEOUT);
15598c2ecf20Sopenharmony_ci	for (i = 0; i < BATADV_DUPLIST_SIZE; i++)
15608c2ecf20Sopenharmony_ci		bat_priv->bla.bcast_duplist[i].entrytime = entrytime;
15618c2ecf20Sopenharmony_ci	bat_priv->bla.bcast_duplist_curr = 0;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	atomic_set(&bat_priv->bla.loopdetect_next,
15648c2ecf20Sopenharmony_ci		   BATADV_BLA_LOOPDETECT_PERIODS);
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	if (bat_priv->bla.claim_hash)
15678c2ecf20Sopenharmony_ci		return 0;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	bat_priv->bla.claim_hash = batadv_hash_new(128);
15708c2ecf20Sopenharmony_ci	if (!bat_priv->bla.claim_hash)
15718c2ecf20Sopenharmony_ci		return -ENOMEM;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	bat_priv->bla.backbone_hash = batadv_hash_new(32);
15748c2ecf20Sopenharmony_ci	if (!bat_priv->bla.backbone_hash) {
15758c2ecf20Sopenharmony_ci		batadv_hash_destroy(bat_priv->bla.claim_hash);
15768c2ecf20Sopenharmony_ci		return -ENOMEM;
15778c2ecf20Sopenharmony_ci	}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	batadv_hash_set_lock_class(bat_priv->bla.claim_hash,
15808c2ecf20Sopenharmony_ci				   &batadv_claim_hash_lock_class_key);
15818c2ecf20Sopenharmony_ci	batadv_hash_set_lock_class(bat_priv->bla.backbone_hash,
15828c2ecf20Sopenharmony_ci				   &batadv_backbone_hash_lock_class_key);
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hashes initialized\n");
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&bat_priv->bla.work, batadv_bla_periodic_work);
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
15898c2ecf20Sopenharmony_ci			   msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
15908c2ecf20Sopenharmony_ci	return 0;
15918c2ecf20Sopenharmony_ci}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci/**
15948c2ecf20Sopenharmony_ci * batadv_bla_check_duplist() - Check if a frame is in the broadcast dup.
15958c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
15968c2ecf20Sopenharmony_ci * @skb: contains the multicast packet to be checked
15978c2ecf20Sopenharmony_ci * @payload_ptr: pointer to position inside the head buffer of the skb
15988c2ecf20Sopenharmony_ci *  marking the start of the data to be CRC'ed
15998c2ecf20Sopenharmony_ci * @orig: originator mac address, NULL if unknown
16008c2ecf20Sopenharmony_ci *
16018c2ecf20Sopenharmony_ci * Check if it is on our broadcast list. Another gateway might have sent the
16028c2ecf20Sopenharmony_ci * same packet because it is connected to the same backbone, so we have to
16038c2ecf20Sopenharmony_ci * remove this duplicate.
16048c2ecf20Sopenharmony_ci *
16058c2ecf20Sopenharmony_ci * This is performed by checking the CRC, which will tell us
16068c2ecf20Sopenharmony_ci * with a good chance that it is the same packet. If it is furthermore
16078c2ecf20Sopenharmony_ci * sent by another host, drop it. We allow equal packets from
16088c2ecf20Sopenharmony_ci * the same host however as this might be intended.
16098c2ecf20Sopenharmony_ci *
16108c2ecf20Sopenharmony_ci * Return: true if a packet is in the duplicate list, false otherwise.
16118c2ecf20Sopenharmony_ci */
16128c2ecf20Sopenharmony_cistatic bool batadv_bla_check_duplist(struct batadv_priv *bat_priv,
16138c2ecf20Sopenharmony_ci				     struct sk_buff *skb, u8 *payload_ptr,
16148c2ecf20Sopenharmony_ci				     const u8 *orig)
16158c2ecf20Sopenharmony_ci{
16168c2ecf20Sopenharmony_ci	struct batadv_bcast_duplist_entry *entry;
16178c2ecf20Sopenharmony_ci	bool ret = false;
16188c2ecf20Sopenharmony_ci	int i, curr;
16198c2ecf20Sopenharmony_ci	__be32 crc;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	/* calculate the crc ... */
16228c2ecf20Sopenharmony_ci	crc = batadv_skb_crc32(skb, payload_ptr);
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->bla.bcast_duplist_lock);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	for (i = 0; i < BATADV_DUPLIST_SIZE; i++) {
16278c2ecf20Sopenharmony_ci		curr = (bat_priv->bla.bcast_duplist_curr + i);
16288c2ecf20Sopenharmony_ci		curr %= BATADV_DUPLIST_SIZE;
16298c2ecf20Sopenharmony_ci		entry = &bat_priv->bla.bcast_duplist[curr];
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci		/* we can stop searching if the entry is too old ;
16328c2ecf20Sopenharmony_ci		 * later entries will be even older
16338c2ecf20Sopenharmony_ci		 */
16348c2ecf20Sopenharmony_ci		if (batadv_has_timed_out(entry->entrytime,
16358c2ecf20Sopenharmony_ci					 BATADV_DUPLIST_TIMEOUT))
16368c2ecf20Sopenharmony_ci			break;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci		if (entry->crc != crc)
16398c2ecf20Sopenharmony_ci			continue;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci		/* are the originators both known and not anonymous? */
16428c2ecf20Sopenharmony_ci		if (orig && !is_zero_ether_addr(orig) &&
16438c2ecf20Sopenharmony_ci		    !is_zero_ether_addr(entry->orig)) {
16448c2ecf20Sopenharmony_ci			/* If known, check if the new frame came from
16458c2ecf20Sopenharmony_ci			 * the same originator:
16468c2ecf20Sopenharmony_ci			 * We are safe to take identical frames from the
16478c2ecf20Sopenharmony_ci			 * same orig, if known, as multiplications in
16488c2ecf20Sopenharmony_ci			 * the mesh are detected via the (orig, seqno) pair.
16498c2ecf20Sopenharmony_ci			 * So we can be a bit more liberal here and allow
16508c2ecf20Sopenharmony_ci			 * identical frames from the same orig which the source
16518c2ecf20Sopenharmony_ci			 * host might have sent multiple times on purpose.
16528c2ecf20Sopenharmony_ci			 */
16538c2ecf20Sopenharmony_ci			if (batadv_compare_eth(entry->orig, orig))
16548c2ecf20Sopenharmony_ci				continue;
16558c2ecf20Sopenharmony_ci		}
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci		/* this entry seems to match: same crc, not too old,
16588c2ecf20Sopenharmony_ci		 * and from another gw. therefore return true to forbid it.
16598c2ecf20Sopenharmony_ci		 */
16608c2ecf20Sopenharmony_ci		ret = true;
16618c2ecf20Sopenharmony_ci		goto out;
16628c2ecf20Sopenharmony_ci	}
16638c2ecf20Sopenharmony_ci	/* not found, add a new entry (overwrite the oldest entry)
16648c2ecf20Sopenharmony_ci	 * and allow it, its the first occurrence.
16658c2ecf20Sopenharmony_ci	 */
16668c2ecf20Sopenharmony_ci	curr = (bat_priv->bla.bcast_duplist_curr + BATADV_DUPLIST_SIZE - 1);
16678c2ecf20Sopenharmony_ci	curr %= BATADV_DUPLIST_SIZE;
16688c2ecf20Sopenharmony_ci	entry = &bat_priv->bla.bcast_duplist[curr];
16698c2ecf20Sopenharmony_ci	entry->crc = crc;
16708c2ecf20Sopenharmony_ci	entry->entrytime = jiffies;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	/* known originator */
16738c2ecf20Sopenharmony_ci	if (orig)
16748c2ecf20Sopenharmony_ci		ether_addr_copy(entry->orig, orig);
16758c2ecf20Sopenharmony_ci	/* anonymous originator */
16768c2ecf20Sopenharmony_ci	else
16778c2ecf20Sopenharmony_ci		eth_zero_addr(entry->orig);
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	bat_priv->bla.bcast_duplist_curr = curr;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ciout:
16828c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->bla.bcast_duplist_lock);
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	return ret;
16858c2ecf20Sopenharmony_ci}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci/**
16888c2ecf20Sopenharmony_ci * batadv_bla_check_ucast_duplist() - Check if a frame is in the broadcast dup.
16898c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
16908c2ecf20Sopenharmony_ci * @skb: contains the multicast packet to be checked, decapsulated from a
16918c2ecf20Sopenharmony_ci *  unicast_packet
16928c2ecf20Sopenharmony_ci *
16938c2ecf20Sopenharmony_ci * Check if it is on our broadcast list. Another gateway might have sent the
16948c2ecf20Sopenharmony_ci * same packet because it is connected to the same backbone, so we have to
16958c2ecf20Sopenharmony_ci * remove this duplicate.
16968c2ecf20Sopenharmony_ci *
16978c2ecf20Sopenharmony_ci * Return: true if a packet is in the duplicate list, false otherwise.
16988c2ecf20Sopenharmony_ci */
16998c2ecf20Sopenharmony_cistatic bool batadv_bla_check_ucast_duplist(struct batadv_priv *bat_priv,
17008c2ecf20Sopenharmony_ci					   struct sk_buff *skb)
17018c2ecf20Sopenharmony_ci{
17028c2ecf20Sopenharmony_ci	return batadv_bla_check_duplist(bat_priv, skb, (u8 *)skb->data, NULL);
17038c2ecf20Sopenharmony_ci}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci/**
17068c2ecf20Sopenharmony_ci * batadv_bla_check_bcast_duplist() - Check if a frame is in the broadcast dup.
17078c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
17088c2ecf20Sopenharmony_ci * @skb: contains the bcast_packet to be checked
17098c2ecf20Sopenharmony_ci *
17108c2ecf20Sopenharmony_ci * Check if it is on our broadcast list. Another gateway might have sent the
17118c2ecf20Sopenharmony_ci * same packet because it is connected to the same backbone, so we have to
17128c2ecf20Sopenharmony_ci * remove this duplicate.
17138c2ecf20Sopenharmony_ci *
17148c2ecf20Sopenharmony_ci * Return: true if a packet is in the duplicate list, false otherwise.
17158c2ecf20Sopenharmony_ci */
17168c2ecf20Sopenharmony_cibool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
17178c2ecf20Sopenharmony_ci				    struct sk_buff *skb)
17188c2ecf20Sopenharmony_ci{
17198c2ecf20Sopenharmony_ci	struct batadv_bcast_packet *bcast_packet;
17208c2ecf20Sopenharmony_ci	u8 *payload_ptr;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	bcast_packet = (struct batadv_bcast_packet *)skb->data;
17238c2ecf20Sopenharmony_ci	payload_ptr = (u8 *)(bcast_packet + 1);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	return batadv_bla_check_duplist(bat_priv, skb, payload_ptr,
17268c2ecf20Sopenharmony_ci					bcast_packet->orig);
17278c2ecf20Sopenharmony_ci}
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci/**
17308c2ecf20Sopenharmony_ci * batadv_bla_is_backbone_gw_orig() - Check if the originator is a gateway for
17318c2ecf20Sopenharmony_ci *  the VLAN identified by vid.
17328c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
17338c2ecf20Sopenharmony_ci * @orig: originator mac address
17348c2ecf20Sopenharmony_ci * @vid: VLAN identifier
17358c2ecf20Sopenharmony_ci *
17368c2ecf20Sopenharmony_ci * Return: true if orig is a backbone for this vid, false otherwise.
17378c2ecf20Sopenharmony_ci */
17388c2ecf20Sopenharmony_cibool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig,
17398c2ecf20Sopenharmony_ci				    unsigned short vid)
17408c2ecf20Sopenharmony_ci{
17418c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
17428c2ecf20Sopenharmony_ci	struct hlist_head *head;
17438c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
17448c2ecf20Sopenharmony_ci	int i;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
17478c2ecf20Sopenharmony_ci		return false;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	if (!hash)
17508c2ecf20Sopenharmony_ci		return false;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
17538c2ecf20Sopenharmony_ci		head = &hash->table[i];
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci		rcu_read_lock();
17568c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
17578c2ecf20Sopenharmony_ci			if (batadv_compare_eth(backbone_gw->orig, orig) &&
17588c2ecf20Sopenharmony_ci			    backbone_gw->vid == vid) {
17598c2ecf20Sopenharmony_ci				rcu_read_unlock();
17608c2ecf20Sopenharmony_ci				return true;
17618c2ecf20Sopenharmony_ci			}
17628c2ecf20Sopenharmony_ci		}
17638c2ecf20Sopenharmony_ci		rcu_read_unlock();
17648c2ecf20Sopenharmony_ci	}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	return false;
17678c2ecf20Sopenharmony_ci}
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci/**
17708c2ecf20Sopenharmony_ci * batadv_bla_is_backbone_gw() - check if originator is a backbone gw for a VLAN
17718c2ecf20Sopenharmony_ci * @skb: the frame to be checked
17728c2ecf20Sopenharmony_ci * @orig_node: the orig_node of the frame
17738c2ecf20Sopenharmony_ci * @hdr_size: maximum length of the frame
17748c2ecf20Sopenharmony_ci *
17758c2ecf20Sopenharmony_ci * Return: true if the orig_node is also a gateway on the soft interface,
17768c2ecf20Sopenharmony_ci * otherwise it returns false.
17778c2ecf20Sopenharmony_ci */
17788c2ecf20Sopenharmony_cibool batadv_bla_is_backbone_gw(struct sk_buff *skb,
17798c2ecf20Sopenharmony_ci			       struct batadv_orig_node *orig_node, int hdr_size)
17808c2ecf20Sopenharmony_ci{
17818c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
17828c2ecf20Sopenharmony_ci	unsigned short vid;
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))
17858c2ecf20Sopenharmony_ci		return false;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	/* first, find out the vid. */
17888c2ecf20Sopenharmony_ci	if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
17898c2ecf20Sopenharmony_ci		return false;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	vid = batadv_get_vid(skb, hdr_size);
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	/* see if this originator is a backbone gw for this VLAN */
17948c2ecf20Sopenharmony_ci	backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,
17958c2ecf20Sopenharmony_ci						orig_node->orig, vid);
17968c2ecf20Sopenharmony_ci	if (!backbone_gw)
17978c2ecf20Sopenharmony_ci		return false;
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
18008c2ecf20Sopenharmony_ci	return true;
18018c2ecf20Sopenharmony_ci}
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci/**
18048c2ecf20Sopenharmony_ci * batadv_bla_free() - free all bla structures
18058c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
18068c2ecf20Sopenharmony_ci *
18078c2ecf20Sopenharmony_ci * for softinterface free or module unload
18088c2ecf20Sopenharmony_ci */
18098c2ecf20Sopenharmony_civoid batadv_bla_free(struct batadv_priv *bat_priv)
18108c2ecf20Sopenharmony_ci{
18118c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&bat_priv->bla.work);
18148c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	if (bat_priv->bla.claim_hash) {
18178c2ecf20Sopenharmony_ci		batadv_bla_purge_claims(bat_priv, primary_if, 1);
18188c2ecf20Sopenharmony_ci		batadv_hash_destroy(bat_priv->bla.claim_hash);
18198c2ecf20Sopenharmony_ci		bat_priv->bla.claim_hash = NULL;
18208c2ecf20Sopenharmony_ci	}
18218c2ecf20Sopenharmony_ci	if (bat_priv->bla.backbone_hash) {
18228c2ecf20Sopenharmony_ci		batadv_bla_purge_backbone_gw(bat_priv, 1);
18238c2ecf20Sopenharmony_ci		batadv_hash_destroy(bat_priv->bla.backbone_hash);
18248c2ecf20Sopenharmony_ci		bat_priv->bla.backbone_hash = NULL;
18258c2ecf20Sopenharmony_ci	}
18268c2ecf20Sopenharmony_ci	if (primary_if)
18278c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
18288c2ecf20Sopenharmony_ci}
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci/**
18318c2ecf20Sopenharmony_ci * batadv_bla_loopdetect_check() - check and handle a detected loop
18328c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
18338c2ecf20Sopenharmony_ci * @skb: the packet to check
18348c2ecf20Sopenharmony_ci * @primary_if: interface where the request came on
18358c2ecf20Sopenharmony_ci * @vid: the VLAN ID of the frame
18368c2ecf20Sopenharmony_ci *
18378c2ecf20Sopenharmony_ci * Checks if this packet is a loop detect frame which has been sent by us,
18388c2ecf20Sopenharmony_ci * throws an uevent and logs the event if that is the case.
18398c2ecf20Sopenharmony_ci *
18408c2ecf20Sopenharmony_ci * Return: true if it is a loop detect frame which is to be dropped, false
18418c2ecf20Sopenharmony_ci * otherwise.
18428c2ecf20Sopenharmony_ci */
18438c2ecf20Sopenharmony_cistatic bool
18448c2ecf20Sopenharmony_cibatadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,
18458c2ecf20Sopenharmony_ci			    struct batadv_hard_iface *primary_if,
18468c2ecf20Sopenharmony_ci			    unsigned short vid)
18478c2ecf20Sopenharmony_ci{
18488c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
18498c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr;
18508c2ecf20Sopenharmony_ci	bool ret;
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	ethhdr = eth_hdr(skb);
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	/* Only check for the MAC address and skip more checks here for
18558c2ecf20Sopenharmony_ci	 * performance reasons - this function is on the hotpath, after all.
18568c2ecf20Sopenharmony_ci	 */
18578c2ecf20Sopenharmony_ci	if (!batadv_compare_eth(ethhdr->h_source,
18588c2ecf20Sopenharmony_ci				bat_priv->bla.loopdetect_addr))
18598c2ecf20Sopenharmony_ci		return false;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	/* If the packet came too late, don't forward it on the mesh
18628c2ecf20Sopenharmony_ci	 * but don't consider that as loop. It might be a coincidence.
18638c2ecf20Sopenharmony_ci	 */
18648c2ecf20Sopenharmony_ci	if (batadv_has_timed_out(bat_priv->bla.loopdetect_lasttime,
18658c2ecf20Sopenharmony_ci				 BATADV_BLA_LOOPDETECT_TIMEOUT))
18668c2ecf20Sopenharmony_ci		return true;
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	backbone_gw = batadv_bla_get_backbone_gw(bat_priv,
18698c2ecf20Sopenharmony_ci						 primary_if->net_dev->dev_addr,
18708c2ecf20Sopenharmony_ci						 vid, true);
18718c2ecf20Sopenharmony_ci	if (unlikely(!backbone_gw))
18728c2ecf20Sopenharmony_ci		return true;
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	ret = queue_work(batadv_event_workqueue, &backbone_gw->report_work);
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	/* backbone_gw is unreferenced in the report work function
18778c2ecf20Sopenharmony_ci	 * if queue_work() call was successful
18788c2ecf20Sopenharmony_ci	 */
18798c2ecf20Sopenharmony_ci	if (!ret)
18808c2ecf20Sopenharmony_ci		batadv_backbone_gw_put(backbone_gw);
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	return true;
18838c2ecf20Sopenharmony_ci}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci/**
18868c2ecf20Sopenharmony_ci * batadv_bla_rx() - check packets coming from the mesh.
18878c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
18888c2ecf20Sopenharmony_ci * @skb: the frame to be checked
18898c2ecf20Sopenharmony_ci * @vid: the VLAN ID of the frame
18908c2ecf20Sopenharmony_ci * @packet_type: the batman packet type this frame came in
18918c2ecf20Sopenharmony_ci *
18928c2ecf20Sopenharmony_ci * batadv_bla_rx avoidance checks if:
18938c2ecf20Sopenharmony_ci *  * we have to race for a claim
18948c2ecf20Sopenharmony_ci *  * if the frame is allowed on the LAN
18958c2ecf20Sopenharmony_ci *
18968c2ecf20Sopenharmony_ci * In these cases, the skb is further handled by this function
18978c2ecf20Sopenharmony_ci *
18988c2ecf20Sopenharmony_ci * Return: true if handled, otherwise it returns false and the caller shall
18998c2ecf20Sopenharmony_ci * further process the skb.
19008c2ecf20Sopenharmony_ci */
19018c2ecf20Sopenharmony_cibool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
19028c2ecf20Sopenharmony_ci		   unsigned short vid, int packet_type)
19038c2ecf20Sopenharmony_ci{
19048c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
19058c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr;
19068c2ecf20Sopenharmony_ci	struct batadv_bla_claim search_claim, *claim = NULL;
19078c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
19088c2ecf20Sopenharmony_ci	bool own_claim;
19098c2ecf20Sopenharmony_ci	bool ret;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	ethhdr = eth_hdr(skb);
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
19148c2ecf20Sopenharmony_ci	if (!primary_if)
19158c2ecf20Sopenharmony_ci		goto handled;
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
19188c2ecf20Sopenharmony_ci		goto allow;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	if (batadv_bla_loopdetect_check(bat_priv, skb, primary_if, vid))
19218c2ecf20Sopenharmony_ci		goto handled;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&bat_priv->bla.num_requests)))
19248c2ecf20Sopenharmony_ci		/* don't allow multicast packets while requests are in flight */
19258c2ecf20Sopenharmony_ci		if (is_multicast_ether_addr(ethhdr->h_dest))
19268c2ecf20Sopenharmony_ci			/* Both broadcast flooding or multicast-via-unicasts
19278c2ecf20Sopenharmony_ci			 * delivery might send to multiple backbone gateways
19288c2ecf20Sopenharmony_ci			 * sharing the same LAN and therefore need to coordinate
19298c2ecf20Sopenharmony_ci			 * which backbone gateway forwards into the LAN,
19308c2ecf20Sopenharmony_ci			 * by claiming the payload source address.
19318c2ecf20Sopenharmony_ci			 *
19328c2ecf20Sopenharmony_ci			 * Broadcast flooding and multicast-via-unicasts
19338c2ecf20Sopenharmony_ci			 * delivery use the following two batman packet types.
19348c2ecf20Sopenharmony_ci			 * Note: explicitly exclude BATADV_UNICAST_4ADDR,
19358c2ecf20Sopenharmony_ci			 * as the DHCP gateway feature will send explicitly
19368c2ecf20Sopenharmony_ci			 * to only one BLA gateway, so the claiming process
19378c2ecf20Sopenharmony_ci			 * should be avoided there.
19388c2ecf20Sopenharmony_ci			 */
19398c2ecf20Sopenharmony_ci			if (packet_type == BATADV_BCAST ||
19408c2ecf20Sopenharmony_ci			    packet_type == BATADV_UNICAST)
19418c2ecf20Sopenharmony_ci				goto handled;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	/* potential duplicates from foreign BLA backbone gateways via
19448c2ecf20Sopenharmony_ci	 * multicast-in-unicast packets
19458c2ecf20Sopenharmony_ci	 */
19468c2ecf20Sopenharmony_ci	if (is_multicast_ether_addr(ethhdr->h_dest) &&
19478c2ecf20Sopenharmony_ci	    packet_type == BATADV_UNICAST &&
19488c2ecf20Sopenharmony_ci	    batadv_bla_check_ucast_duplist(bat_priv, skb))
19498c2ecf20Sopenharmony_ci		goto handled;
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci	ether_addr_copy(search_claim.addr, ethhdr->h_source);
19528c2ecf20Sopenharmony_ci	search_claim.vid = vid;
19538c2ecf20Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	if (!claim) {
19568c2ecf20Sopenharmony_ci		/* possible optimization: race for a claim */
19578c2ecf20Sopenharmony_ci		/* No claim exists yet, claim it for us!
19588c2ecf20Sopenharmony_ci		 */
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
19618c2ecf20Sopenharmony_ci			   "%s(): Unclaimed MAC %pM found. Claim it. Local: %s\n",
19628c2ecf20Sopenharmony_ci			   __func__, ethhdr->h_source,
19638c2ecf20Sopenharmony_ci			   batadv_is_my_client(bat_priv,
19648c2ecf20Sopenharmony_ci					       ethhdr->h_source, vid) ?
19658c2ecf20Sopenharmony_ci			   "yes" : "no");
19668c2ecf20Sopenharmony_ci		batadv_handle_claim(bat_priv, primary_if,
19678c2ecf20Sopenharmony_ci				    primary_if->net_dev->dev_addr,
19688c2ecf20Sopenharmony_ci				    ethhdr->h_source, vid);
19698c2ecf20Sopenharmony_ci		goto allow;
19708c2ecf20Sopenharmony_ci	}
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	/* if it is our own claim ... */
19738c2ecf20Sopenharmony_ci	backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
19748c2ecf20Sopenharmony_ci	own_claim = batadv_compare_eth(backbone_gw->orig,
19758c2ecf20Sopenharmony_ci				       primary_if->net_dev->dev_addr);
19768c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	if (own_claim) {
19798c2ecf20Sopenharmony_ci		/* ... allow it in any case */
19808c2ecf20Sopenharmony_ci		claim->lasttime = jiffies;
19818c2ecf20Sopenharmony_ci		goto allow;
19828c2ecf20Sopenharmony_ci	}
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	/* if it is a multicast ... */
19858c2ecf20Sopenharmony_ci	if (is_multicast_ether_addr(ethhdr->h_dest) &&
19868c2ecf20Sopenharmony_ci	    (packet_type == BATADV_BCAST || packet_type == BATADV_UNICAST)) {
19878c2ecf20Sopenharmony_ci		/* ... drop it. the responsible gateway is in charge.
19888c2ecf20Sopenharmony_ci		 *
19898c2ecf20Sopenharmony_ci		 * We need to check packet type because with the gateway
19908c2ecf20Sopenharmony_ci		 * feature, broadcasts (like DHCP requests) may be sent
19918c2ecf20Sopenharmony_ci		 * using a unicast 4 address packet type. See comment above.
19928c2ecf20Sopenharmony_ci		 */
19938c2ecf20Sopenharmony_ci		goto handled;
19948c2ecf20Sopenharmony_ci	} else {
19958c2ecf20Sopenharmony_ci		/* seems the client considers us as its best gateway.
19968c2ecf20Sopenharmony_ci		 * send a claim and update the claim table
19978c2ecf20Sopenharmony_ci		 * immediately.
19988c2ecf20Sopenharmony_ci		 */
19998c2ecf20Sopenharmony_ci		batadv_handle_claim(bat_priv, primary_if,
20008c2ecf20Sopenharmony_ci				    primary_if->net_dev->dev_addr,
20018c2ecf20Sopenharmony_ci				    ethhdr->h_source, vid);
20028c2ecf20Sopenharmony_ci		goto allow;
20038c2ecf20Sopenharmony_ci	}
20048c2ecf20Sopenharmony_ciallow:
20058c2ecf20Sopenharmony_ci	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
20068c2ecf20Sopenharmony_ci	ret = false;
20078c2ecf20Sopenharmony_ci	goto out;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_cihandled:
20108c2ecf20Sopenharmony_ci	kfree_skb(skb);
20118c2ecf20Sopenharmony_ci	ret = true;
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ciout:
20148c2ecf20Sopenharmony_ci	if (primary_if)
20158c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
20168c2ecf20Sopenharmony_ci	if (claim)
20178c2ecf20Sopenharmony_ci		batadv_claim_put(claim);
20188c2ecf20Sopenharmony_ci	return ret;
20198c2ecf20Sopenharmony_ci}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci/**
20228c2ecf20Sopenharmony_ci * batadv_bla_tx() - check packets going into the mesh
20238c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
20248c2ecf20Sopenharmony_ci * @skb: the frame to be checked
20258c2ecf20Sopenharmony_ci * @vid: the VLAN ID of the frame
20268c2ecf20Sopenharmony_ci *
20278c2ecf20Sopenharmony_ci * batadv_bla_tx checks if:
20288c2ecf20Sopenharmony_ci *  * a claim was received which has to be processed
20298c2ecf20Sopenharmony_ci *  * the frame is allowed on the mesh
20308c2ecf20Sopenharmony_ci *
20318c2ecf20Sopenharmony_ci * in these cases, the skb is further handled by this function.
20328c2ecf20Sopenharmony_ci *
20338c2ecf20Sopenharmony_ci * This call might reallocate skb data.
20348c2ecf20Sopenharmony_ci *
20358c2ecf20Sopenharmony_ci * Return: true if handled, otherwise it returns false and the caller shall
20368c2ecf20Sopenharmony_ci * further process the skb.
20378c2ecf20Sopenharmony_ci */
20388c2ecf20Sopenharmony_cibool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
20398c2ecf20Sopenharmony_ci		   unsigned short vid)
20408c2ecf20Sopenharmony_ci{
20418c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr;
20428c2ecf20Sopenharmony_ci	struct batadv_bla_claim search_claim, *claim = NULL;
20438c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
20448c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
20458c2ecf20Sopenharmony_ci	bool client_roamed;
20468c2ecf20Sopenharmony_ci	bool ret = false;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
20498c2ecf20Sopenharmony_ci	if (!primary_if)
20508c2ecf20Sopenharmony_ci		goto out;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
20538c2ecf20Sopenharmony_ci		goto allow;
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci	if (batadv_bla_process_claim(bat_priv, primary_if, skb))
20568c2ecf20Sopenharmony_ci		goto handled;
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	ethhdr = eth_hdr(skb);
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&bat_priv->bla.num_requests)))
20618c2ecf20Sopenharmony_ci		/* don't allow broadcasts while requests are in flight */
20628c2ecf20Sopenharmony_ci		if (is_multicast_ether_addr(ethhdr->h_dest))
20638c2ecf20Sopenharmony_ci			goto handled;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	ether_addr_copy(search_claim.addr, ethhdr->h_source);
20668c2ecf20Sopenharmony_ci	search_claim.vid = vid;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	/* if no claim exists, allow it. */
20718c2ecf20Sopenharmony_ci	if (!claim)
20728c2ecf20Sopenharmony_ci		goto allow;
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	/* check if we are responsible. */
20758c2ecf20Sopenharmony_ci	backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
20768c2ecf20Sopenharmony_ci	client_roamed = batadv_compare_eth(backbone_gw->orig,
20778c2ecf20Sopenharmony_ci					   primary_if->net_dev->dev_addr);
20788c2ecf20Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	if (client_roamed) {
20818c2ecf20Sopenharmony_ci		/* if yes, the client has roamed and we have
20828c2ecf20Sopenharmony_ci		 * to unclaim it.
20838c2ecf20Sopenharmony_ci		 */
20848c2ecf20Sopenharmony_ci		if (batadv_has_timed_out(claim->lasttime, 100)) {
20858c2ecf20Sopenharmony_ci			/* only unclaim if the last claim entry is
20868c2ecf20Sopenharmony_ci			 * older than 100 ms to make sure we really
20878c2ecf20Sopenharmony_ci			 * have a roaming client here.
20888c2ecf20Sopenharmony_ci			 */
20898c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Roaming client %pM detected. Unclaim it.\n",
20908c2ecf20Sopenharmony_ci				   __func__, ethhdr->h_source);
20918c2ecf20Sopenharmony_ci			batadv_handle_unclaim(bat_priv, primary_if,
20928c2ecf20Sopenharmony_ci					      primary_if->net_dev->dev_addr,
20938c2ecf20Sopenharmony_ci					      ethhdr->h_source, vid);
20948c2ecf20Sopenharmony_ci			goto allow;
20958c2ecf20Sopenharmony_ci		} else {
20968c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Race for claim %pM detected. Drop packet.\n",
20978c2ecf20Sopenharmony_ci				   __func__, ethhdr->h_source);
20988c2ecf20Sopenharmony_ci			goto handled;
20998c2ecf20Sopenharmony_ci		}
21008c2ecf20Sopenharmony_ci	}
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	/* check if it is a multicast/broadcast frame */
21038c2ecf20Sopenharmony_ci	if (is_multicast_ether_addr(ethhdr->h_dest)) {
21048c2ecf20Sopenharmony_ci		/* drop it. the responsible gateway has forwarded it into
21058c2ecf20Sopenharmony_ci		 * the backbone network.
21068c2ecf20Sopenharmony_ci		 */
21078c2ecf20Sopenharmony_ci		goto handled;
21088c2ecf20Sopenharmony_ci	} else {
21098c2ecf20Sopenharmony_ci		/* we must allow it. at least if we are
21108c2ecf20Sopenharmony_ci		 * responsible for the DESTINATION.
21118c2ecf20Sopenharmony_ci		 */
21128c2ecf20Sopenharmony_ci		goto allow;
21138c2ecf20Sopenharmony_ci	}
21148c2ecf20Sopenharmony_ciallow:
21158c2ecf20Sopenharmony_ci	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
21168c2ecf20Sopenharmony_ci	ret = false;
21178c2ecf20Sopenharmony_ci	goto out;
21188c2ecf20Sopenharmony_cihandled:
21198c2ecf20Sopenharmony_ci	ret = true;
21208c2ecf20Sopenharmony_ciout:
21218c2ecf20Sopenharmony_ci	if (primary_if)
21228c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
21238c2ecf20Sopenharmony_ci	if (claim)
21248c2ecf20Sopenharmony_ci		batadv_claim_put(claim);
21258c2ecf20Sopenharmony_ci	return ret;
21268c2ecf20Sopenharmony_ci}
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS
21298c2ecf20Sopenharmony_ci/**
21308c2ecf20Sopenharmony_ci * batadv_bla_claim_table_seq_print_text() - print the claim table in a seq file
21318c2ecf20Sopenharmony_ci * @seq: seq file to print on
21328c2ecf20Sopenharmony_ci * @offset: not used
21338c2ecf20Sopenharmony_ci *
21348c2ecf20Sopenharmony_ci * Return: always 0
21358c2ecf20Sopenharmony_ci */
21368c2ecf20Sopenharmony_ciint batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
21378c2ecf20Sopenharmony_ci{
21388c2ecf20Sopenharmony_ci	struct net_device *net_dev = (struct net_device *)seq->private;
21398c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(net_dev);
21408c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->bla.claim_hash;
21418c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
21428c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim;
21438c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
21448c2ecf20Sopenharmony_ci	struct hlist_head *head;
21458c2ecf20Sopenharmony_ci	u16 backbone_crc;
21468c2ecf20Sopenharmony_ci	u32 i;
21478c2ecf20Sopenharmony_ci	bool is_own;
21488c2ecf20Sopenharmony_ci	u8 *primary_addr;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	primary_if = batadv_seq_print_text_primary_if_get(seq);
21518c2ecf20Sopenharmony_ci	if (!primary_if)
21528c2ecf20Sopenharmony_ci		goto out;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	primary_addr = primary_if->net_dev->dev_addr;
21558c2ecf20Sopenharmony_ci	seq_printf(seq,
21568c2ecf20Sopenharmony_ci		   "Claims announced for the mesh %s (orig %pM, group id %#.4x)\n",
21578c2ecf20Sopenharmony_ci		   net_dev->name, primary_addr,
21588c2ecf20Sopenharmony_ci		   ntohs(bat_priv->bla.claim_dest.group));
21598c2ecf20Sopenharmony_ci	seq_puts(seq,
21608c2ecf20Sopenharmony_ci		 "   Client               VID      Originator        [o] (CRC   )\n");
21618c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
21628c2ecf20Sopenharmony_ci		head = &hash->table[i];
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci		rcu_read_lock();
21658c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(claim, head, hash_entry) {
21668c2ecf20Sopenharmony_ci			backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci			is_own = batadv_compare_eth(backbone_gw->orig,
21698c2ecf20Sopenharmony_ci						    primary_addr);
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci			spin_lock_bh(&backbone_gw->crc_lock);
21728c2ecf20Sopenharmony_ci			backbone_crc = backbone_gw->crc;
21738c2ecf20Sopenharmony_ci			spin_unlock_bh(&backbone_gw->crc_lock);
21748c2ecf20Sopenharmony_ci			seq_printf(seq, " * %pM on %5d by %pM [%c] (%#.4x)\n",
21758c2ecf20Sopenharmony_ci				   claim->addr, batadv_print_vid(claim->vid),
21768c2ecf20Sopenharmony_ci				   backbone_gw->orig,
21778c2ecf20Sopenharmony_ci				   (is_own ? 'x' : ' '),
21788c2ecf20Sopenharmony_ci				   backbone_crc);
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci			batadv_backbone_gw_put(backbone_gw);
21818c2ecf20Sopenharmony_ci		}
21828c2ecf20Sopenharmony_ci		rcu_read_unlock();
21838c2ecf20Sopenharmony_ci	}
21848c2ecf20Sopenharmony_ciout:
21858c2ecf20Sopenharmony_ci	if (primary_if)
21868c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
21878c2ecf20Sopenharmony_ci	return 0;
21888c2ecf20Sopenharmony_ci}
21898c2ecf20Sopenharmony_ci#endif
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci/**
21928c2ecf20Sopenharmony_ci * batadv_bla_claim_dump_entry() - dump one entry of the claim table
21938c2ecf20Sopenharmony_ci * to a netlink socket
21948c2ecf20Sopenharmony_ci * @msg: buffer for the message
21958c2ecf20Sopenharmony_ci * @portid: netlink port
21968c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
21978c2ecf20Sopenharmony_ci * @primary_if: primary interface
21988c2ecf20Sopenharmony_ci * @claim: entry to dump
21998c2ecf20Sopenharmony_ci *
22008c2ecf20Sopenharmony_ci * Return: 0 or error code.
22018c2ecf20Sopenharmony_ci */
22028c2ecf20Sopenharmony_cistatic int
22038c2ecf20Sopenharmony_cibatadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,
22048c2ecf20Sopenharmony_ci			    struct netlink_callback *cb,
22058c2ecf20Sopenharmony_ci			    struct batadv_hard_iface *primary_if,
22068c2ecf20Sopenharmony_ci			    struct batadv_bla_claim *claim)
22078c2ecf20Sopenharmony_ci{
22088c2ecf20Sopenharmony_ci	u8 *primary_addr = primary_if->net_dev->dev_addr;
22098c2ecf20Sopenharmony_ci	u16 backbone_crc;
22108c2ecf20Sopenharmony_ci	bool is_own;
22118c2ecf20Sopenharmony_ci	void *hdr;
22128c2ecf20Sopenharmony_ci	int ret = -EINVAL;
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
22158c2ecf20Sopenharmony_ci			  &batadv_netlink_family, NLM_F_MULTI,
22168c2ecf20Sopenharmony_ci			  BATADV_CMD_GET_BLA_CLAIM);
22178c2ecf20Sopenharmony_ci	if (!hdr) {
22188c2ecf20Sopenharmony_ci		ret = -ENOBUFS;
22198c2ecf20Sopenharmony_ci		goto out;
22208c2ecf20Sopenharmony_ci	}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	genl_dump_check_consistent(cb, hdr);
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci	is_own = batadv_compare_eth(claim->backbone_gw->orig,
22258c2ecf20Sopenharmony_ci				    primary_addr);
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	spin_lock_bh(&claim->backbone_gw->crc_lock);
22288c2ecf20Sopenharmony_ci	backbone_crc = claim->backbone_gw->crc;
22298c2ecf20Sopenharmony_ci	spin_unlock_bh(&claim->backbone_gw->crc_lock);
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	if (is_own)
22328c2ecf20Sopenharmony_ci		if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
22338c2ecf20Sopenharmony_ci			genlmsg_cancel(msg, hdr);
22348c2ecf20Sopenharmony_ci			goto out;
22358c2ecf20Sopenharmony_ci		}
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	if (nla_put(msg, BATADV_ATTR_BLA_ADDRESS, ETH_ALEN, claim->addr) ||
22388c2ecf20Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_BLA_VID, claim->vid) ||
22398c2ecf20Sopenharmony_ci	    nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,
22408c2ecf20Sopenharmony_ci		    claim->backbone_gw->orig) ||
22418c2ecf20Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
22428c2ecf20Sopenharmony_ci			backbone_crc)) {
22438c2ecf20Sopenharmony_ci		genlmsg_cancel(msg, hdr);
22448c2ecf20Sopenharmony_ci		goto out;
22458c2ecf20Sopenharmony_ci	}
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
22488c2ecf20Sopenharmony_ci	ret = 0;
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ciout:
22518c2ecf20Sopenharmony_ci	return ret;
22528c2ecf20Sopenharmony_ci}
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci/**
22558c2ecf20Sopenharmony_ci * batadv_bla_claim_dump_bucket() - dump one bucket of the claim table
22568c2ecf20Sopenharmony_ci * to a netlink socket
22578c2ecf20Sopenharmony_ci * @msg: buffer for the message
22588c2ecf20Sopenharmony_ci * @portid: netlink port
22598c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
22608c2ecf20Sopenharmony_ci * @primary_if: primary interface
22618c2ecf20Sopenharmony_ci * @hash: hash to dump
22628c2ecf20Sopenharmony_ci * @bucket: bucket index to dump
22638c2ecf20Sopenharmony_ci * @idx_skip: How many entries to skip
22648c2ecf20Sopenharmony_ci *
22658c2ecf20Sopenharmony_ci * Return: always 0.
22668c2ecf20Sopenharmony_ci */
22678c2ecf20Sopenharmony_cistatic int
22688c2ecf20Sopenharmony_cibatadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid,
22698c2ecf20Sopenharmony_ci			     struct netlink_callback *cb,
22708c2ecf20Sopenharmony_ci			     struct batadv_hard_iface *primary_if,
22718c2ecf20Sopenharmony_ci			     struct batadv_hashtable *hash, unsigned int bucket,
22728c2ecf20Sopenharmony_ci			     int *idx_skip)
22738c2ecf20Sopenharmony_ci{
22748c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim;
22758c2ecf20Sopenharmony_ci	int idx = 0;
22768c2ecf20Sopenharmony_ci	int ret = 0;
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	spin_lock_bh(&hash->list_locks[bucket]);
22798c2ecf20Sopenharmony_ci	cb->seq = atomic_read(&hash->generation) << 1 | 1;
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	hlist_for_each_entry(claim, &hash->table[bucket], hash_entry) {
22828c2ecf20Sopenharmony_ci		if (idx++ < *idx_skip)
22838c2ecf20Sopenharmony_ci			continue;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci		ret = batadv_bla_claim_dump_entry(msg, portid, cb,
22868c2ecf20Sopenharmony_ci						  primary_if, claim);
22878c2ecf20Sopenharmony_ci		if (ret) {
22888c2ecf20Sopenharmony_ci			*idx_skip = idx - 1;
22898c2ecf20Sopenharmony_ci			goto unlock;
22908c2ecf20Sopenharmony_ci		}
22918c2ecf20Sopenharmony_ci	}
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci	*idx_skip = 0;
22948c2ecf20Sopenharmony_ciunlock:
22958c2ecf20Sopenharmony_ci	spin_unlock_bh(&hash->list_locks[bucket]);
22968c2ecf20Sopenharmony_ci	return ret;
22978c2ecf20Sopenharmony_ci}
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci/**
23008c2ecf20Sopenharmony_ci * batadv_bla_claim_dump() - dump claim table to a netlink socket
23018c2ecf20Sopenharmony_ci * @msg: buffer for the message
23028c2ecf20Sopenharmony_ci * @cb: callback structure containing arguments
23038c2ecf20Sopenharmony_ci *
23048c2ecf20Sopenharmony_ci * Return: message length.
23058c2ecf20Sopenharmony_ci */
23068c2ecf20Sopenharmony_ciint batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)
23078c2ecf20Sopenharmony_ci{
23088c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
23098c2ecf20Sopenharmony_ci	int portid = NETLINK_CB(cb->skb).portid;
23108c2ecf20Sopenharmony_ci	struct net *net = sock_net(cb->skb->sk);
23118c2ecf20Sopenharmony_ci	struct net_device *soft_iface;
23128c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
23138c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
23148c2ecf20Sopenharmony_ci	int bucket = cb->args[0];
23158c2ecf20Sopenharmony_ci	int idx = cb->args[1];
23168c2ecf20Sopenharmony_ci	int ifindex;
23178c2ecf20Sopenharmony_ci	int ret = 0;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	ifindex = batadv_netlink_get_ifindex(cb->nlh,
23208c2ecf20Sopenharmony_ci					     BATADV_ATTR_MESH_IFINDEX);
23218c2ecf20Sopenharmony_ci	if (!ifindex)
23228c2ecf20Sopenharmony_ci		return -EINVAL;
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci	soft_iface = dev_get_by_index(net, ifindex);
23258c2ecf20Sopenharmony_ci	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
23268c2ecf20Sopenharmony_ci		ret = -ENODEV;
23278c2ecf20Sopenharmony_ci		goto out;
23288c2ecf20Sopenharmony_ci	}
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	bat_priv = netdev_priv(soft_iface);
23318c2ecf20Sopenharmony_ci	hash = bat_priv->bla.claim_hash;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
23348c2ecf20Sopenharmony_ci	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
23358c2ecf20Sopenharmony_ci		ret = -ENOENT;
23368c2ecf20Sopenharmony_ci		goto out;
23378c2ecf20Sopenharmony_ci	}
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	while (bucket < hash->size) {
23408c2ecf20Sopenharmony_ci		if (batadv_bla_claim_dump_bucket(msg, portid, cb, primary_if,
23418c2ecf20Sopenharmony_ci						 hash, bucket, &idx))
23428c2ecf20Sopenharmony_ci			break;
23438c2ecf20Sopenharmony_ci		bucket++;
23448c2ecf20Sopenharmony_ci	}
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	cb->args[0] = bucket;
23478c2ecf20Sopenharmony_ci	cb->args[1] = idx;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	ret = msg->len;
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ciout:
23528c2ecf20Sopenharmony_ci	if (primary_if)
23538c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	if (soft_iface)
23568c2ecf20Sopenharmony_ci		dev_put(soft_iface);
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	return ret;
23598c2ecf20Sopenharmony_ci}
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS
23628c2ecf20Sopenharmony_ci/**
23638c2ecf20Sopenharmony_ci * batadv_bla_backbone_table_seq_print_text() - print the backbone table in a
23648c2ecf20Sopenharmony_ci *  seq file
23658c2ecf20Sopenharmony_ci * @seq: seq file to print on
23668c2ecf20Sopenharmony_ci * @offset: not used
23678c2ecf20Sopenharmony_ci *
23688c2ecf20Sopenharmony_ci * Return: always 0
23698c2ecf20Sopenharmony_ci */
23708c2ecf20Sopenharmony_ciint batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset)
23718c2ecf20Sopenharmony_ci{
23728c2ecf20Sopenharmony_ci	struct net_device *net_dev = (struct net_device *)seq->private;
23738c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(net_dev);
23748c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
23758c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
23768c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
23778c2ecf20Sopenharmony_ci	struct hlist_head *head;
23788c2ecf20Sopenharmony_ci	int secs, msecs;
23798c2ecf20Sopenharmony_ci	u16 backbone_crc;
23808c2ecf20Sopenharmony_ci	u32 i;
23818c2ecf20Sopenharmony_ci	bool is_own;
23828c2ecf20Sopenharmony_ci	u8 *primary_addr;
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci	primary_if = batadv_seq_print_text_primary_if_get(seq);
23858c2ecf20Sopenharmony_ci	if (!primary_if)
23868c2ecf20Sopenharmony_ci		goto out;
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	primary_addr = primary_if->net_dev->dev_addr;
23898c2ecf20Sopenharmony_ci	seq_printf(seq,
23908c2ecf20Sopenharmony_ci		   "Backbones announced for the mesh %s (orig %pM, group id %#.4x)\n",
23918c2ecf20Sopenharmony_ci		   net_dev->name, primary_addr,
23928c2ecf20Sopenharmony_ci		   ntohs(bat_priv->bla.claim_dest.group));
23938c2ecf20Sopenharmony_ci	seq_puts(seq, "   Originator           VID   last seen (CRC   )\n");
23948c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
23958c2ecf20Sopenharmony_ci		head = &hash->table[i];
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci		rcu_read_lock();
23988c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
23998c2ecf20Sopenharmony_ci			msecs = jiffies_to_msecs(jiffies -
24008c2ecf20Sopenharmony_ci						 backbone_gw->lasttime);
24018c2ecf20Sopenharmony_ci			secs = msecs / 1000;
24028c2ecf20Sopenharmony_ci			msecs = msecs % 1000;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci			is_own = batadv_compare_eth(backbone_gw->orig,
24058c2ecf20Sopenharmony_ci						    primary_addr);
24068c2ecf20Sopenharmony_ci			if (is_own)
24078c2ecf20Sopenharmony_ci				continue;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci			spin_lock_bh(&backbone_gw->crc_lock);
24108c2ecf20Sopenharmony_ci			backbone_crc = backbone_gw->crc;
24118c2ecf20Sopenharmony_ci			spin_unlock_bh(&backbone_gw->crc_lock);
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci			seq_printf(seq, " * %pM on %5d %4i.%03is (%#.4x)\n",
24148c2ecf20Sopenharmony_ci				   backbone_gw->orig,
24158c2ecf20Sopenharmony_ci				   batadv_print_vid(backbone_gw->vid), secs,
24168c2ecf20Sopenharmony_ci				   msecs, backbone_crc);
24178c2ecf20Sopenharmony_ci		}
24188c2ecf20Sopenharmony_ci		rcu_read_unlock();
24198c2ecf20Sopenharmony_ci	}
24208c2ecf20Sopenharmony_ciout:
24218c2ecf20Sopenharmony_ci	if (primary_if)
24228c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
24238c2ecf20Sopenharmony_ci	return 0;
24248c2ecf20Sopenharmony_ci}
24258c2ecf20Sopenharmony_ci#endif
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci/**
24288c2ecf20Sopenharmony_ci * batadv_bla_backbone_dump_entry() - dump one entry of the backbone table to a
24298c2ecf20Sopenharmony_ci *  netlink socket
24308c2ecf20Sopenharmony_ci * @msg: buffer for the message
24318c2ecf20Sopenharmony_ci * @portid: netlink port
24328c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
24338c2ecf20Sopenharmony_ci * @primary_if: primary interface
24348c2ecf20Sopenharmony_ci * @backbone_gw: entry to dump
24358c2ecf20Sopenharmony_ci *
24368c2ecf20Sopenharmony_ci * Return: 0 or error code.
24378c2ecf20Sopenharmony_ci */
24388c2ecf20Sopenharmony_cistatic int
24398c2ecf20Sopenharmony_cibatadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid,
24408c2ecf20Sopenharmony_ci			       struct netlink_callback *cb,
24418c2ecf20Sopenharmony_ci			       struct batadv_hard_iface *primary_if,
24428c2ecf20Sopenharmony_ci			       struct batadv_bla_backbone_gw *backbone_gw)
24438c2ecf20Sopenharmony_ci{
24448c2ecf20Sopenharmony_ci	u8 *primary_addr = primary_if->net_dev->dev_addr;
24458c2ecf20Sopenharmony_ci	u16 backbone_crc;
24468c2ecf20Sopenharmony_ci	bool is_own;
24478c2ecf20Sopenharmony_ci	int msecs;
24488c2ecf20Sopenharmony_ci	void *hdr;
24498c2ecf20Sopenharmony_ci	int ret = -EINVAL;
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
24528c2ecf20Sopenharmony_ci			  &batadv_netlink_family, NLM_F_MULTI,
24538c2ecf20Sopenharmony_ci			  BATADV_CMD_GET_BLA_BACKBONE);
24548c2ecf20Sopenharmony_ci	if (!hdr) {
24558c2ecf20Sopenharmony_ci		ret = -ENOBUFS;
24568c2ecf20Sopenharmony_ci		goto out;
24578c2ecf20Sopenharmony_ci	}
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	genl_dump_check_consistent(cb, hdr);
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	is_own = batadv_compare_eth(backbone_gw->orig, primary_addr);
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
24648c2ecf20Sopenharmony_ci	backbone_crc = backbone_gw->crc;
24658c2ecf20Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	msecs = jiffies_to_msecs(jiffies - backbone_gw->lasttime);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	if (is_own)
24708c2ecf20Sopenharmony_ci		if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
24718c2ecf20Sopenharmony_ci			genlmsg_cancel(msg, hdr);
24728c2ecf20Sopenharmony_ci			goto out;
24738c2ecf20Sopenharmony_ci		}
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	if (nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,
24768c2ecf20Sopenharmony_ci		    backbone_gw->orig) ||
24778c2ecf20Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_BLA_VID, backbone_gw->vid) ||
24788c2ecf20Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
24798c2ecf20Sopenharmony_ci			backbone_crc) ||
24808c2ecf20Sopenharmony_ci	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {
24818c2ecf20Sopenharmony_ci		genlmsg_cancel(msg, hdr);
24828c2ecf20Sopenharmony_ci		goto out;
24838c2ecf20Sopenharmony_ci	}
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
24868c2ecf20Sopenharmony_ci	ret = 0;
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ciout:
24898c2ecf20Sopenharmony_ci	return ret;
24908c2ecf20Sopenharmony_ci}
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci/**
24938c2ecf20Sopenharmony_ci * batadv_bla_backbone_dump_bucket() - dump one bucket of the backbone table to
24948c2ecf20Sopenharmony_ci *  a netlink socket
24958c2ecf20Sopenharmony_ci * @msg: buffer for the message
24968c2ecf20Sopenharmony_ci * @portid: netlink port
24978c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
24988c2ecf20Sopenharmony_ci * @primary_if: primary interface
24998c2ecf20Sopenharmony_ci * @hash: hash to dump
25008c2ecf20Sopenharmony_ci * @bucket: bucket index to dump
25018c2ecf20Sopenharmony_ci * @idx_skip: How many entries to skip
25028c2ecf20Sopenharmony_ci *
25038c2ecf20Sopenharmony_ci * Return: always 0.
25048c2ecf20Sopenharmony_ci */
25058c2ecf20Sopenharmony_cistatic int
25068c2ecf20Sopenharmony_cibatadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid,
25078c2ecf20Sopenharmony_ci				struct netlink_callback *cb,
25088c2ecf20Sopenharmony_ci				struct batadv_hard_iface *primary_if,
25098c2ecf20Sopenharmony_ci				struct batadv_hashtable *hash,
25108c2ecf20Sopenharmony_ci				unsigned int bucket, int *idx_skip)
25118c2ecf20Sopenharmony_ci{
25128c2ecf20Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
25138c2ecf20Sopenharmony_ci	int idx = 0;
25148c2ecf20Sopenharmony_ci	int ret = 0;
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	spin_lock_bh(&hash->list_locks[bucket]);
25178c2ecf20Sopenharmony_ci	cb->seq = atomic_read(&hash->generation) << 1 | 1;
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	hlist_for_each_entry(backbone_gw, &hash->table[bucket], hash_entry) {
25208c2ecf20Sopenharmony_ci		if (idx++ < *idx_skip)
25218c2ecf20Sopenharmony_ci			continue;
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci		ret = batadv_bla_backbone_dump_entry(msg, portid, cb,
25248c2ecf20Sopenharmony_ci						     primary_if, backbone_gw);
25258c2ecf20Sopenharmony_ci		if (ret) {
25268c2ecf20Sopenharmony_ci			*idx_skip = idx - 1;
25278c2ecf20Sopenharmony_ci			goto unlock;
25288c2ecf20Sopenharmony_ci		}
25298c2ecf20Sopenharmony_ci	}
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	*idx_skip = 0;
25328c2ecf20Sopenharmony_ciunlock:
25338c2ecf20Sopenharmony_ci	spin_unlock_bh(&hash->list_locks[bucket]);
25348c2ecf20Sopenharmony_ci	return ret;
25358c2ecf20Sopenharmony_ci}
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci/**
25388c2ecf20Sopenharmony_ci * batadv_bla_backbone_dump() - dump backbone table to a netlink socket
25398c2ecf20Sopenharmony_ci * @msg: buffer for the message
25408c2ecf20Sopenharmony_ci * @cb: callback structure containing arguments
25418c2ecf20Sopenharmony_ci *
25428c2ecf20Sopenharmony_ci * Return: message length.
25438c2ecf20Sopenharmony_ci */
25448c2ecf20Sopenharmony_ciint batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)
25458c2ecf20Sopenharmony_ci{
25468c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
25478c2ecf20Sopenharmony_ci	int portid = NETLINK_CB(cb->skb).portid;
25488c2ecf20Sopenharmony_ci	struct net *net = sock_net(cb->skb->sk);
25498c2ecf20Sopenharmony_ci	struct net_device *soft_iface;
25508c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
25518c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
25528c2ecf20Sopenharmony_ci	int bucket = cb->args[0];
25538c2ecf20Sopenharmony_ci	int idx = cb->args[1];
25548c2ecf20Sopenharmony_ci	int ifindex;
25558c2ecf20Sopenharmony_ci	int ret = 0;
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci	ifindex = batadv_netlink_get_ifindex(cb->nlh,
25588c2ecf20Sopenharmony_ci					     BATADV_ATTR_MESH_IFINDEX);
25598c2ecf20Sopenharmony_ci	if (!ifindex)
25608c2ecf20Sopenharmony_ci		return -EINVAL;
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	soft_iface = dev_get_by_index(net, ifindex);
25638c2ecf20Sopenharmony_ci	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
25648c2ecf20Sopenharmony_ci		ret = -ENODEV;
25658c2ecf20Sopenharmony_ci		goto out;
25668c2ecf20Sopenharmony_ci	}
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	bat_priv = netdev_priv(soft_iface);
25698c2ecf20Sopenharmony_ci	hash = bat_priv->bla.backbone_hash;
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
25728c2ecf20Sopenharmony_ci	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
25738c2ecf20Sopenharmony_ci		ret = -ENOENT;
25748c2ecf20Sopenharmony_ci		goto out;
25758c2ecf20Sopenharmony_ci	}
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	while (bucket < hash->size) {
25788c2ecf20Sopenharmony_ci		if (batadv_bla_backbone_dump_bucket(msg, portid, cb, primary_if,
25798c2ecf20Sopenharmony_ci						    hash, bucket, &idx))
25808c2ecf20Sopenharmony_ci			break;
25818c2ecf20Sopenharmony_ci		bucket++;
25828c2ecf20Sopenharmony_ci	}
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	cb->args[0] = bucket;
25858c2ecf20Sopenharmony_ci	cb->args[1] = idx;
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci	ret = msg->len;
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ciout:
25908c2ecf20Sopenharmony_ci	if (primary_if)
25918c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci	if (soft_iface)
25948c2ecf20Sopenharmony_ci		dev_put(soft_iface);
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	return ret;
25978c2ecf20Sopenharmony_ci}
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DAT
26008c2ecf20Sopenharmony_ci/**
26018c2ecf20Sopenharmony_ci * batadv_bla_check_claim() - check if address is claimed
26028c2ecf20Sopenharmony_ci *
26038c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
26048c2ecf20Sopenharmony_ci * @addr: mac address of which the claim status is checked
26058c2ecf20Sopenharmony_ci * @vid: the VLAN ID
26068c2ecf20Sopenharmony_ci *
26078c2ecf20Sopenharmony_ci * addr is checked if this address is claimed by the local device itself.
26088c2ecf20Sopenharmony_ci *
26098c2ecf20Sopenharmony_ci * Return: true if bla is disabled or the mac is claimed by the device,
26108c2ecf20Sopenharmony_ci * false if the device addr is already claimed by another gateway
26118c2ecf20Sopenharmony_ci */
26128c2ecf20Sopenharmony_cibool batadv_bla_check_claim(struct batadv_priv *bat_priv,
26138c2ecf20Sopenharmony_ci			    u8 *addr, unsigned short vid)
26148c2ecf20Sopenharmony_ci{
26158c2ecf20Sopenharmony_ci	struct batadv_bla_claim search_claim;
26168c2ecf20Sopenharmony_ci	struct batadv_bla_claim *claim = NULL;
26178c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
26188c2ecf20Sopenharmony_ci	bool ret = true;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
26218c2ecf20Sopenharmony_ci		return ret;
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
26248c2ecf20Sopenharmony_ci	if (!primary_if)
26258c2ecf20Sopenharmony_ci		return ret;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	/* First look if the mac address is claimed */
26288c2ecf20Sopenharmony_ci	ether_addr_copy(search_claim.addr, addr);
26298c2ecf20Sopenharmony_ci	search_claim.vid = vid;
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	/* If there is a claim and we are not owner of the claim,
26348c2ecf20Sopenharmony_ci	 * return false.
26358c2ecf20Sopenharmony_ci	 */
26368c2ecf20Sopenharmony_ci	if (claim) {
26378c2ecf20Sopenharmony_ci		if (!batadv_compare_eth(claim->backbone_gw->orig,
26388c2ecf20Sopenharmony_ci					primary_if->net_dev->dev_addr))
26398c2ecf20Sopenharmony_ci			ret = false;
26408c2ecf20Sopenharmony_ci		batadv_claim_put(claim);
26418c2ecf20Sopenharmony_ci	}
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci	batadv_hardif_put(primary_if);
26448c2ecf20Sopenharmony_ci	return ret;
26458c2ecf20Sopenharmony_ci}
26468c2ecf20Sopenharmony_ci#endif
2647