162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) B.A.T.M.A.N. contributors:
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Simon Wunderlich
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "bridge_loop_avoidance.h"
862306a36Sopenharmony_ci#include "main.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/atomic.h>
1162306a36Sopenharmony_ci#include <linux/byteorder/generic.h>
1262306a36Sopenharmony_ci#include <linux/compiler.h>
1362306a36Sopenharmony_ci#include <linux/container_of.h>
1462306a36Sopenharmony_ci#include <linux/crc16.h>
1562306a36Sopenharmony_ci#include <linux/errno.h>
1662306a36Sopenharmony_ci#include <linux/etherdevice.h>
1762306a36Sopenharmony_ci#include <linux/gfp.h>
1862306a36Sopenharmony_ci#include <linux/if_arp.h>
1962306a36Sopenharmony_ci#include <linux/if_ether.h>
2062306a36Sopenharmony_ci#include <linux/if_vlan.h>
2162306a36Sopenharmony_ci#include <linux/jhash.h>
2262306a36Sopenharmony_ci#include <linux/jiffies.h>
2362306a36Sopenharmony_ci#include <linux/kernel.h>
2462306a36Sopenharmony_ci#include <linux/kref.h>
2562306a36Sopenharmony_ci#include <linux/list.h>
2662306a36Sopenharmony_ci#include <linux/lockdep.h>
2762306a36Sopenharmony_ci#include <linux/netdevice.h>
2862306a36Sopenharmony_ci#include <linux/netlink.h>
2962306a36Sopenharmony_ci#include <linux/rculist.h>
3062306a36Sopenharmony_ci#include <linux/rcupdate.h>
3162306a36Sopenharmony_ci#include <linux/skbuff.h>
3262306a36Sopenharmony_ci#include <linux/slab.h>
3362306a36Sopenharmony_ci#include <linux/spinlock.h>
3462306a36Sopenharmony_ci#include <linux/stddef.h>
3562306a36Sopenharmony_ci#include <linux/string.h>
3662306a36Sopenharmony_ci#include <linux/workqueue.h>
3762306a36Sopenharmony_ci#include <net/arp.h>
3862306a36Sopenharmony_ci#include <net/genetlink.h>
3962306a36Sopenharmony_ci#include <net/netlink.h>
4062306a36Sopenharmony_ci#include <net/sock.h>
4162306a36Sopenharmony_ci#include <uapi/linux/batadv_packet.h>
4262306a36Sopenharmony_ci#include <uapi/linux/batman_adv.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include "hard-interface.h"
4562306a36Sopenharmony_ci#include "hash.h"
4662306a36Sopenharmony_ci#include "log.h"
4762306a36Sopenharmony_ci#include "netlink.h"
4862306a36Sopenharmony_ci#include "originator.h"
4962306a36Sopenharmony_ci#include "soft-interface.h"
5062306a36Sopenharmony_ci#include "translation-table.h"
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic const u8 batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void batadv_bla_periodic_work(struct work_struct *work);
5562306a36Sopenharmony_cistatic void
5662306a36Sopenharmony_cibatadv_bla_send_announce(struct batadv_priv *bat_priv,
5762306a36Sopenharmony_ci			 struct batadv_bla_backbone_gw *backbone_gw);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/**
6062306a36Sopenharmony_ci * batadv_choose_claim() - choose the right bucket for a claim.
6162306a36Sopenharmony_ci * @data: data to hash
6262306a36Sopenharmony_ci * @size: size of the hash table
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * Return: the hash index of the claim
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_cistatic inline u32 batadv_choose_claim(const void *data, u32 size)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	const struct batadv_bla_claim *claim = data;
6962306a36Sopenharmony_ci	u32 hash = 0;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	hash = jhash(&claim->addr, sizeof(claim->addr), hash);
7262306a36Sopenharmony_ci	hash = jhash(&claim->vid, sizeof(claim->vid), hash);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return hash % size;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/**
7862306a36Sopenharmony_ci * batadv_choose_backbone_gw() - choose the right bucket for a backbone gateway.
7962306a36Sopenharmony_ci * @data: data to hash
8062306a36Sopenharmony_ci * @size: size of the hash table
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * Return: the hash index of the backbone gateway
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_cistatic inline u32 batadv_choose_backbone_gw(const void *data, u32 size)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	const struct batadv_bla_backbone_gw *gw;
8762306a36Sopenharmony_ci	u32 hash = 0;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	gw = data;
9062306a36Sopenharmony_ci	hash = jhash(&gw->orig, sizeof(gw->orig), hash);
9162306a36Sopenharmony_ci	hash = jhash(&gw->vid, sizeof(gw->vid), hash);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return hash % size;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/**
9762306a36Sopenharmony_ci * batadv_compare_backbone_gw() - compare address and vid of two backbone gws
9862306a36Sopenharmony_ci * @node: list node of the first entry to compare
9962306a36Sopenharmony_ci * @data2: pointer to the second backbone gateway
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci * Return: true if the backbones have the same data, false otherwise
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_cistatic bool batadv_compare_backbone_gw(const struct hlist_node *node,
10462306a36Sopenharmony_ci				       const void *data2)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	const void *data1 = container_of(node, struct batadv_bla_backbone_gw,
10762306a36Sopenharmony_ci					 hash_entry);
10862306a36Sopenharmony_ci	const struct batadv_bla_backbone_gw *gw1 = data1;
10962306a36Sopenharmony_ci	const struct batadv_bla_backbone_gw *gw2 = data2;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (!batadv_compare_eth(gw1->orig, gw2->orig))
11262306a36Sopenharmony_ci		return false;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (gw1->vid != gw2->vid)
11562306a36Sopenharmony_ci		return false;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return true;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/**
12162306a36Sopenharmony_ci * batadv_compare_claim() - compare address and vid of two claims
12262306a36Sopenharmony_ci * @node: list node of the first entry to compare
12362306a36Sopenharmony_ci * @data2: pointer to the second claims
12462306a36Sopenharmony_ci *
12562306a36Sopenharmony_ci * Return: true if the claim have the same data, 0 otherwise
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistatic bool batadv_compare_claim(const struct hlist_node *node,
12862306a36Sopenharmony_ci				 const void *data2)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	const void *data1 = container_of(node, struct batadv_bla_claim,
13162306a36Sopenharmony_ci					 hash_entry);
13262306a36Sopenharmony_ci	const struct batadv_bla_claim *cl1 = data1;
13362306a36Sopenharmony_ci	const struct batadv_bla_claim *cl2 = data2;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (!batadv_compare_eth(cl1->addr, cl2->addr))
13662306a36Sopenharmony_ci		return false;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (cl1->vid != cl2->vid)
13962306a36Sopenharmony_ci		return false;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return true;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/**
14562306a36Sopenharmony_ci * batadv_backbone_gw_release() - release backbone gw from lists and queue for
14662306a36Sopenharmony_ci *  free after rcu grace period
14762306a36Sopenharmony_ci * @ref: kref pointer of the backbone gw
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_cistatic void batadv_backbone_gw_release(struct kref *ref)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	backbone_gw = container_of(ref, struct batadv_bla_backbone_gw,
15462306a36Sopenharmony_ci				   refcount);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	kfree_rcu(backbone_gw, rcu);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/**
16062306a36Sopenharmony_ci * batadv_backbone_gw_put() - decrement the backbone gw refcounter and possibly
16162306a36Sopenharmony_ci *  release it
16262306a36Sopenharmony_ci * @backbone_gw: backbone gateway to be free'd
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_cistatic void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	if (!backbone_gw)
16762306a36Sopenharmony_ci		return;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	kref_put(&backbone_gw->refcount, batadv_backbone_gw_release);
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/**
17362306a36Sopenharmony_ci * batadv_claim_release() - release claim from lists and queue for free after
17462306a36Sopenharmony_ci *  rcu grace period
17562306a36Sopenharmony_ci * @ref: kref pointer of the claim
17662306a36Sopenharmony_ci */
17762306a36Sopenharmony_cistatic void batadv_claim_release(struct kref *ref)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct batadv_bla_claim *claim;
18062306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *old_backbone_gw;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	claim = container_of(ref, struct batadv_bla_claim, refcount);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	spin_lock_bh(&claim->backbone_lock);
18562306a36Sopenharmony_ci	old_backbone_gw = claim->backbone_gw;
18662306a36Sopenharmony_ci	claim->backbone_gw = NULL;
18762306a36Sopenharmony_ci	spin_unlock_bh(&claim->backbone_lock);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	spin_lock_bh(&old_backbone_gw->crc_lock);
19062306a36Sopenharmony_ci	old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
19162306a36Sopenharmony_ci	spin_unlock_bh(&old_backbone_gw->crc_lock);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	batadv_backbone_gw_put(old_backbone_gw);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	kfree_rcu(claim, rcu);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/**
19962306a36Sopenharmony_ci * batadv_claim_put() - decrement the claim refcounter and possibly release it
20062306a36Sopenharmony_ci * @claim: claim to be free'd
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_cistatic void batadv_claim_put(struct batadv_bla_claim *claim)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	if (!claim)
20562306a36Sopenharmony_ci		return;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	kref_put(&claim->refcount, batadv_claim_release);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/**
21162306a36Sopenharmony_ci * batadv_claim_hash_find() - looks for a claim in the claim hash
21262306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
21362306a36Sopenharmony_ci * @data: search data (may be local/static data)
21462306a36Sopenharmony_ci *
21562306a36Sopenharmony_ci * Return: claim if found or NULL otherwise.
21662306a36Sopenharmony_ci */
21762306a36Sopenharmony_cistatic struct batadv_bla_claim *
21862306a36Sopenharmony_cibatadv_claim_hash_find(struct batadv_priv *bat_priv,
21962306a36Sopenharmony_ci		       struct batadv_bla_claim *data)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->bla.claim_hash;
22262306a36Sopenharmony_ci	struct hlist_head *head;
22362306a36Sopenharmony_ci	struct batadv_bla_claim *claim;
22462306a36Sopenharmony_ci	struct batadv_bla_claim *claim_tmp = NULL;
22562306a36Sopenharmony_ci	int index;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (!hash)
22862306a36Sopenharmony_ci		return NULL;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	index = batadv_choose_claim(data, hash->size);
23162306a36Sopenharmony_ci	head = &hash->table[index];
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	rcu_read_lock();
23462306a36Sopenharmony_ci	hlist_for_each_entry_rcu(claim, head, hash_entry) {
23562306a36Sopenharmony_ci		if (!batadv_compare_claim(&claim->hash_entry, data))
23662306a36Sopenharmony_ci			continue;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		if (!kref_get_unless_zero(&claim->refcount))
23962306a36Sopenharmony_ci			continue;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		claim_tmp = claim;
24262306a36Sopenharmony_ci		break;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci	rcu_read_unlock();
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return claim_tmp;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/**
25062306a36Sopenharmony_ci * batadv_backbone_hash_find() - looks for a backbone gateway in the hash
25162306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
25262306a36Sopenharmony_ci * @addr: the address of the originator
25362306a36Sopenharmony_ci * @vid: the VLAN ID
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci * Return: backbone gateway if found or NULL otherwise
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cistatic struct batadv_bla_backbone_gw *
25862306a36Sopenharmony_cibatadv_backbone_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
25962306a36Sopenharmony_ci			  unsigned short vid)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
26262306a36Sopenharmony_ci	struct hlist_head *head;
26362306a36Sopenharmony_ci	struct batadv_bla_backbone_gw search_entry, *backbone_gw;
26462306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw_tmp = NULL;
26562306a36Sopenharmony_ci	int index;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (!hash)
26862306a36Sopenharmony_ci		return NULL;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	ether_addr_copy(search_entry.orig, addr);
27162306a36Sopenharmony_ci	search_entry.vid = vid;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	index = batadv_choose_backbone_gw(&search_entry, hash->size);
27462306a36Sopenharmony_ci	head = &hash->table[index];
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	rcu_read_lock();
27762306a36Sopenharmony_ci	hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
27862306a36Sopenharmony_ci		if (!batadv_compare_backbone_gw(&backbone_gw->hash_entry,
27962306a36Sopenharmony_ci						&search_entry))
28062306a36Sopenharmony_ci			continue;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		if (!kref_get_unless_zero(&backbone_gw->refcount))
28362306a36Sopenharmony_ci			continue;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		backbone_gw_tmp = backbone_gw;
28662306a36Sopenharmony_ci		break;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	rcu_read_unlock();
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	return backbone_gw_tmp;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/**
29462306a36Sopenharmony_ci * batadv_bla_del_backbone_claims() - delete all claims for a backbone
29562306a36Sopenharmony_ci * @backbone_gw: backbone gateway where the claims should be removed
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic void
29862306a36Sopenharmony_cibatadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct batadv_hashtable *hash;
30162306a36Sopenharmony_ci	struct hlist_node *node_tmp;
30262306a36Sopenharmony_ci	struct hlist_head *head;
30362306a36Sopenharmony_ci	struct batadv_bla_claim *claim;
30462306a36Sopenharmony_ci	int i;
30562306a36Sopenharmony_ci	spinlock_t *list_lock;	/* protects write access to the hash lists */
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	hash = backbone_gw->bat_priv->bla.claim_hash;
30862306a36Sopenharmony_ci	if (!hash)
30962306a36Sopenharmony_ci		return;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
31262306a36Sopenharmony_ci		head = &hash->table[i];
31362306a36Sopenharmony_ci		list_lock = &hash->list_locks[i];
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		spin_lock_bh(list_lock);
31662306a36Sopenharmony_ci		hlist_for_each_entry_safe(claim, node_tmp,
31762306a36Sopenharmony_ci					  head, hash_entry) {
31862306a36Sopenharmony_ci			if (claim->backbone_gw != backbone_gw)
31962306a36Sopenharmony_ci				continue;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci			batadv_claim_put(claim);
32262306a36Sopenharmony_ci			hlist_del_rcu(&claim->hash_entry);
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci		spin_unlock_bh(list_lock);
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* all claims gone, initialize CRC */
32862306a36Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
32962306a36Sopenharmony_ci	backbone_gw->crc = BATADV_BLA_CRC_INIT;
33062306a36Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/**
33462306a36Sopenharmony_ci * batadv_bla_send_claim() - sends a claim frame according to the provided info
33562306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
33662306a36Sopenharmony_ci * @mac: the mac address to be announced within the claim
33762306a36Sopenharmony_ci * @vid: the VLAN ID
33862306a36Sopenharmony_ci * @claimtype: the type of the claim (CLAIM, UNCLAIM, ANNOUNCE, ...)
33962306a36Sopenharmony_ci */
34062306a36Sopenharmony_cistatic void batadv_bla_send_claim(struct batadv_priv *bat_priv, const u8 *mac,
34162306a36Sopenharmony_ci				  unsigned short vid, int claimtype)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct sk_buff *skb;
34462306a36Sopenharmony_ci	struct ethhdr *ethhdr;
34562306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
34662306a36Sopenharmony_ci	struct net_device *soft_iface;
34762306a36Sopenharmony_ci	u8 *hw_src;
34862306a36Sopenharmony_ci	struct batadv_bla_claim_dst local_claim_dest;
34962306a36Sopenharmony_ci	__be32 zeroip = 0;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
35262306a36Sopenharmony_ci	if (!primary_if)
35362306a36Sopenharmony_ci		return;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	memcpy(&local_claim_dest, &bat_priv->bla.claim_dest,
35662306a36Sopenharmony_ci	       sizeof(local_claim_dest));
35762306a36Sopenharmony_ci	local_claim_dest.type = claimtype;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	soft_iface = primary_if->soft_iface;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
36262306a36Sopenharmony_ci			 /* IP DST: 0.0.0.0 */
36362306a36Sopenharmony_ci			 zeroip,
36462306a36Sopenharmony_ci			 primary_if->soft_iface,
36562306a36Sopenharmony_ci			 /* IP SRC: 0.0.0.0 */
36662306a36Sopenharmony_ci			 zeroip,
36762306a36Sopenharmony_ci			 /* Ethernet DST: Broadcast */
36862306a36Sopenharmony_ci			 NULL,
36962306a36Sopenharmony_ci			 /* Ethernet SRC/HW SRC:  originator mac */
37062306a36Sopenharmony_ci			 primary_if->net_dev->dev_addr,
37162306a36Sopenharmony_ci			 /* HW DST: FF:43:05:XX:YY:YY
37262306a36Sopenharmony_ci			  * with XX   = claim type
37362306a36Sopenharmony_ci			  * and YY:YY = group id
37462306a36Sopenharmony_ci			  */
37562306a36Sopenharmony_ci			 (u8 *)&local_claim_dest);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (!skb)
37862306a36Sopenharmony_ci		goto out;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	ethhdr = (struct ethhdr *)skb->data;
38162306a36Sopenharmony_ci	hw_src = (u8 *)ethhdr + ETH_HLEN + sizeof(struct arphdr);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	/* now we pretend that the client would have sent this ... */
38462306a36Sopenharmony_ci	switch (claimtype) {
38562306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_CLAIM:
38662306a36Sopenharmony_ci		/* normal claim frame
38762306a36Sopenharmony_ci		 * set Ethernet SRC to the clients mac
38862306a36Sopenharmony_ci		 */
38962306a36Sopenharmony_ci		ether_addr_copy(ethhdr->h_source, mac);
39062306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
39162306a36Sopenharmony_ci			   "%s(): CLAIM %pM on vid %d\n", __func__, mac,
39262306a36Sopenharmony_ci			   batadv_print_vid(vid));
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_UNCLAIM:
39562306a36Sopenharmony_ci		/* unclaim frame
39662306a36Sopenharmony_ci		 * set HW SRC to the clients mac
39762306a36Sopenharmony_ci		 */
39862306a36Sopenharmony_ci		ether_addr_copy(hw_src, mac);
39962306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
40062306a36Sopenharmony_ci			   "%s(): UNCLAIM %pM on vid %d\n", __func__, mac,
40162306a36Sopenharmony_ci			   batadv_print_vid(vid));
40262306a36Sopenharmony_ci		break;
40362306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_ANNOUNCE:
40462306a36Sopenharmony_ci		/* announcement frame
40562306a36Sopenharmony_ci		 * set HW SRC to the special mac containing the crc
40662306a36Sopenharmony_ci		 */
40762306a36Sopenharmony_ci		ether_addr_copy(hw_src, mac);
40862306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
40962306a36Sopenharmony_ci			   "%s(): ANNOUNCE of %pM on vid %d\n", __func__,
41062306a36Sopenharmony_ci			   ethhdr->h_source, batadv_print_vid(vid));
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_REQUEST:
41362306a36Sopenharmony_ci		/* request frame
41462306a36Sopenharmony_ci		 * set HW SRC and header destination to the receiving backbone
41562306a36Sopenharmony_ci		 * gws mac
41662306a36Sopenharmony_ci		 */
41762306a36Sopenharmony_ci		ether_addr_copy(hw_src, mac);
41862306a36Sopenharmony_ci		ether_addr_copy(ethhdr->h_dest, mac);
41962306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
42062306a36Sopenharmony_ci			   "%s(): REQUEST of %pM to %pM on vid %d\n", __func__,
42162306a36Sopenharmony_ci			   ethhdr->h_source, ethhdr->h_dest,
42262306a36Sopenharmony_ci			   batadv_print_vid(vid));
42362306a36Sopenharmony_ci		break;
42462306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_LOOPDETECT:
42562306a36Sopenharmony_ci		ether_addr_copy(ethhdr->h_source, mac);
42662306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
42762306a36Sopenharmony_ci			   "%s(): LOOPDETECT of %pM to %pM on vid %d\n",
42862306a36Sopenharmony_ci			   __func__, ethhdr->h_source, ethhdr->h_dest,
42962306a36Sopenharmony_ci			   batadv_print_vid(vid));
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		break;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (vid & BATADV_VLAN_HAS_TAG) {
43562306a36Sopenharmony_ci		skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),
43662306a36Sopenharmony_ci				      vid & VLAN_VID_MASK);
43762306a36Sopenharmony_ci		if (!skb)
43862306a36Sopenharmony_ci			goto out;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	skb_reset_mac_header(skb);
44262306a36Sopenharmony_ci	skb->protocol = eth_type_trans(skb, soft_iface);
44362306a36Sopenharmony_ci	batadv_inc_counter(bat_priv, BATADV_CNT_RX);
44462306a36Sopenharmony_ci	batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
44562306a36Sopenharmony_ci			   skb->len + ETH_HLEN);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	netif_rx(skb);
44862306a36Sopenharmony_ciout:
44962306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/**
45362306a36Sopenharmony_ci * batadv_bla_loopdetect_report() - worker for reporting the loop
45462306a36Sopenharmony_ci * @work: work queue item
45562306a36Sopenharmony_ci *
45662306a36Sopenharmony_ci * Throws an uevent, as the loopdetect check function can't do that itself
45762306a36Sopenharmony_ci * since the kernel may sleep while throwing uevents.
45862306a36Sopenharmony_ci */
45962306a36Sopenharmony_cistatic void batadv_bla_loopdetect_report(struct work_struct *work)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
46262306a36Sopenharmony_ci	struct batadv_priv *bat_priv;
46362306a36Sopenharmony_ci	char vid_str[6] = { '\0' };
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	backbone_gw = container_of(work, struct batadv_bla_backbone_gw,
46662306a36Sopenharmony_ci				   report_work);
46762306a36Sopenharmony_ci	bat_priv = backbone_gw->bat_priv;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	batadv_info(bat_priv->soft_iface,
47062306a36Sopenharmony_ci		    "Possible loop on VLAN %d detected which can't be handled by BLA - please check your network setup!\n",
47162306a36Sopenharmony_ci		    batadv_print_vid(backbone_gw->vid));
47262306a36Sopenharmony_ci	snprintf(vid_str, sizeof(vid_str), "%d",
47362306a36Sopenharmony_ci		 batadv_print_vid(backbone_gw->vid));
47462306a36Sopenharmony_ci	vid_str[sizeof(vid_str) - 1] = 0;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	batadv_throw_uevent(bat_priv, BATADV_UEV_BLA, BATADV_UEV_LOOPDETECT,
47762306a36Sopenharmony_ci			    vid_str);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/**
48362306a36Sopenharmony_ci * batadv_bla_get_backbone_gw() - finds or creates a backbone gateway
48462306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
48562306a36Sopenharmony_ci * @orig: the mac address of the originator
48662306a36Sopenharmony_ci * @vid: the VLAN ID
48762306a36Sopenharmony_ci * @own_backbone: set if the requested backbone is local
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci * Return: the (possibly created) backbone gateway or NULL on error
49062306a36Sopenharmony_ci */
49162306a36Sopenharmony_cistatic struct batadv_bla_backbone_gw *
49262306a36Sopenharmony_cibatadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, const u8 *orig,
49362306a36Sopenharmony_ci			   unsigned short vid, bool own_backbone)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *entry;
49662306a36Sopenharmony_ci	struct batadv_orig_node *orig_node;
49762306a36Sopenharmony_ci	int hash_added;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	entry = batadv_backbone_hash_find(bat_priv, orig, vid);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (entry)
50262306a36Sopenharmony_ci		return entry;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
50562306a36Sopenharmony_ci		   "%s(): not found (%pM, %d), creating new entry\n", __func__,
50662306a36Sopenharmony_ci		   orig, batadv_print_vid(vid));
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
50962306a36Sopenharmony_ci	if (!entry)
51062306a36Sopenharmony_ci		return NULL;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	entry->vid = vid;
51362306a36Sopenharmony_ci	entry->lasttime = jiffies;
51462306a36Sopenharmony_ci	entry->crc = BATADV_BLA_CRC_INIT;
51562306a36Sopenharmony_ci	entry->bat_priv = bat_priv;
51662306a36Sopenharmony_ci	spin_lock_init(&entry->crc_lock);
51762306a36Sopenharmony_ci	atomic_set(&entry->request_sent, 0);
51862306a36Sopenharmony_ci	atomic_set(&entry->wait_periods, 0);
51962306a36Sopenharmony_ci	ether_addr_copy(entry->orig, orig);
52062306a36Sopenharmony_ci	INIT_WORK(&entry->report_work, batadv_bla_loopdetect_report);
52162306a36Sopenharmony_ci	kref_init(&entry->refcount);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	kref_get(&entry->refcount);
52462306a36Sopenharmony_ci	hash_added = batadv_hash_add(bat_priv->bla.backbone_hash,
52562306a36Sopenharmony_ci				     batadv_compare_backbone_gw,
52662306a36Sopenharmony_ci				     batadv_choose_backbone_gw, entry,
52762306a36Sopenharmony_ci				     &entry->hash_entry);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (unlikely(hash_added != 0)) {
53062306a36Sopenharmony_ci		/* hash failed, free the structure */
53162306a36Sopenharmony_ci		kfree(entry);
53262306a36Sopenharmony_ci		return NULL;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/* this is a gateway now, remove any TT entry on this VLAN */
53662306a36Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, orig);
53762306a36Sopenharmony_ci	if (orig_node) {
53862306a36Sopenharmony_ci		batadv_tt_global_del_orig(bat_priv, orig_node, vid,
53962306a36Sopenharmony_ci					  "became a backbone gateway");
54062306a36Sopenharmony_ci		batadv_orig_node_put(orig_node);
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (own_backbone) {
54462306a36Sopenharmony_ci		batadv_bla_send_announce(bat_priv, entry);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		/* this will be decreased in the worker thread */
54762306a36Sopenharmony_ci		atomic_inc(&entry->request_sent);
54862306a36Sopenharmony_ci		atomic_set(&entry->wait_periods, BATADV_BLA_WAIT_PERIODS);
54962306a36Sopenharmony_ci		atomic_inc(&bat_priv->bla.num_requests);
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	return entry;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci/**
55662306a36Sopenharmony_ci * batadv_bla_update_own_backbone_gw() - updates the own backbone gw for a VLAN
55762306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
55862306a36Sopenharmony_ci * @primary_if: the selected primary interface
55962306a36Sopenharmony_ci * @vid: VLAN identifier
56062306a36Sopenharmony_ci *
56162306a36Sopenharmony_ci * update or add the own backbone gw to make sure we announce
56262306a36Sopenharmony_ci * where we receive other backbone gws
56362306a36Sopenharmony_ci */
56462306a36Sopenharmony_cistatic void
56562306a36Sopenharmony_cibatadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv,
56662306a36Sopenharmony_ci				  struct batadv_hard_iface *primary_if,
56762306a36Sopenharmony_ci				  unsigned short vid)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	backbone_gw = batadv_bla_get_backbone_gw(bat_priv,
57262306a36Sopenharmony_ci						 primary_if->net_dev->dev_addr,
57362306a36Sopenharmony_ci						 vid, true);
57462306a36Sopenharmony_ci	if (unlikely(!backbone_gw))
57562306a36Sopenharmony_ci		return;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	backbone_gw->lasttime = jiffies;
57862306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci/**
58262306a36Sopenharmony_ci * batadv_bla_answer_request() - answer a bla request by sending own claims
58362306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
58462306a36Sopenharmony_ci * @primary_if: interface where the request came on
58562306a36Sopenharmony_ci * @vid: the vid where the request came on
58662306a36Sopenharmony_ci *
58762306a36Sopenharmony_ci * Repeat all of our own claims, and finally send an ANNOUNCE frame
58862306a36Sopenharmony_ci * to allow the requester another check if the CRC is correct now.
58962306a36Sopenharmony_ci */
59062306a36Sopenharmony_cistatic void batadv_bla_answer_request(struct batadv_priv *bat_priv,
59162306a36Sopenharmony_ci				      struct batadv_hard_iface *primary_if,
59262306a36Sopenharmony_ci				      unsigned short vid)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	struct hlist_head *head;
59562306a36Sopenharmony_ci	struct batadv_hashtable *hash;
59662306a36Sopenharmony_ci	struct batadv_bla_claim *claim;
59762306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
59862306a36Sopenharmony_ci	int i;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
60162306a36Sopenharmony_ci		   "%s(): received a claim request, send all of our own claims again\n",
60262306a36Sopenharmony_ci		   __func__);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	backbone_gw = batadv_backbone_hash_find(bat_priv,
60562306a36Sopenharmony_ci						primary_if->net_dev->dev_addr,
60662306a36Sopenharmony_ci						vid);
60762306a36Sopenharmony_ci	if (!backbone_gw)
60862306a36Sopenharmony_ci		return;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	hash = bat_priv->bla.claim_hash;
61162306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
61262306a36Sopenharmony_ci		head = &hash->table[i];
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		rcu_read_lock();
61562306a36Sopenharmony_ci		hlist_for_each_entry_rcu(claim, head, hash_entry) {
61662306a36Sopenharmony_ci			/* only own claims are interesting */
61762306a36Sopenharmony_ci			if (claim->backbone_gw != backbone_gw)
61862306a36Sopenharmony_ci				continue;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci			batadv_bla_send_claim(bat_priv, claim->addr, claim->vid,
62162306a36Sopenharmony_ci					      BATADV_CLAIM_TYPE_CLAIM);
62262306a36Sopenharmony_ci		}
62362306a36Sopenharmony_ci		rcu_read_unlock();
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* finally, send an announcement frame */
62762306a36Sopenharmony_ci	batadv_bla_send_announce(bat_priv, backbone_gw);
62862306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci/**
63262306a36Sopenharmony_ci * batadv_bla_send_request() - send a request to repeat claims
63362306a36Sopenharmony_ci * @backbone_gw: the backbone gateway from whom we are out of sync
63462306a36Sopenharmony_ci *
63562306a36Sopenharmony_ci * When the crc is wrong, ask the backbone gateway for a full table update.
63662306a36Sopenharmony_ci * After the request, it will repeat all of his own claims and finally
63762306a36Sopenharmony_ci * send an announcement claim with which we can check again.
63862306a36Sopenharmony_ci */
63962306a36Sopenharmony_cistatic void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	/* first, remove all old entries */
64262306a36Sopenharmony_ci	batadv_bla_del_backbone_claims(backbone_gw);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
64562306a36Sopenharmony_ci		   "Sending REQUEST to %pM\n", backbone_gw->orig);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/* send request */
64862306a36Sopenharmony_ci	batadv_bla_send_claim(backbone_gw->bat_priv, backbone_gw->orig,
64962306a36Sopenharmony_ci			      backbone_gw->vid, BATADV_CLAIM_TYPE_REQUEST);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	/* no local broadcasts should be sent or received, for now. */
65262306a36Sopenharmony_ci	if (!atomic_read(&backbone_gw->request_sent)) {
65362306a36Sopenharmony_ci		atomic_inc(&backbone_gw->bat_priv->bla.num_requests);
65462306a36Sopenharmony_ci		atomic_set(&backbone_gw->request_sent, 1);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci/**
65962306a36Sopenharmony_ci * batadv_bla_send_announce() - Send an announcement frame
66062306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
66162306a36Sopenharmony_ci * @backbone_gw: our backbone gateway which should be announced
66262306a36Sopenharmony_ci */
66362306a36Sopenharmony_cistatic void batadv_bla_send_announce(struct batadv_priv *bat_priv,
66462306a36Sopenharmony_ci				     struct batadv_bla_backbone_gw *backbone_gw)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	u8 mac[ETH_ALEN];
66762306a36Sopenharmony_ci	__be16 crc;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	memcpy(mac, batadv_announce_mac, 4);
67062306a36Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
67162306a36Sopenharmony_ci	crc = htons(backbone_gw->crc);
67262306a36Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
67362306a36Sopenharmony_ci	memcpy(&mac[4], &crc, 2);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	batadv_bla_send_claim(bat_priv, mac, backbone_gw->vid,
67662306a36Sopenharmony_ci			      BATADV_CLAIM_TYPE_ANNOUNCE);
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci/**
68062306a36Sopenharmony_ci * batadv_bla_add_claim() - Adds a claim in the claim hash
68162306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
68262306a36Sopenharmony_ci * @mac: the mac address of the claim
68362306a36Sopenharmony_ci * @vid: the VLAN ID of the frame
68462306a36Sopenharmony_ci * @backbone_gw: the backbone gateway which claims it
68562306a36Sopenharmony_ci */
68662306a36Sopenharmony_cistatic void batadv_bla_add_claim(struct batadv_priv *bat_priv,
68762306a36Sopenharmony_ci				 const u8 *mac, const unsigned short vid,
68862306a36Sopenharmony_ci				 struct batadv_bla_backbone_gw *backbone_gw)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *old_backbone_gw;
69162306a36Sopenharmony_ci	struct batadv_bla_claim *claim;
69262306a36Sopenharmony_ci	struct batadv_bla_claim search_claim;
69362306a36Sopenharmony_ci	bool remove_crc = false;
69462306a36Sopenharmony_ci	int hash_added;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	ether_addr_copy(search_claim.addr, mac);
69762306a36Sopenharmony_ci	search_claim.vid = vid;
69862306a36Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	/* create a new claim entry if it does not exist yet. */
70162306a36Sopenharmony_ci	if (!claim) {
70262306a36Sopenharmony_ci		claim = kzalloc(sizeof(*claim), GFP_ATOMIC);
70362306a36Sopenharmony_ci		if (!claim)
70462306a36Sopenharmony_ci			return;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		ether_addr_copy(claim->addr, mac);
70762306a36Sopenharmony_ci		spin_lock_init(&claim->backbone_lock);
70862306a36Sopenharmony_ci		claim->vid = vid;
70962306a36Sopenharmony_ci		claim->lasttime = jiffies;
71062306a36Sopenharmony_ci		kref_get(&backbone_gw->refcount);
71162306a36Sopenharmony_ci		claim->backbone_gw = backbone_gw;
71262306a36Sopenharmony_ci		kref_init(&claim->refcount);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
71562306a36Sopenharmony_ci			   "%s(): adding new entry %pM, vid %d to hash ...\n",
71662306a36Sopenharmony_ci			   __func__, mac, batadv_print_vid(vid));
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		kref_get(&claim->refcount);
71962306a36Sopenharmony_ci		hash_added = batadv_hash_add(bat_priv->bla.claim_hash,
72062306a36Sopenharmony_ci					     batadv_compare_claim,
72162306a36Sopenharmony_ci					     batadv_choose_claim, claim,
72262306a36Sopenharmony_ci					     &claim->hash_entry);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci		if (unlikely(hash_added != 0)) {
72562306a36Sopenharmony_ci			/* only local changes happened. */
72662306a36Sopenharmony_ci			kfree(claim);
72762306a36Sopenharmony_ci			return;
72862306a36Sopenharmony_ci		}
72962306a36Sopenharmony_ci	} else {
73062306a36Sopenharmony_ci		claim->lasttime = jiffies;
73162306a36Sopenharmony_ci		if (claim->backbone_gw == backbone_gw)
73262306a36Sopenharmony_ci			/* no need to register a new backbone */
73362306a36Sopenharmony_ci			goto claim_free_ref;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
73662306a36Sopenharmony_ci			   "%s(): changing ownership for %pM, vid %d to gw %pM\n",
73762306a36Sopenharmony_ci			   __func__, mac, batadv_print_vid(vid),
73862306a36Sopenharmony_ci			   backbone_gw->orig);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci		remove_crc = true;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/* replace backbone_gw atomically and adjust reference counters */
74462306a36Sopenharmony_ci	spin_lock_bh(&claim->backbone_lock);
74562306a36Sopenharmony_ci	old_backbone_gw = claim->backbone_gw;
74662306a36Sopenharmony_ci	kref_get(&backbone_gw->refcount);
74762306a36Sopenharmony_ci	claim->backbone_gw = backbone_gw;
74862306a36Sopenharmony_ci	spin_unlock_bh(&claim->backbone_lock);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (remove_crc) {
75162306a36Sopenharmony_ci		/* remove claim address from old backbone_gw */
75262306a36Sopenharmony_ci		spin_lock_bh(&old_backbone_gw->crc_lock);
75362306a36Sopenharmony_ci		old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
75462306a36Sopenharmony_ci		spin_unlock_bh(&old_backbone_gw->crc_lock);
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	batadv_backbone_gw_put(old_backbone_gw);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	/* add claim address to new backbone_gw */
76062306a36Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
76162306a36Sopenharmony_ci	backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
76262306a36Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
76362306a36Sopenharmony_ci	backbone_gw->lasttime = jiffies;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ciclaim_free_ref:
76662306a36Sopenharmony_ci	batadv_claim_put(claim);
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci/**
77062306a36Sopenharmony_ci * batadv_bla_claim_get_backbone_gw() - Get valid reference for backbone_gw of
77162306a36Sopenharmony_ci *  claim
77262306a36Sopenharmony_ci * @claim: claim whose backbone_gw should be returned
77362306a36Sopenharmony_ci *
77462306a36Sopenharmony_ci * Return: valid reference to claim::backbone_gw
77562306a36Sopenharmony_ci */
77662306a36Sopenharmony_cistatic struct batadv_bla_backbone_gw *
77762306a36Sopenharmony_cibatadv_bla_claim_get_backbone_gw(struct batadv_bla_claim *claim)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	spin_lock_bh(&claim->backbone_lock);
78262306a36Sopenharmony_ci	backbone_gw = claim->backbone_gw;
78362306a36Sopenharmony_ci	kref_get(&backbone_gw->refcount);
78462306a36Sopenharmony_ci	spin_unlock_bh(&claim->backbone_lock);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	return backbone_gw;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci/**
79062306a36Sopenharmony_ci * batadv_bla_del_claim() - delete a claim from the claim hash
79162306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
79262306a36Sopenharmony_ci * @mac: mac address of the claim to be removed
79362306a36Sopenharmony_ci * @vid: VLAN id for the claim to be removed
79462306a36Sopenharmony_ci */
79562306a36Sopenharmony_cistatic void batadv_bla_del_claim(struct batadv_priv *bat_priv,
79662306a36Sopenharmony_ci				 const u8 *mac, const unsigned short vid)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	struct batadv_bla_claim search_claim, *claim;
79962306a36Sopenharmony_ci	struct batadv_bla_claim *claim_removed_entry;
80062306a36Sopenharmony_ci	struct hlist_node *claim_removed_node;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	ether_addr_copy(search_claim.addr, mac);
80362306a36Sopenharmony_ci	search_claim.vid = vid;
80462306a36Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
80562306a36Sopenharmony_ci	if (!claim)
80662306a36Sopenharmony_ci		return;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): %pM, vid %d\n", __func__,
80962306a36Sopenharmony_ci		   mac, batadv_print_vid(vid));
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	claim_removed_node = batadv_hash_remove(bat_priv->bla.claim_hash,
81262306a36Sopenharmony_ci						batadv_compare_claim,
81362306a36Sopenharmony_ci						batadv_choose_claim, claim);
81462306a36Sopenharmony_ci	if (!claim_removed_node)
81562306a36Sopenharmony_ci		goto free_claim;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* reference from the hash is gone */
81862306a36Sopenharmony_ci	claim_removed_entry = hlist_entry(claim_removed_node,
81962306a36Sopenharmony_ci					  struct batadv_bla_claim, hash_entry);
82062306a36Sopenharmony_ci	batadv_claim_put(claim_removed_entry);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cifree_claim:
82362306a36Sopenharmony_ci	/* don't need the reference from hash_find() anymore */
82462306a36Sopenharmony_ci	batadv_claim_put(claim);
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci/**
82862306a36Sopenharmony_ci * batadv_handle_announce() - check for ANNOUNCE frame
82962306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
83062306a36Sopenharmony_ci * @an_addr: announcement mac address (ARP Sender HW address)
83162306a36Sopenharmony_ci * @backbone_addr: originator address of the sender (Ethernet source MAC)
83262306a36Sopenharmony_ci * @vid: the VLAN ID of the frame
83362306a36Sopenharmony_ci *
83462306a36Sopenharmony_ci * Return: true if handled
83562306a36Sopenharmony_ci */
83662306a36Sopenharmony_cistatic bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
83762306a36Sopenharmony_ci				   u8 *backbone_addr, unsigned short vid)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
84062306a36Sopenharmony_ci	u16 backbone_crc, crc;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	if (memcmp(an_addr, batadv_announce_mac, 4) != 0)
84362306a36Sopenharmony_ci		return false;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid,
84662306a36Sopenharmony_ci						 false);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (unlikely(!backbone_gw))
84962306a36Sopenharmony_ci		return true;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/* handle as ANNOUNCE frame */
85262306a36Sopenharmony_ci	backbone_gw->lasttime = jiffies;
85362306a36Sopenharmony_ci	crc = ntohs(*((__force __be16 *)(&an_addr[4])));
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
85662306a36Sopenharmony_ci		   "%s(): ANNOUNCE vid %d (sent by %pM)... CRC = %#.4x\n",
85762306a36Sopenharmony_ci		   __func__, batadv_print_vid(vid), backbone_gw->orig, crc);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
86062306a36Sopenharmony_ci	backbone_crc = backbone_gw->crc;
86162306a36Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (backbone_crc != crc) {
86462306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
86562306a36Sopenharmony_ci			   "%s(): CRC FAILED for %pM/%d (my = %#.4x, sent = %#.4x)\n",
86662306a36Sopenharmony_ci			   __func__, backbone_gw->orig,
86762306a36Sopenharmony_ci			   batadv_print_vid(backbone_gw->vid),
86862306a36Sopenharmony_ci			   backbone_crc, crc);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		batadv_bla_send_request(backbone_gw);
87162306a36Sopenharmony_ci	} else {
87262306a36Sopenharmony_ci		/* if we have sent a request and the crc was OK,
87362306a36Sopenharmony_ci		 * we can allow traffic again.
87462306a36Sopenharmony_ci		 */
87562306a36Sopenharmony_ci		if (atomic_read(&backbone_gw->request_sent)) {
87662306a36Sopenharmony_ci			atomic_dec(&backbone_gw->bat_priv->bla.num_requests);
87762306a36Sopenharmony_ci			atomic_set(&backbone_gw->request_sent, 0);
87862306a36Sopenharmony_ci		}
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
88262306a36Sopenharmony_ci	return true;
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/**
88662306a36Sopenharmony_ci * batadv_handle_request() - check for REQUEST frame
88762306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
88862306a36Sopenharmony_ci * @primary_if: the primary hard interface of this batman soft interface
88962306a36Sopenharmony_ci * @backbone_addr: backbone address to be requested (ARP sender HW MAC)
89062306a36Sopenharmony_ci * @ethhdr: ethernet header of a packet
89162306a36Sopenharmony_ci * @vid: the VLAN ID of the frame
89262306a36Sopenharmony_ci *
89362306a36Sopenharmony_ci * Return: true if handled
89462306a36Sopenharmony_ci */
89562306a36Sopenharmony_cistatic bool batadv_handle_request(struct batadv_priv *bat_priv,
89662306a36Sopenharmony_ci				  struct batadv_hard_iface *primary_if,
89762306a36Sopenharmony_ci				  u8 *backbone_addr, struct ethhdr *ethhdr,
89862306a36Sopenharmony_ci				  unsigned short vid)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	/* check for REQUEST frame */
90162306a36Sopenharmony_ci	if (!batadv_compare_eth(backbone_addr, ethhdr->h_dest))
90262306a36Sopenharmony_ci		return false;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/* sanity check, this should not happen on a normal switch,
90562306a36Sopenharmony_ci	 * we ignore it in this case.
90662306a36Sopenharmony_ci	 */
90762306a36Sopenharmony_ci	if (!batadv_compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr))
90862306a36Sopenharmony_ci		return true;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
91162306a36Sopenharmony_ci		   "%s(): REQUEST vid %d (sent by %pM)...\n",
91262306a36Sopenharmony_ci		   __func__, batadv_print_vid(vid), ethhdr->h_source);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	batadv_bla_answer_request(bat_priv, primary_if, vid);
91562306a36Sopenharmony_ci	return true;
91662306a36Sopenharmony_ci}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci/**
91962306a36Sopenharmony_ci * batadv_handle_unclaim() - check for UNCLAIM frame
92062306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
92162306a36Sopenharmony_ci * @primary_if: the primary hard interface of this batman soft interface
92262306a36Sopenharmony_ci * @backbone_addr: originator address of the backbone (Ethernet source)
92362306a36Sopenharmony_ci * @claim_addr: Client to be unclaimed (ARP sender HW MAC)
92462306a36Sopenharmony_ci * @vid: the VLAN ID of the frame
92562306a36Sopenharmony_ci *
92662306a36Sopenharmony_ci * Return: true if handled
92762306a36Sopenharmony_ci */
92862306a36Sopenharmony_cistatic bool batadv_handle_unclaim(struct batadv_priv *bat_priv,
92962306a36Sopenharmony_ci				  struct batadv_hard_iface *primary_if,
93062306a36Sopenharmony_ci				  const u8 *backbone_addr, const u8 *claim_addr,
93162306a36Sopenharmony_ci				  unsigned short vid)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* unclaim in any case if it is our own */
93662306a36Sopenharmony_ci	if (primary_if && batadv_compare_eth(backbone_addr,
93762306a36Sopenharmony_ci					     primary_if->net_dev->dev_addr))
93862306a36Sopenharmony_ci		batadv_bla_send_claim(bat_priv, claim_addr, vid,
93962306a36Sopenharmony_ci				      BATADV_CLAIM_TYPE_UNCLAIM);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (!backbone_gw)
94462306a36Sopenharmony_ci		return true;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/* this must be an UNCLAIM frame */
94762306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
94862306a36Sopenharmony_ci		   "%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n", __func__,
94962306a36Sopenharmony_ci		   claim_addr, batadv_print_vid(vid), backbone_gw->orig);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	batadv_bla_del_claim(bat_priv, claim_addr, vid);
95262306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
95362306a36Sopenharmony_ci	return true;
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci/**
95762306a36Sopenharmony_ci * batadv_handle_claim() - check for CLAIM frame
95862306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
95962306a36Sopenharmony_ci * @primary_if: the primary hard interface of this batman soft interface
96062306a36Sopenharmony_ci * @backbone_addr: originator address of the backbone (Ethernet Source)
96162306a36Sopenharmony_ci * @claim_addr: client mac address to be claimed (ARP sender HW MAC)
96262306a36Sopenharmony_ci * @vid: the VLAN ID of the frame
96362306a36Sopenharmony_ci *
96462306a36Sopenharmony_ci * Return: true if handled
96562306a36Sopenharmony_ci */
96662306a36Sopenharmony_cistatic bool batadv_handle_claim(struct batadv_priv *bat_priv,
96762306a36Sopenharmony_ci				struct batadv_hard_iface *primary_if,
96862306a36Sopenharmony_ci				const u8 *backbone_addr, const u8 *claim_addr,
96962306a36Sopenharmony_ci				unsigned short vid)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/* register the gateway if not yet available, and add the claim. */
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid,
97662306a36Sopenharmony_ci						 false);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (unlikely(!backbone_gw))
97962306a36Sopenharmony_ci		return true;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/* this must be a CLAIM frame */
98262306a36Sopenharmony_ci	batadv_bla_add_claim(bat_priv, claim_addr, vid, backbone_gw);
98362306a36Sopenharmony_ci	if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
98462306a36Sopenharmony_ci		batadv_bla_send_claim(bat_priv, claim_addr, vid,
98562306a36Sopenharmony_ci				      BATADV_CLAIM_TYPE_CLAIM);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/* TODO: we could call something like tt_local_del() here. */
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
99062306a36Sopenharmony_ci	return true;
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci/**
99462306a36Sopenharmony_ci * batadv_check_claim_group() - check for claim group membership
99562306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
99662306a36Sopenharmony_ci * @primary_if: the primary interface of this batman interface
99762306a36Sopenharmony_ci * @hw_src: the Hardware source in the ARP Header
99862306a36Sopenharmony_ci * @hw_dst: the Hardware destination in the ARP Header
99962306a36Sopenharmony_ci * @ethhdr: pointer to the Ethernet header of the claim frame
100062306a36Sopenharmony_ci *
100162306a36Sopenharmony_ci * checks if it is a claim packet and if it's on the same group.
100262306a36Sopenharmony_ci * This function also applies the group ID of the sender
100362306a36Sopenharmony_ci * if it is in the same mesh.
100462306a36Sopenharmony_ci *
100562306a36Sopenharmony_ci * Return:
100662306a36Sopenharmony_ci *	2  - if it is a claim packet and on the same group
100762306a36Sopenharmony_ci *	1  - if is a claim packet from another group
100862306a36Sopenharmony_ci *	0  - if it is not a claim packet
100962306a36Sopenharmony_ci */
101062306a36Sopenharmony_cistatic int batadv_check_claim_group(struct batadv_priv *bat_priv,
101162306a36Sopenharmony_ci				    struct batadv_hard_iface *primary_if,
101262306a36Sopenharmony_ci				    u8 *hw_src, u8 *hw_dst,
101362306a36Sopenharmony_ci				    struct ethhdr *ethhdr)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	u8 *backbone_addr;
101662306a36Sopenharmony_ci	struct batadv_orig_node *orig_node;
101762306a36Sopenharmony_ci	struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	bla_dst = (struct batadv_bla_claim_dst *)hw_dst;
102062306a36Sopenharmony_ci	bla_dst_own = &bat_priv->bla.claim_dest;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* if announcement packet, use the source,
102362306a36Sopenharmony_ci	 * otherwise assume it is in the hw_src
102462306a36Sopenharmony_ci	 */
102562306a36Sopenharmony_ci	switch (bla_dst->type) {
102662306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_CLAIM:
102762306a36Sopenharmony_ci		backbone_addr = hw_src;
102862306a36Sopenharmony_ci		break;
102962306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_REQUEST:
103062306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_ANNOUNCE:
103162306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_UNCLAIM:
103262306a36Sopenharmony_ci		backbone_addr = ethhdr->h_source;
103362306a36Sopenharmony_ci		break;
103462306a36Sopenharmony_ci	default:
103562306a36Sopenharmony_ci		return 0;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	/* don't accept claim frames from ourselves */
103962306a36Sopenharmony_ci	if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
104062306a36Sopenharmony_ci		return 0;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	/* if its already the same group, it is fine. */
104362306a36Sopenharmony_ci	if (bla_dst->group == bla_dst_own->group)
104462306a36Sopenharmony_ci		return 2;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	/* lets see if this originator is in our mesh */
104762306a36Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, backbone_addr);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	/* don't accept claims from gateways which are not in
105062306a36Sopenharmony_ci	 * the same mesh or group.
105162306a36Sopenharmony_ci	 */
105262306a36Sopenharmony_ci	if (!orig_node)
105362306a36Sopenharmony_ci		return 1;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* if our mesh friends mac is bigger, use it for ourselves. */
105662306a36Sopenharmony_ci	if (ntohs(bla_dst->group) > ntohs(bla_dst_own->group)) {
105762306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
105862306a36Sopenharmony_ci			   "taking other backbones claim group: %#.4x\n",
105962306a36Sopenharmony_ci			   ntohs(bla_dst->group));
106062306a36Sopenharmony_ci		bla_dst_own->group = bla_dst->group;
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	batadv_orig_node_put(orig_node);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	return 2;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci/**
106962306a36Sopenharmony_ci * batadv_bla_process_claim() - Check if this is a claim frame, and process it
107062306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
107162306a36Sopenharmony_ci * @primary_if: the primary hard interface of this batman soft interface
107262306a36Sopenharmony_ci * @skb: the frame to be checked
107362306a36Sopenharmony_ci *
107462306a36Sopenharmony_ci * Return: true if it was a claim frame, otherwise return false to
107562306a36Sopenharmony_ci * tell the callee that it can use the frame on its own.
107662306a36Sopenharmony_ci */
107762306a36Sopenharmony_cistatic bool batadv_bla_process_claim(struct batadv_priv *bat_priv,
107862306a36Sopenharmony_ci				     struct batadv_hard_iface *primary_if,
107962306a36Sopenharmony_ci				     struct sk_buff *skb)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;
108262306a36Sopenharmony_ci	u8 *hw_src, *hw_dst;
108362306a36Sopenharmony_ci	struct vlan_hdr *vhdr, vhdr_buf;
108462306a36Sopenharmony_ci	struct ethhdr *ethhdr;
108562306a36Sopenharmony_ci	struct arphdr *arphdr;
108662306a36Sopenharmony_ci	unsigned short vid;
108762306a36Sopenharmony_ci	int vlan_depth = 0;
108862306a36Sopenharmony_ci	__be16 proto;
108962306a36Sopenharmony_ci	int headlen;
109062306a36Sopenharmony_ci	int ret;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	vid = batadv_get_vid(skb, 0);
109362306a36Sopenharmony_ci	ethhdr = eth_hdr(skb);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	proto = ethhdr->h_proto;
109662306a36Sopenharmony_ci	headlen = ETH_HLEN;
109762306a36Sopenharmony_ci	if (vid & BATADV_VLAN_HAS_TAG) {
109862306a36Sopenharmony_ci		/* Traverse the VLAN/Ethertypes.
109962306a36Sopenharmony_ci		 *
110062306a36Sopenharmony_ci		 * At this point it is known that the first protocol is a VLAN
110162306a36Sopenharmony_ci		 * header, so start checking at the encapsulated protocol.
110262306a36Sopenharmony_ci		 *
110362306a36Sopenharmony_ci		 * The depth of the VLAN headers is recorded to drop BLA claim
110462306a36Sopenharmony_ci		 * frames encapsulated into multiple VLAN headers (QinQ).
110562306a36Sopenharmony_ci		 */
110662306a36Sopenharmony_ci		do {
110762306a36Sopenharmony_ci			vhdr = skb_header_pointer(skb, headlen, VLAN_HLEN,
110862306a36Sopenharmony_ci						  &vhdr_buf);
110962306a36Sopenharmony_ci			if (!vhdr)
111062306a36Sopenharmony_ci				return false;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci			proto = vhdr->h_vlan_encapsulated_proto;
111362306a36Sopenharmony_ci			headlen += VLAN_HLEN;
111462306a36Sopenharmony_ci			vlan_depth++;
111562306a36Sopenharmony_ci		} while (proto == htons(ETH_P_8021Q));
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	if (proto != htons(ETH_P_ARP))
111962306a36Sopenharmony_ci		return false; /* not a claim frame */
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	/* this must be a ARP frame. check if it is a claim. */
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	if (unlikely(!pskb_may_pull(skb, headlen + arp_hdr_len(skb->dev))))
112462306a36Sopenharmony_ci		return false;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	/* pskb_may_pull() may have modified the pointers, get ethhdr again */
112762306a36Sopenharmony_ci	ethhdr = eth_hdr(skb);
112862306a36Sopenharmony_ci	arphdr = (struct arphdr *)((u8 *)ethhdr + headlen);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	/* Check whether the ARP frame carries a valid
113162306a36Sopenharmony_ci	 * IP information
113262306a36Sopenharmony_ci	 */
113362306a36Sopenharmony_ci	if (arphdr->ar_hrd != htons(ARPHRD_ETHER))
113462306a36Sopenharmony_ci		return false;
113562306a36Sopenharmony_ci	if (arphdr->ar_pro != htons(ETH_P_IP))
113662306a36Sopenharmony_ci		return false;
113762306a36Sopenharmony_ci	if (arphdr->ar_hln != ETH_ALEN)
113862306a36Sopenharmony_ci		return false;
113962306a36Sopenharmony_ci	if (arphdr->ar_pln != 4)
114062306a36Sopenharmony_ci		return false;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	hw_src = (u8 *)arphdr + sizeof(struct arphdr);
114362306a36Sopenharmony_ci	hw_dst = hw_src + ETH_ALEN + 4;
114462306a36Sopenharmony_ci	bla_dst = (struct batadv_bla_claim_dst *)hw_dst;
114562306a36Sopenharmony_ci	bla_dst_own = &bat_priv->bla.claim_dest;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	/* check if it is a claim frame in general */
114862306a36Sopenharmony_ci	if (memcmp(bla_dst->magic, bla_dst_own->magic,
114962306a36Sopenharmony_ci		   sizeof(bla_dst->magic)) != 0)
115062306a36Sopenharmony_ci		return false;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	/* check if there is a claim frame encapsulated deeper in (QinQ) and
115362306a36Sopenharmony_ci	 * drop that, as this is not supported by BLA but should also not be
115462306a36Sopenharmony_ci	 * sent via the mesh.
115562306a36Sopenharmony_ci	 */
115662306a36Sopenharmony_ci	if (vlan_depth > 1)
115762306a36Sopenharmony_ci		return true;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	/* Let the loopdetect frames on the mesh in any case. */
116062306a36Sopenharmony_ci	if (bla_dst->type == BATADV_CLAIM_TYPE_LOOPDETECT)
116162306a36Sopenharmony_ci		return false;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	/* check if it is a claim frame. */
116462306a36Sopenharmony_ci	ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst,
116562306a36Sopenharmony_ci				       ethhdr);
116662306a36Sopenharmony_ci	if (ret == 1)
116762306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
116862306a36Sopenharmony_ci			   "%s(): received a claim frame from another group. From: %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
116962306a36Sopenharmony_ci			   __func__, ethhdr->h_source, batadv_print_vid(vid),
117062306a36Sopenharmony_ci			   hw_src, hw_dst);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (ret < 2)
117362306a36Sopenharmony_ci		return !!ret;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* become a backbone gw ourselves on this vlan if not happened yet */
117662306a36Sopenharmony_ci	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	/* check for the different types of claim frames ... */
117962306a36Sopenharmony_ci	switch (bla_dst->type) {
118062306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_CLAIM:
118162306a36Sopenharmony_ci		if (batadv_handle_claim(bat_priv, primary_if, hw_src,
118262306a36Sopenharmony_ci					ethhdr->h_source, vid))
118362306a36Sopenharmony_ci			return true;
118462306a36Sopenharmony_ci		break;
118562306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_UNCLAIM:
118662306a36Sopenharmony_ci		if (batadv_handle_unclaim(bat_priv, primary_if,
118762306a36Sopenharmony_ci					  ethhdr->h_source, hw_src, vid))
118862306a36Sopenharmony_ci			return true;
118962306a36Sopenharmony_ci		break;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_ANNOUNCE:
119262306a36Sopenharmony_ci		if (batadv_handle_announce(bat_priv, hw_src, ethhdr->h_source,
119362306a36Sopenharmony_ci					   vid))
119462306a36Sopenharmony_ci			return true;
119562306a36Sopenharmony_ci		break;
119662306a36Sopenharmony_ci	case BATADV_CLAIM_TYPE_REQUEST:
119762306a36Sopenharmony_ci		if (batadv_handle_request(bat_priv, primary_if, hw_src, ethhdr,
119862306a36Sopenharmony_ci					  vid))
119962306a36Sopenharmony_ci			return true;
120062306a36Sopenharmony_ci		break;
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv,
120462306a36Sopenharmony_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",
120562306a36Sopenharmony_ci		   __func__, ethhdr->h_source, batadv_print_vid(vid), hw_src,
120662306a36Sopenharmony_ci		   hw_dst);
120762306a36Sopenharmony_ci	return true;
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci/**
121162306a36Sopenharmony_ci * batadv_bla_purge_backbone_gw() - Remove backbone gateways after a timeout or
121262306a36Sopenharmony_ci *  immediately
121362306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
121462306a36Sopenharmony_ci * @now: whether the whole hash shall be wiped now
121562306a36Sopenharmony_ci *
121662306a36Sopenharmony_ci * Check when we last heard from other nodes, and remove them in case of
121762306a36Sopenharmony_ci * a time out, or clean all backbone gws if now is set.
121862306a36Sopenharmony_ci */
121962306a36Sopenharmony_cistatic void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
122262306a36Sopenharmony_ci	struct hlist_node *node_tmp;
122362306a36Sopenharmony_ci	struct hlist_head *head;
122462306a36Sopenharmony_ci	struct batadv_hashtable *hash;
122562306a36Sopenharmony_ci	spinlock_t *list_lock;	/* protects write access to the hash lists */
122662306a36Sopenharmony_ci	int i;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	hash = bat_priv->bla.backbone_hash;
122962306a36Sopenharmony_ci	if (!hash)
123062306a36Sopenharmony_ci		return;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
123362306a36Sopenharmony_ci		head = &hash->table[i];
123462306a36Sopenharmony_ci		list_lock = &hash->list_locks[i];
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci		spin_lock_bh(list_lock);
123762306a36Sopenharmony_ci		hlist_for_each_entry_safe(backbone_gw, node_tmp,
123862306a36Sopenharmony_ci					  head, hash_entry) {
123962306a36Sopenharmony_ci			if (now)
124062306a36Sopenharmony_ci				goto purge_now;
124162306a36Sopenharmony_ci			if (!batadv_has_timed_out(backbone_gw->lasttime,
124262306a36Sopenharmony_ci						  BATADV_BLA_BACKBONE_TIMEOUT))
124362306a36Sopenharmony_ci				continue;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
124662306a36Sopenharmony_ci				   "%s(): backbone gw %pM timed out\n",
124762306a36Sopenharmony_ci				   __func__, backbone_gw->orig);
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_cipurge_now:
125062306a36Sopenharmony_ci			/* don't wait for the pending request anymore */
125162306a36Sopenharmony_ci			if (atomic_read(&backbone_gw->request_sent))
125262306a36Sopenharmony_ci				atomic_dec(&bat_priv->bla.num_requests);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci			batadv_bla_del_backbone_claims(backbone_gw);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci			hlist_del_rcu(&backbone_gw->hash_entry);
125762306a36Sopenharmony_ci			batadv_backbone_gw_put(backbone_gw);
125862306a36Sopenharmony_ci		}
125962306a36Sopenharmony_ci		spin_unlock_bh(list_lock);
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci/**
126462306a36Sopenharmony_ci * batadv_bla_purge_claims() - Remove claims after a timeout or immediately
126562306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
126662306a36Sopenharmony_ci * @primary_if: the selected primary interface, may be NULL if now is set
126762306a36Sopenharmony_ci * @now: whether the whole hash shall be wiped now
126862306a36Sopenharmony_ci *
126962306a36Sopenharmony_ci * Check when we heard last time from our own claims, and remove them in case of
127062306a36Sopenharmony_ci * a time out, or clean all claims if now is set
127162306a36Sopenharmony_ci */
127262306a36Sopenharmony_cistatic void batadv_bla_purge_claims(struct batadv_priv *bat_priv,
127362306a36Sopenharmony_ci				    struct batadv_hard_iface *primary_if,
127462306a36Sopenharmony_ci				    int now)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
127762306a36Sopenharmony_ci	struct batadv_bla_claim *claim;
127862306a36Sopenharmony_ci	struct hlist_head *head;
127962306a36Sopenharmony_ci	struct batadv_hashtable *hash;
128062306a36Sopenharmony_ci	int i;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	hash = bat_priv->bla.claim_hash;
128362306a36Sopenharmony_ci	if (!hash)
128462306a36Sopenharmony_ci		return;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
128762306a36Sopenharmony_ci		head = &hash->table[i];
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci		rcu_read_lock();
129062306a36Sopenharmony_ci		hlist_for_each_entry_rcu(claim, head, hash_entry) {
129162306a36Sopenharmony_ci			backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
129262306a36Sopenharmony_ci			if (now)
129362306a36Sopenharmony_ci				goto purge_now;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci			if (!batadv_compare_eth(backbone_gw->orig,
129662306a36Sopenharmony_ci						primary_if->net_dev->dev_addr))
129762306a36Sopenharmony_ci				goto skip;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci			if (!batadv_has_timed_out(claim->lasttime,
130062306a36Sopenharmony_ci						  BATADV_BLA_CLAIM_TIMEOUT))
130162306a36Sopenharmony_ci				goto skip;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, bat_priv,
130462306a36Sopenharmony_ci				   "%s(): timed out.\n", __func__);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_cipurge_now:
130762306a36Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, bat_priv,
130862306a36Sopenharmony_ci				   "%s(): %pM, vid %d\n", __func__,
130962306a36Sopenharmony_ci				   claim->addr, claim->vid);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci			batadv_handle_unclaim(bat_priv, primary_if,
131262306a36Sopenharmony_ci					      backbone_gw->orig,
131362306a36Sopenharmony_ci					      claim->addr, claim->vid);
131462306a36Sopenharmony_ciskip:
131562306a36Sopenharmony_ci			batadv_backbone_gw_put(backbone_gw);
131662306a36Sopenharmony_ci		}
131762306a36Sopenharmony_ci		rcu_read_unlock();
131862306a36Sopenharmony_ci	}
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci/**
132262306a36Sopenharmony_ci * batadv_bla_update_orig_address() - Update the backbone gateways when the own
132362306a36Sopenharmony_ci *  originator address changes
132462306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
132562306a36Sopenharmony_ci * @primary_if: the new selected primary_if
132662306a36Sopenharmony_ci * @oldif: the old primary interface, may be NULL
132762306a36Sopenharmony_ci */
132862306a36Sopenharmony_civoid batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
132962306a36Sopenharmony_ci				    struct batadv_hard_iface *primary_if,
133062306a36Sopenharmony_ci				    struct batadv_hard_iface *oldif)
133162306a36Sopenharmony_ci{
133262306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
133362306a36Sopenharmony_ci	struct hlist_head *head;
133462306a36Sopenharmony_ci	struct batadv_hashtable *hash;
133562306a36Sopenharmony_ci	__be16 group;
133662306a36Sopenharmony_ci	int i;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	/* reset bridge loop avoidance group id */
133962306a36Sopenharmony_ci	group = htons(crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN));
134062306a36Sopenharmony_ci	bat_priv->bla.claim_dest.group = group;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	/* purge everything when bridge loop avoidance is turned off */
134362306a36Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
134462306a36Sopenharmony_ci		oldif = NULL;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (!oldif) {
134762306a36Sopenharmony_ci		batadv_bla_purge_claims(bat_priv, NULL, 1);
134862306a36Sopenharmony_ci		batadv_bla_purge_backbone_gw(bat_priv, 1);
134962306a36Sopenharmony_ci		return;
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	hash = bat_priv->bla.backbone_hash;
135362306a36Sopenharmony_ci	if (!hash)
135462306a36Sopenharmony_ci		return;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
135762306a36Sopenharmony_ci		head = &hash->table[i];
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		rcu_read_lock();
136062306a36Sopenharmony_ci		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
136162306a36Sopenharmony_ci			/* own orig still holds the old value. */
136262306a36Sopenharmony_ci			if (!batadv_compare_eth(backbone_gw->orig,
136362306a36Sopenharmony_ci						oldif->net_dev->dev_addr))
136462306a36Sopenharmony_ci				continue;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci			ether_addr_copy(backbone_gw->orig,
136762306a36Sopenharmony_ci					primary_if->net_dev->dev_addr);
136862306a36Sopenharmony_ci			/* send an announce frame so others will ask for our
136962306a36Sopenharmony_ci			 * claims and update their tables.
137062306a36Sopenharmony_ci			 */
137162306a36Sopenharmony_ci			batadv_bla_send_announce(bat_priv, backbone_gw);
137262306a36Sopenharmony_ci		}
137362306a36Sopenharmony_ci		rcu_read_unlock();
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci/**
137862306a36Sopenharmony_ci * batadv_bla_send_loopdetect() - send a loopdetect frame
137962306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
138062306a36Sopenharmony_ci * @backbone_gw: the backbone gateway for which a loop should be detected
138162306a36Sopenharmony_ci *
138262306a36Sopenharmony_ci * To detect loops that the bridge loop avoidance can't handle, send a loop
138362306a36Sopenharmony_ci * detection packet on the backbone. Unlike other BLA frames, this frame will
138462306a36Sopenharmony_ci * be allowed on the mesh by other nodes. If it is received on the mesh, this
138562306a36Sopenharmony_ci * indicates that there is a loop.
138662306a36Sopenharmony_ci */
138762306a36Sopenharmony_cistatic void
138862306a36Sopenharmony_cibatadv_bla_send_loopdetect(struct batadv_priv *bat_priv,
138962306a36Sopenharmony_ci			   struct batadv_bla_backbone_gw *backbone_gw)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv, "Send loopdetect frame for vid %d\n",
139262306a36Sopenharmony_ci		   backbone_gw->vid);
139362306a36Sopenharmony_ci	batadv_bla_send_claim(bat_priv, bat_priv->bla.loopdetect_addr,
139462306a36Sopenharmony_ci			      backbone_gw->vid, BATADV_CLAIM_TYPE_LOOPDETECT);
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci/**
139862306a36Sopenharmony_ci * batadv_bla_status_update() - purge bla interfaces if necessary
139962306a36Sopenharmony_ci * @net_dev: the soft interface net device
140062306a36Sopenharmony_ci */
140162306a36Sopenharmony_civoid batadv_bla_status_update(struct net_device *net_dev)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(net_dev);
140462306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
140762306a36Sopenharmony_ci	if (!primary_if)
140862306a36Sopenharmony_ci		return;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	/* this function already purges everything when bla is disabled,
141162306a36Sopenharmony_ci	 * so just call that one.
141262306a36Sopenharmony_ci	 */
141362306a36Sopenharmony_ci	batadv_bla_update_orig_address(bat_priv, primary_if, primary_if);
141462306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
141562306a36Sopenharmony_ci}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci/**
141862306a36Sopenharmony_ci * batadv_bla_periodic_work() - performs periodic bla work
141962306a36Sopenharmony_ci * @work: kernel work struct
142062306a36Sopenharmony_ci *
142162306a36Sopenharmony_ci * periodic work to do:
142262306a36Sopenharmony_ci *  * purge structures when they are too old
142362306a36Sopenharmony_ci *  * send announcements
142462306a36Sopenharmony_ci */
142562306a36Sopenharmony_cistatic void batadv_bla_periodic_work(struct work_struct *work)
142662306a36Sopenharmony_ci{
142762306a36Sopenharmony_ci	struct delayed_work *delayed_work;
142862306a36Sopenharmony_ci	struct batadv_priv *bat_priv;
142962306a36Sopenharmony_ci	struct batadv_priv_bla *priv_bla;
143062306a36Sopenharmony_ci	struct hlist_head *head;
143162306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
143262306a36Sopenharmony_ci	struct batadv_hashtable *hash;
143362306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
143462306a36Sopenharmony_ci	bool send_loopdetect = false;
143562306a36Sopenharmony_ci	int i;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	delayed_work = to_delayed_work(work);
143862306a36Sopenharmony_ci	priv_bla = container_of(delayed_work, struct batadv_priv_bla, work);
143962306a36Sopenharmony_ci	bat_priv = container_of(priv_bla, struct batadv_priv, bla);
144062306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
144162306a36Sopenharmony_ci	if (!primary_if)
144262306a36Sopenharmony_ci		goto out;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	batadv_bla_purge_claims(bat_priv, primary_if, 0);
144562306a36Sopenharmony_ci	batadv_bla_purge_backbone_gw(bat_priv, 0);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
144862306a36Sopenharmony_ci		goto out;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	if (atomic_dec_and_test(&bat_priv->bla.loopdetect_next)) {
145162306a36Sopenharmony_ci		/* set a new random mac address for the next bridge loop
145262306a36Sopenharmony_ci		 * detection frames. Set the locally administered bit to avoid
145362306a36Sopenharmony_ci		 * collisions with users mac addresses.
145462306a36Sopenharmony_ci		 */
145562306a36Sopenharmony_ci		eth_random_addr(bat_priv->bla.loopdetect_addr);
145662306a36Sopenharmony_ci		bat_priv->bla.loopdetect_addr[0] = 0xba;
145762306a36Sopenharmony_ci		bat_priv->bla.loopdetect_addr[1] = 0xbe;
145862306a36Sopenharmony_ci		bat_priv->bla.loopdetect_lasttime = jiffies;
145962306a36Sopenharmony_ci		atomic_set(&bat_priv->bla.loopdetect_next,
146062306a36Sopenharmony_ci			   BATADV_BLA_LOOPDETECT_PERIODS);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci		/* mark for sending loop detect on all VLANs */
146362306a36Sopenharmony_ci		send_loopdetect = true;
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	hash = bat_priv->bla.backbone_hash;
146762306a36Sopenharmony_ci	if (!hash)
146862306a36Sopenharmony_ci		goto out;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
147162306a36Sopenharmony_ci		head = &hash->table[i];
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci		rcu_read_lock();
147462306a36Sopenharmony_ci		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
147562306a36Sopenharmony_ci			if (!batadv_compare_eth(backbone_gw->orig,
147662306a36Sopenharmony_ci						primary_if->net_dev->dev_addr))
147762306a36Sopenharmony_ci				continue;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci			backbone_gw->lasttime = jiffies;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci			batadv_bla_send_announce(bat_priv, backbone_gw);
148262306a36Sopenharmony_ci			if (send_loopdetect)
148362306a36Sopenharmony_ci				batadv_bla_send_loopdetect(bat_priv,
148462306a36Sopenharmony_ci							   backbone_gw);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci			/* request_sent is only set after creation to avoid
148762306a36Sopenharmony_ci			 * problems when we are not yet known as backbone gw
148862306a36Sopenharmony_ci			 * in the backbone.
148962306a36Sopenharmony_ci			 *
149062306a36Sopenharmony_ci			 * We can reset this now after we waited some periods
149162306a36Sopenharmony_ci			 * to give bridge forward delays and bla group forming
149262306a36Sopenharmony_ci			 * some grace time.
149362306a36Sopenharmony_ci			 */
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci			if (atomic_read(&backbone_gw->request_sent) == 0)
149662306a36Sopenharmony_ci				continue;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci			if (!atomic_dec_and_test(&backbone_gw->wait_periods))
149962306a36Sopenharmony_ci				continue;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci			atomic_dec(&backbone_gw->bat_priv->bla.num_requests);
150262306a36Sopenharmony_ci			atomic_set(&backbone_gw->request_sent, 0);
150362306a36Sopenharmony_ci		}
150462306a36Sopenharmony_ci		rcu_read_unlock();
150562306a36Sopenharmony_ci	}
150662306a36Sopenharmony_ciout:
150762306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
151062306a36Sopenharmony_ci			   msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci/* The hash for claim and backbone hash receive the same key because they
151462306a36Sopenharmony_ci * are getting initialized by hash_new with the same key. Reinitializing
151562306a36Sopenharmony_ci * them with to different keys to allow nested locking without generating
151662306a36Sopenharmony_ci * lockdep warnings
151762306a36Sopenharmony_ci */
151862306a36Sopenharmony_cistatic struct lock_class_key batadv_claim_hash_lock_class_key;
151962306a36Sopenharmony_cistatic struct lock_class_key batadv_backbone_hash_lock_class_key;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci/**
152262306a36Sopenharmony_ci * batadv_bla_init() - initialize all bla structures
152362306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
152462306a36Sopenharmony_ci *
152562306a36Sopenharmony_ci * Return: 0 on success, < 0 on error.
152662306a36Sopenharmony_ci */
152762306a36Sopenharmony_ciint batadv_bla_init(struct batadv_priv *bat_priv)
152862306a36Sopenharmony_ci{
152962306a36Sopenharmony_ci	int i;
153062306a36Sopenharmony_ci	u8 claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00};
153162306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
153262306a36Sopenharmony_ci	u16 crc;
153362306a36Sopenharmony_ci	unsigned long entrytime;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	spin_lock_init(&bat_priv->bla.bcast_duplist_lock);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hash registering\n");
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	/* setting claim destination address */
154062306a36Sopenharmony_ci	memcpy(&bat_priv->bla.claim_dest.magic, claim_dest, 3);
154162306a36Sopenharmony_ci	bat_priv->bla.claim_dest.type = 0;
154262306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
154362306a36Sopenharmony_ci	if (primary_if) {
154462306a36Sopenharmony_ci		crc = crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN);
154562306a36Sopenharmony_ci		bat_priv->bla.claim_dest.group = htons(crc);
154662306a36Sopenharmony_ci		batadv_hardif_put(primary_if);
154762306a36Sopenharmony_ci	} else {
154862306a36Sopenharmony_ci		bat_priv->bla.claim_dest.group = 0; /* will be set later */
154962306a36Sopenharmony_ci	}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	/* initialize the duplicate list */
155262306a36Sopenharmony_ci	entrytime = jiffies - msecs_to_jiffies(BATADV_DUPLIST_TIMEOUT);
155362306a36Sopenharmony_ci	for (i = 0; i < BATADV_DUPLIST_SIZE; i++)
155462306a36Sopenharmony_ci		bat_priv->bla.bcast_duplist[i].entrytime = entrytime;
155562306a36Sopenharmony_ci	bat_priv->bla.bcast_duplist_curr = 0;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	atomic_set(&bat_priv->bla.loopdetect_next,
155862306a36Sopenharmony_ci		   BATADV_BLA_LOOPDETECT_PERIODS);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	if (bat_priv->bla.claim_hash)
156162306a36Sopenharmony_ci		return 0;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	bat_priv->bla.claim_hash = batadv_hash_new(128);
156462306a36Sopenharmony_ci	if (!bat_priv->bla.claim_hash)
156562306a36Sopenharmony_ci		return -ENOMEM;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	bat_priv->bla.backbone_hash = batadv_hash_new(32);
156862306a36Sopenharmony_ci	if (!bat_priv->bla.backbone_hash) {
156962306a36Sopenharmony_ci		batadv_hash_destroy(bat_priv->bla.claim_hash);
157062306a36Sopenharmony_ci		return -ENOMEM;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	batadv_hash_set_lock_class(bat_priv->bla.claim_hash,
157462306a36Sopenharmony_ci				   &batadv_claim_hash_lock_class_key);
157562306a36Sopenharmony_ci	batadv_hash_set_lock_class(bat_priv->bla.backbone_hash,
157662306a36Sopenharmony_ci				   &batadv_backbone_hash_lock_class_key);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hashes initialized\n");
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	INIT_DELAYED_WORK(&bat_priv->bla.work, batadv_bla_periodic_work);
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
158362306a36Sopenharmony_ci			   msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
158462306a36Sopenharmony_ci	return 0;
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci/**
158862306a36Sopenharmony_ci * batadv_bla_check_duplist() - Check if a frame is in the broadcast dup.
158962306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
159062306a36Sopenharmony_ci * @skb: contains the multicast packet to be checked
159162306a36Sopenharmony_ci * @payload_ptr: pointer to position inside the head buffer of the skb
159262306a36Sopenharmony_ci *  marking the start of the data to be CRC'ed
159362306a36Sopenharmony_ci * @orig: originator mac address, NULL if unknown
159462306a36Sopenharmony_ci *
159562306a36Sopenharmony_ci * Check if it is on our broadcast list. Another gateway might have sent the
159662306a36Sopenharmony_ci * same packet because it is connected to the same backbone, so we have to
159762306a36Sopenharmony_ci * remove this duplicate.
159862306a36Sopenharmony_ci *
159962306a36Sopenharmony_ci * This is performed by checking the CRC, which will tell us
160062306a36Sopenharmony_ci * with a good chance that it is the same packet. If it is furthermore
160162306a36Sopenharmony_ci * sent by another host, drop it. We allow equal packets from
160262306a36Sopenharmony_ci * the same host however as this might be intended.
160362306a36Sopenharmony_ci *
160462306a36Sopenharmony_ci * Return: true if a packet is in the duplicate list, false otherwise.
160562306a36Sopenharmony_ci */
160662306a36Sopenharmony_cistatic bool batadv_bla_check_duplist(struct batadv_priv *bat_priv,
160762306a36Sopenharmony_ci				     struct sk_buff *skb, u8 *payload_ptr,
160862306a36Sopenharmony_ci				     const u8 *orig)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci	struct batadv_bcast_duplist_entry *entry;
161162306a36Sopenharmony_ci	bool ret = false;
161262306a36Sopenharmony_ci	int i, curr;
161362306a36Sopenharmony_ci	__be32 crc;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	/* calculate the crc ... */
161662306a36Sopenharmony_ci	crc = batadv_skb_crc32(skb, payload_ptr);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	spin_lock_bh(&bat_priv->bla.bcast_duplist_lock);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	for (i = 0; i < BATADV_DUPLIST_SIZE; i++) {
162162306a36Sopenharmony_ci		curr = (bat_priv->bla.bcast_duplist_curr + i);
162262306a36Sopenharmony_ci		curr %= BATADV_DUPLIST_SIZE;
162362306a36Sopenharmony_ci		entry = &bat_priv->bla.bcast_duplist[curr];
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci		/* we can stop searching if the entry is too old ;
162662306a36Sopenharmony_ci		 * later entries will be even older
162762306a36Sopenharmony_ci		 */
162862306a36Sopenharmony_ci		if (batadv_has_timed_out(entry->entrytime,
162962306a36Sopenharmony_ci					 BATADV_DUPLIST_TIMEOUT))
163062306a36Sopenharmony_ci			break;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci		if (entry->crc != crc)
163362306a36Sopenharmony_ci			continue;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci		/* are the originators both known and not anonymous? */
163662306a36Sopenharmony_ci		if (orig && !is_zero_ether_addr(orig) &&
163762306a36Sopenharmony_ci		    !is_zero_ether_addr(entry->orig)) {
163862306a36Sopenharmony_ci			/* If known, check if the new frame came from
163962306a36Sopenharmony_ci			 * the same originator:
164062306a36Sopenharmony_ci			 * We are safe to take identical frames from the
164162306a36Sopenharmony_ci			 * same orig, if known, as multiplications in
164262306a36Sopenharmony_ci			 * the mesh are detected via the (orig, seqno) pair.
164362306a36Sopenharmony_ci			 * So we can be a bit more liberal here and allow
164462306a36Sopenharmony_ci			 * identical frames from the same orig which the source
164562306a36Sopenharmony_ci			 * host might have sent multiple times on purpose.
164662306a36Sopenharmony_ci			 */
164762306a36Sopenharmony_ci			if (batadv_compare_eth(entry->orig, orig))
164862306a36Sopenharmony_ci				continue;
164962306a36Sopenharmony_ci		}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		/* this entry seems to match: same crc, not too old,
165262306a36Sopenharmony_ci		 * and from another gw. therefore return true to forbid it.
165362306a36Sopenharmony_ci		 */
165462306a36Sopenharmony_ci		ret = true;
165562306a36Sopenharmony_ci		goto out;
165662306a36Sopenharmony_ci	}
165762306a36Sopenharmony_ci	/* not found, add a new entry (overwrite the oldest entry)
165862306a36Sopenharmony_ci	 * and allow it, its the first occurrence.
165962306a36Sopenharmony_ci	 */
166062306a36Sopenharmony_ci	curr = (bat_priv->bla.bcast_duplist_curr + BATADV_DUPLIST_SIZE - 1);
166162306a36Sopenharmony_ci	curr %= BATADV_DUPLIST_SIZE;
166262306a36Sopenharmony_ci	entry = &bat_priv->bla.bcast_duplist[curr];
166362306a36Sopenharmony_ci	entry->crc = crc;
166462306a36Sopenharmony_ci	entry->entrytime = jiffies;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	/* known originator */
166762306a36Sopenharmony_ci	if (orig)
166862306a36Sopenharmony_ci		ether_addr_copy(entry->orig, orig);
166962306a36Sopenharmony_ci	/* anonymous originator */
167062306a36Sopenharmony_ci	else
167162306a36Sopenharmony_ci		eth_zero_addr(entry->orig);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	bat_priv->bla.bcast_duplist_curr = curr;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ciout:
167662306a36Sopenharmony_ci	spin_unlock_bh(&bat_priv->bla.bcast_duplist_lock);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	return ret;
167962306a36Sopenharmony_ci}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci/**
168262306a36Sopenharmony_ci * batadv_bla_check_ucast_duplist() - Check if a frame is in the broadcast dup.
168362306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
168462306a36Sopenharmony_ci * @skb: contains the multicast packet to be checked, decapsulated from a
168562306a36Sopenharmony_ci *  unicast_packet
168662306a36Sopenharmony_ci *
168762306a36Sopenharmony_ci * Check if it is on our broadcast list. Another gateway might have sent the
168862306a36Sopenharmony_ci * same packet because it is connected to the same backbone, so we have to
168962306a36Sopenharmony_ci * remove this duplicate.
169062306a36Sopenharmony_ci *
169162306a36Sopenharmony_ci * Return: true if a packet is in the duplicate list, false otherwise.
169262306a36Sopenharmony_ci */
169362306a36Sopenharmony_cistatic bool batadv_bla_check_ucast_duplist(struct batadv_priv *bat_priv,
169462306a36Sopenharmony_ci					   struct sk_buff *skb)
169562306a36Sopenharmony_ci{
169662306a36Sopenharmony_ci	return batadv_bla_check_duplist(bat_priv, skb, (u8 *)skb->data, NULL);
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci/**
170062306a36Sopenharmony_ci * batadv_bla_check_bcast_duplist() - Check if a frame is in the broadcast dup.
170162306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
170262306a36Sopenharmony_ci * @skb: contains the bcast_packet to be checked
170362306a36Sopenharmony_ci *
170462306a36Sopenharmony_ci * Check if it is on our broadcast list. Another gateway might have sent the
170562306a36Sopenharmony_ci * same packet because it is connected to the same backbone, so we have to
170662306a36Sopenharmony_ci * remove this duplicate.
170762306a36Sopenharmony_ci *
170862306a36Sopenharmony_ci * Return: true if a packet is in the duplicate list, false otherwise.
170962306a36Sopenharmony_ci */
171062306a36Sopenharmony_cibool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
171162306a36Sopenharmony_ci				    struct sk_buff *skb)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	struct batadv_bcast_packet *bcast_packet;
171462306a36Sopenharmony_ci	u8 *payload_ptr;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	bcast_packet = (struct batadv_bcast_packet *)skb->data;
171762306a36Sopenharmony_ci	payload_ptr = (u8 *)(bcast_packet + 1);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	return batadv_bla_check_duplist(bat_priv, skb, payload_ptr,
172062306a36Sopenharmony_ci					bcast_packet->orig);
172162306a36Sopenharmony_ci}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci/**
172462306a36Sopenharmony_ci * batadv_bla_is_backbone_gw_orig() - Check if the originator is a gateway for
172562306a36Sopenharmony_ci *  the VLAN identified by vid.
172662306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
172762306a36Sopenharmony_ci * @orig: originator mac address
172862306a36Sopenharmony_ci * @vid: VLAN identifier
172962306a36Sopenharmony_ci *
173062306a36Sopenharmony_ci * Return: true if orig is a backbone for this vid, false otherwise.
173162306a36Sopenharmony_ci */
173262306a36Sopenharmony_cibool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig,
173362306a36Sopenharmony_ci				    unsigned short vid)
173462306a36Sopenharmony_ci{
173562306a36Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
173662306a36Sopenharmony_ci	struct hlist_head *head;
173762306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
173862306a36Sopenharmony_ci	int i;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
174162306a36Sopenharmony_ci		return false;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	if (!hash)
174462306a36Sopenharmony_ci		return false;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
174762306a36Sopenharmony_ci		head = &hash->table[i];
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci		rcu_read_lock();
175062306a36Sopenharmony_ci		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
175162306a36Sopenharmony_ci			if (batadv_compare_eth(backbone_gw->orig, orig) &&
175262306a36Sopenharmony_ci			    backbone_gw->vid == vid) {
175362306a36Sopenharmony_ci				rcu_read_unlock();
175462306a36Sopenharmony_ci				return true;
175562306a36Sopenharmony_ci			}
175662306a36Sopenharmony_ci		}
175762306a36Sopenharmony_ci		rcu_read_unlock();
175862306a36Sopenharmony_ci	}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	return false;
176162306a36Sopenharmony_ci}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci/**
176462306a36Sopenharmony_ci * batadv_bla_is_backbone_gw() - check if originator is a backbone gw for a VLAN
176562306a36Sopenharmony_ci * @skb: the frame to be checked
176662306a36Sopenharmony_ci * @orig_node: the orig_node of the frame
176762306a36Sopenharmony_ci * @hdr_size: maximum length of the frame
176862306a36Sopenharmony_ci *
176962306a36Sopenharmony_ci * Return: true if the orig_node is also a gateway on the soft interface,
177062306a36Sopenharmony_ci * otherwise it returns false.
177162306a36Sopenharmony_ci */
177262306a36Sopenharmony_cibool batadv_bla_is_backbone_gw(struct sk_buff *skb,
177362306a36Sopenharmony_ci			       struct batadv_orig_node *orig_node, int hdr_size)
177462306a36Sopenharmony_ci{
177562306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
177662306a36Sopenharmony_ci	unsigned short vid;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))
177962306a36Sopenharmony_ci		return false;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	/* first, find out the vid. */
178262306a36Sopenharmony_ci	if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
178362306a36Sopenharmony_ci		return false;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	vid = batadv_get_vid(skb, hdr_size);
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	/* see if this originator is a backbone gw for this VLAN */
178862306a36Sopenharmony_ci	backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,
178962306a36Sopenharmony_ci						orig_node->orig, vid);
179062306a36Sopenharmony_ci	if (!backbone_gw)
179162306a36Sopenharmony_ci		return false;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
179462306a36Sopenharmony_ci	return true;
179562306a36Sopenharmony_ci}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci/**
179862306a36Sopenharmony_ci * batadv_bla_free() - free all bla structures
179962306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
180062306a36Sopenharmony_ci *
180162306a36Sopenharmony_ci * for softinterface free or module unload
180262306a36Sopenharmony_ci */
180362306a36Sopenharmony_civoid batadv_bla_free(struct batadv_priv *bat_priv)
180462306a36Sopenharmony_ci{
180562306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	cancel_delayed_work_sync(&bat_priv->bla.work);
180862306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	if (bat_priv->bla.claim_hash) {
181162306a36Sopenharmony_ci		batadv_bla_purge_claims(bat_priv, primary_if, 1);
181262306a36Sopenharmony_ci		batadv_hash_destroy(bat_priv->bla.claim_hash);
181362306a36Sopenharmony_ci		bat_priv->bla.claim_hash = NULL;
181462306a36Sopenharmony_ci	}
181562306a36Sopenharmony_ci	if (bat_priv->bla.backbone_hash) {
181662306a36Sopenharmony_ci		batadv_bla_purge_backbone_gw(bat_priv, 1);
181762306a36Sopenharmony_ci		batadv_hash_destroy(bat_priv->bla.backbone_hash);
181862306a36Sopenharmony_ci		bat_priv->bla.backbone_hash = NULL;
181962306a36Sopenharmony_ci	}
182062306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
182162306a36Sopenharmony_ci}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci/**
182462306a36Sopenharmony_ci * batadv_bla_loopdetect_check() - check and handle a detected loop
182562306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
182662306a36Sopenharmony_ci * @skb: the packet to check
182762306a36Sopenharmony_ci * @primary_if: interface where the request came on
182862306a36Sopenharmony_ci * @vid: the VLAN ID of the frame
182962306a36Sopenharmony_ci *
183062306a36Sopenharmony_ci * Checks if this packet is a loop detect frame which has been sent by us,
183162306a36Sopenharmony_ci * throws an uevent and logs the event if that is the case.
183262306a36Sopenharmony_ci *
183362306a36Sopenharmony_ci * Return: true if it is a loop detect frame which is to be dropped, false
183462306a36Sopenharmony_ci * otherwise.
183562306a36Sopenharmony_ci */
183662306a36Sopenharmony_cistatic bool
183762306a36Sopenharmony_cibatadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,
183862306a36Sopenharmony_ci			    struct batadv_hard_iface *primary_if,
183962306a36Sopenharmony_ci			    unsigned short vid)
184062306a36Sopenharmony_ci{
184162306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
184262306a36Sopenharmony_ci	struct ethhdr *ethhdr;
184362306a36Sopenharmony_ci	bool ret;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	ethhdr = eth_hdr(skb);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	/* Only check for the MAC address and skip more checks here for
184862306a36Sopenharmony_ci	 * performance reasons - this function is on the hotpath, after all.
184962306a36Sopenharmony_ci	 */
185062306a36Sopenharmony_ci	if (!batadv_compare_eth(ethhdr->h_source,
185162306a36Sopenharmony_ci				bat_priv->bla.loopdetect_addr))
185262306a36Sopenharmony_ci		return false;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	/* If the packet came too late, don't forward it on the mesh
185562306a36Sopenharmony_ci	 * but don't consider that as loop. It might be a coincidence.
185662306a36Sopenharmony_ci	 */
185762306a36Sopenharmony_ci	if (batadv_has_timed_out(bat_priv->bla.loopdetect_lasttime,
185862306a36Sopenharmony_ci				 BATADV_BLA_LOOPDETECT_TIMEOUT))
185962306a36Sopenharmony_ci		return true;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	backbone_gw = batadv_bla_get_backbone_gw(bat_priv,
186262306a36Sopenharmony_ci						 primary_if->net_dev->dev_addr,
186362306a36Sopenharmony_ci						 vid, true);
186462306a36Sopenharmony_ci	if (unlikely(!backbone_gw))
186562306a36Sopenharmony_ci		return true;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	ret = queue_work(batadv_event_workqueue, &backbone_gw->report_work);
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	/* backbone_gw is unreferenced in the report work function
187062306a36Sopenharmony_ci	 * if queue_work() call was successful
187162306a36Sopenharmony_ci	 */
187262306a36Sopenharmony_ci	if (!ret)
187362306a36Sopenharmony_ci		batadv_backbone_gw_put(backbone_gw);
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	return true;
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci/**
187962306a36Sopenharmony_ci * batadv_bla_rx() - check packets coming from the mesh.
188062306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
188162306a36Sopenharmony_ci * @skb: the frame to be checked
188262306a36Sopenharmony_ci * @vid: the VLAN ID of the frame
188362306a36Sopenharmony_ci * @packet_type: the batman packet type this frame came in
188462306a36Sopenharmony_ci *
188562306a36Sopenharmony_ci * batadv_bla_rx avoidance checks if:
188662306a36Sopenharmony_ci *  * we have to race for a claim
188762306a36Sopenharmony_ci *  * if the frame is allowed on the LAN
188862306a36Sopenharmony_ci *
188962306a36Sopenharmony_ci * In these cases, the skb is further handled by this function
189062306a36Sopenharmony_ci *
189162306a36Sopenharmony_ci * Return: true if handled, otherwise it returns false and the caller shall
189262306a36Sopenharmony_ci * further process the skb.
189362306a36Sopenharmony_ci */
189462306a36Sopenharmony_cibool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
189562306a36Sopenharmony_ci		   unsigned short vid, int packet_type)
189662306a36Sopenharmony_ci{
189762306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
189862306a36Sopenharmony_ci	struct ethhdr *ethhdr;
189962306a36Sopenharmony_ci	struct batadv_bla_claim search_claim, *claim = NULL;
190062306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
190162306a36Sopenharmony_ci	bool own_claim;
190262306a36Sopenharmony_ci	bool ret;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	ethhdr = eth_hdr(skb);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
190762306a36Sopenharmony_ci	if (!primary_if)
190862306a36Sopenharmony_ci		goto handled;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
191162306a36Sopenharmony_ci		goto allow;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (batadv_bla_loopdetect_check(bat_priv, skb, primary_if, vid))
191462306a36Sopenharmony_ci		goto handled;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	if (unlikely(atomic_read(&bat_priv->bla.num_requests)))
191762306a36Sopenharmony_ci		/* don't allow multicast packets while requests are in flight */
191862306a36Sopenharmony_ci		if (is_multicast_ether_addr(ethhdr->h_dest))
191962306a36Sopenharmony_ci			/* Both broadcast flooding or multicast-via-unicasts
192062306a36Sopenharmony_ci			 * delivery might send to multiple backbone gateways
192162306a36Sopenharmony_ci			 * sharing the same LAN and therefore need to coordinate
192262306a36Sopenharmony_ci			 * which backbone gateway forwards into the LAN,
192362306a36Sopenharmony_ci			 * by claiming the payload source address.
192462306a36Sopenharmony_ci			 *
192562306a36Sopenharmony_ci			 * Broadcast flooding and multicast-via-unicasts
192662306a36Sopenharmony_ci			 * delivery use the following two batman packet types.
192762306a36Sopenharmony_ci			 * Note: explicitly exclude BATADV_UNICAST_4ADDR,
192862306a36Sopenharmony_ci			 * as the DHCP gateway feature will send explicitly
192962306a36Sopenharmony_ci			 * to only one BLA gateway, so the claiming process
193062306a36Sopenharmony_ci			 * should be avoided there.
193162306a36Sopenharmony_ci			 */
193262306a36Sopenharmony_ci			if (packet_type == BATADV_BCAST ||
193362306a36Sopenharmony_ci			    packet_type == BATADV_UNICAST)
193462306a36Sopenharmony_ci				goto handled;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	/* potential duplicates from foreign BLA backbone gateways via
193762306a36Sopenharmony_ci	 * multicast-in-unicast packets
193862306a36Sopenharmony_ci	 */
193962306a36Sopenharmony_ci	if (is_multicast_ether_addr(ethhdr->h_dest) &&
194062306a36Sopenharmony_ci	    packet_type == BATADV_UNICAST &&
194162306a36Sopenharmony_ci	    batadv_bla_check_ucast_duplist(bat_priv, skb))
194262306a36Sopenharmony_ci		goto handled;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	ether_addr_copy(search_claim.addr, ethhdr->h_source);
194562306a36Sopenharmony_ci	search_claim.vid = vid;
194662306a36Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	if (!claim) {
194962306a36Sopenharmony_ci		/* possible optimization: race for a claim */
195062306a36Sopenharmony_ci		/* No claim exists yet, claim it for us!
195162306a36Sopenharmony_ci		 */
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BLA, bat_priv,
195462306a36Sopenharmony_ci			   "%s(): Unclaimed MAC %pM found. Claim it. Local: %s\n",
195562306a36Sopenharmony_ci			   __func__, ethhdr->h_source,
195662306a36Sopenharmony_ci			   batadv_is_my_client(bat_priv,
195762306a36Sopenharmony_ci					       ethhdr->h_source, vid) ?
195862306a36Sopenharmony_ci			   "yes" : "no");
195962306a36Sopenharmony_ci		batadv_handle_claim(bat_priv, primary_if,
196062306a36Sopenharmony_ci				    primary_if->net_dev->dev_addr,
196162306a36Sopenharmony_ci				    ethhdr->h_source, vid);
196262306a36Sopenharmony_ci		goto allow;
196362306a36Sopenharmony_ci	}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	/* if it is our own claim ... */
196662306a36Sopenharmony_ci	backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
196762306a36Sopenharmony_ci	own_claim = batadv_compare_eth(backbone_gw->orig,
196862306a36Sopenharmony_ci				       primary_if->net_dev->dev_addr);
196962306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	if (own_claim) {
197262306a36Sopenharmony_ci		/* ... allow it in any case */
197362306a36Sopenharmony_ci		claim->lasttime = jiffies;
197462306a36Sopenharmony_ci		goto allow;
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	/* if it is a multicast ... */
197862306a36Sopenharmony_ci	if (is_multicast_ether_addr(ethhdr->h_dest) &&
197962306a36Sopenharmony_ci	    (packet_type == BATADV_BCAST || packet_type == BATADV_UNICAST)) {
198062306a36Sopenharmony_ci		/* ... drop it. the responsible gateway is in charge.
198162306a36Sopenharmony_ci		 *
198262306a36Sopenharmony_ci		 * We need to check packet type because with the gateway
198362306a36Sopenharmony_ci		 * feature, broadcasts (like DHCP requests) may be sent
198462306a36Sopenharmony_ci		 * using a unicast 4 address packet type. See comment above.
198562306a36Sopenharmony_ci		 */
198662306a36Sopenharmony_ci		goto handled;
198762306a36Sopenharmony_ci	} else {
198862306a36Sopenharmony_ci		/* seems the client considers us as its best gateway.
198962306a36Sopenharmony_ci		 * send a claim and update the claim table
199062306a36Sopenharmony_ci		 * immediately.
199162306a36Sopenharmony_ci		 */
199262306a36Sopenharmony_ci		batadv_handle_claim(bat_priv, primary_if,
199362306a36Sopenharmony_ci				    primary_if->net_dev->dev_addr,
199462306a36Sopenharmony_ci				    ethhdr->h_source, vid);
199562306a36Sopenharmony_ci		goto allow;
199662306a36Sopenharmony_ci	}
199762306a36Sopenharmony_ciallow:
199862306a36Sopenharmony_ci	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
199962306a36Sopenharmony_ci	ret = false;
200062306a36Sopenharmony_ci	goto out;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_cihandled:
200362306a36Sopenharmony_ci	kfree_skb(skb);
200462306a36Sopenharmony_ci	ret = true;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ciout:
200762306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
200862306a36Sopenharmony_ci	batadv_claim_put(claim);
200962306a36Sopenharmony_ci	return ret;
201062306a36Sopenharmony_ci}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci/**
201362306a36Sopenharmony_ci * batadv_bla_tx() - check packets going into the mesh
201462306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
201562306a36Sopenharmony_ci * @skb: the frame to be checked
201662306a36Sopenharmony_ci * @vid: the VLAN ID of the frame
201762306a36Sopenharmony_ci *
201862306a36Sopenharmony_ci * batadv_bla_tx checks if:
201962306a36Sopenharmony_ci *  * a claim was received which has to be processed
202062306a36Sopenharmony_ci *  * the frame is allowed on the mesh
202162306a36Sopenharmony_ci *
202262306a36Sopenharmony_ci * in these cases, the skb is further handled by this function.
202362306a36Sopenharmony_ci *
202462306a36Sopenharmony_ci * This call might reallocate skb data.
202562306a36Sopenharmony_ci *
202662306a36Sopenharmony_ci * Return: true if handled, otherwise it returns false and the caller shall
202762306a36Sopenharmony_ci * further process the skb.
202862306a36Sopenharmony_ci */
202962306a36Sopenharmony_cibool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
203062306a36Sopenharmony_ci		   unsigned short vid)
203162306a36Sopenharmony_ci{
203262306a36Sopenharmony_ci	struct ethhdr *ethhdr;
203362306a36Sopenharmony_ci	struct batadv_bla_claim search_claim, *claim = NULL;
203462306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
203562306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
203662306a36Sopenharmony_ci	bool client_roamed;
203762306a36Sopenharmony_ci	bool ret = false;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
204062306a36Sopenharmony_ci	if (!primary_if)
204162306a36Sopenharmony_ci		goto out;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
204462306a36Sopenharmony_ci		goto allow;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	if (batadv_bla_process_claim(bat_priv, primary_if, skb))
204762306a36Sopenharmony_ci		goto handled;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	ethhdr = eth_hdr(skb);
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	if (unlikely(atomic_read(&bat_priv->bla.num_requests)))
205262306a36Sopenharmony_ci		/* don't allow broadcasts while requests are in flight */
205362306a36Sopenharmony_ci		if (is_multicast_ether_addr(ethhdr->h_dest))
205462306a36Sopenharmony_ci			goto handled;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	ether_addr_copy(search_claim.addr, ethhdr->h_source);
205762306a36Sopenharmony_ci	search_claim.vid = vid;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	/* if no claim exists, allow it. */
206262306a36Sopenharmony_ci	if (!claim)
206362306a36Sopenharmony_ci		goto allow;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	/* check if we are responsible. */
206662306a36Sopenharmony_ci	backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
206762306a36Sopenharmony_ci	client_roamed = batadv_compare_eth(backbone_gw->orig,
206862306a36Sopenharmony_ci					   primary_if->net_dev->dev_addr);
206962306a36Sopenharmony_ci	batadv_backbone_gw_put(backbone_gw);
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	if (client_roamed) {
207262306a36Sopenharmony_ci		/* if yes, the client has roamed and we have
207362306a36Sopenharmony_ci		 * to unclaim it.
207462306a36Sopenharmony_ci		 */
207562306a36Sopenharmony_ci		if (batadv_has_timed_out(claim->lasttime, 100)) {
207662306a36Sopenharmony_ci			/* only unclaim if the last claim entry is
207762306a36Sopenharmony_ci			 * older than 100 ms to make sure we really
207862306a36Sopenharmony_ci			 * have a roaming client here.
207962306a36Sopenharmony_ci			 */
208062306a36Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Roaming client %pM detected. Unclaim it.\n",
208162306a36Sopenharmony_ci				   __func__, ethhdr->h_source);
208262306a36Sopenharmony_ci			batadv_handle_unclaim(bat_priv, primary_if,
208362306a36Sopenharmony_ci					      primary_if->net_dev->dev_addr,
208462306a36Sopenharmony_ci					      ethhdr->h_source, vid);
208562306a36Sopenharmony_ci			goto allow;
208662306a36Sopenharmony_ci		} else {
208762306a36Sopenharmony_ci			batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Race for claim %pM detected. Drop packet.\n",
208862306a36Sopenharmony_ci				   __func__, ethhdr->h_source);
208962306a36Sopenharmony_ci			goto handled;
209062306a36Sopenharmony_ci		}
209162306a36Sopenharmony_ci	}
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	/* check if it is a multicast/broadcast frame */
209462306a36Sopenharmony_ci	if (is_multicast_ether_addr(ethhdr->h_dest)) {
209562306a36Sopenharmony_ci		/* drop it. the responsible gateway has forwarded it into
209662306a36Sopenharmony_ci		 * the backbone network.
209762306a36Sopenharmony_ci		 */
209862306a36Sopenharmony_ci		goto handled;
209962306a36Sopenharmony_ci	} else {
210062306a36Sopenharmony_ci		/* we must allow it. at least if we are
210162306a36Sopenharmony_ci		 * responsible for the DESTINATION.
210262306a36Sopenharmony_ci		 */
210362306a36Sopenharmony_ci		goto allow;
210462306a36Sopenharmony_ci	}
210562306a36Sopenharmony_ciallow:
210662306a36Sopenharmony_ci	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
210762306a36Sopenharmony_ci	ret = false;
210862306a36Sopenharmony_ci	goto out;
210962306a36Sopenharmony_cihandled:
211062306a36Sopenharmony_ci	ret = true;
211162306a36Sopenharmony_ciout:
211262306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
211362306a36Sopenharmony_ci	batadv_claim_put(claim);
211462306a36Sopenharmony_ci	return ret;
211562306a36Sopenharmony_ci}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci/**
211862306a36Sopenharmony_ci * batadv_bla_claim_dump_entry() - dump one entry of the claim table
211962306a36Sopenharmony_ci * to a netlink socket
212062306a36Sopenharmony_ci * @msg: buffer for the message
212162306a36Sopenharmony_ci * @portid: netlink port
212262306a36Sopenharmony_ci * @cb: Control block containing additional options
212362306a36Sopenharmony_ci * @primary_if: primary interface
212462306a36Sopenharmony_ci * @claim: entry to dump
212562306a36Sopenharmony_ci *
212662306a36Sopenharmony_ci * Return: 0 or error code.
212762306a36Sopenharmony_ci */
212862306a36Sopenharmony_cistatic int
212962306a36Sopenharmony_cibatadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,
213062306a36Sopenharmony_ci			    struct netlink_callback *cb,
213162306a36Sopenharmony_ci			    struct batadv_hard_iface *primary_if,
213262306a36Sopenharmony_ci			    struct batadv_bla_claim *claim)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	const u8 *primary_addr = primary_if->net_dev->dev_addr;
213562306a36Sopenharmony_ci	u16 backbone_crc;
213662306a36Sopenharmony_ci	bool is_own;
213762306a36Sopenharmony_ci	void *hdr;
213862306a36Sopenharmony_ci	int ret = -EINVAL;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
214162306a36Sopenharmony_ci			  &batadv_netlink_family, NLM_F_MULTI,
214262306a36Sopenharmony_ci			  BATADV_CMD_GET_BLA_CLAIM);
214362306a36Sopenharmony_ci	if (!hdr) {
214462306a36Sopenharmony_ci		ret = -ENOBUFS;
214562306a36Sopenharmony_ci		goto out;
214662306a36Sopenharmony_ci	}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	genl_dump_check_consistent(cb, hdr);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	is_own = batadv_compare_eth(claim->backbone_gw->orig,
215162306a36Sopenharmony_ci				    primary_addr);
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	spin_lock_bh(&claim->backbone_gw->crc_lock);
215462306a36Sopenharmony_ci	backbone_crc = claim->backbone_gw->crc;
215562306a36Sopenharmony_ci	spin_unlock_bh(&claim->backbone_gw->crc_lock);
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	if (is_own)
215862306a36Sopenharmony_ci		if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
215962306a36Sopenharmony_ci			genlmsg_cancel(msg, hdr);
216062306a36Sopenharmony_ci			goto out;
216162306a36Sopenharmony_ci		}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	if (nla_put(msg, BATADV_ATTR_BLA_ADDRESS, ETH_ALEN, claim->addr) ||
216462306a36Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_BLA_VID, claim->vid) ||
216562306a36Sopenharmony_ci	    nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,
216662306a36Sopenharmony_ci		    claim->backbone_gw->orig) ||
216762306a36Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
216862306a36Sopenharmony_ci			backbone_crc)) {
216962306a36Sopenharmony_ci		genlmsg_cancel(msg, hdr);
217062306a36Sopenharmony_ci		goto out;
217162306a36Sopenharmony_ci	}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	genlmsg_end(msg, hdr);
217462306a36Sopenharmony_ci	ret = 0;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ciout:
217762306a36Sopenharmony_ci	return ret;
217862306a36Sopenharmony_ci}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci/**
218162306a36Sopenharmony_ci * batadv_bla_claim_dump_bucket() - dump one bucket of the claim table
218262306a36Sopenharmony_ci * to a netlink socket
218362306a36Sopenharmony_ci * @msg: buffer for the message
218462306a36Sopenharmony_ci * @portid: netlink port
218562306a36Sopenharmony_ci * @cb: Control block containing additional options
218662306a36Sopenharmony_ci * @primary_if: primary interface
218762306a36Sopenharmony_ci * @hash: hash to dump
218862306a36Sopenharmony_ci * @bucket: bucket index to dump
218962306a36Sopenharmony_ci * @idx_skip: How many entries to skip
219062306a36Sopenharmony_ci *
219162306a36Sopenharmony_ci * Return: always 0.
219262306a36Sopenharmony_ci */
219362306a36Sopenharmony_cistatic int
219462306a36Sopenharmony_cibatadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid,
219562306a36Sopenharmony_ci			     struct netlink_callback *cb,
219662306a36Sopenharmony_ci			     struct batadv_hard_iface *primary_if,
219762306a36Sopenharmony_ci			     struct batadv_hashtable *hash, unsigned int bucket,
219862306a36Sopenharmony_ci			     int *idx_skip)
219962306a36Sopenharmony_ci{
220062306a36Sopenharmony_ci	struct batadv_bla_claim *claim;
220162306a36Sopenharmony_ci	int idx = 0;
220262306a36Sopenharmony_ci	int ret = 0;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	spin_lock_bh(&hash->list_locks[bucket]);
220562306a36Sopenharmony_ci	cb->seq = atomic_read(&hash->generation) << 1 | 1;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	hlist_for_each_entry(claim, &hash->table[bucket], hash_entry) {
220862306a36Sopenharmony_ci		if (idx++ < *idx_skip)
220962306a36Sopenharmony_ci			continue;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci		ret = batadv_bla_claim_dump_entry(msg, portid, cb,
221262306a36Sopenharmony_ci						  primary_if, claim);
221362306a36Sopenharmony_ci		if (ret) {
221462306a36Sopenharmony_ci			*idx_skip = idx - 1;
221562306a36Sopenharmony_ci			goto unlock;
221662306a36Sopenharmony_ci		}
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	*idx_skip = 0;
222062306a36Sopenharmony_ciunlock:
222162306a36Sopenharmony_ci	spin_unlock_bh(&hash->list_locks[bucket]);
222262306a36Sopenharmony_ci	return ret;
222362306a36Sopenharmony_ci}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci/**
222662306a36Sopenharmony_ci * batadv_bla_claim_dump() - dump claim table to a netlink socket
222762306a36Sopenharmony_ci * @msg: buffer for the message
222862306a36Sopenharmony_ci * @cb: callback structure containing arguments
222962306a36Sopenharmony_ci *
223062306a36Sopenharmony_ci * Return: message length.
223162306a36Sopenharmony_ci */
223262306a36Sopenharmony_ciint batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)
223362306a36Sopenharmony_ci{
223462306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
223562306a36Sopenharmony_ci	int portid = NETLINK_CB(cb->skb).portid;
223662306a36Sopenharmony_ci	struct net *net = sock_net(cb->skb->sk);
223762306a36Sopenharmony_ci	struct net_device *soft_iface;
223862306a36Sopenharmony_ci	struct batadv_hashtable *hash;
223962306a36Sopenharmony_ci	struct batadv_priv *bat_priv;
224062306a36Sopenharmony_ci	int bucket = cb->args[0];
224162306a36Sopenharmony_ci	int idx = cb->args[1];
224262306a36Sopenharmony_ci	int ifindex;
224362306a36Sopenharmony_ci	int ret = 0;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	ifindex = batadv_netlink_get_ifindex(cb->nlh,
224662306a36Sopenharmony_ci					     BATADV_ATTR_MESH_IFINDEX);
224762306a36Sopenharmony_ci	if (!ifindex)
224862306a36Sopenharmony_ci		return -EINVAL;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	soft_iface = dev_get_by_index(net, ifindex);
225162306a36Sopenharmony_ci	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
225262306a36Sopenharmony_ci		ret = -ENODEV;
225362306a36Sopenharmony_ci		goto out;
225462306a36Sopenharmony_ci	}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	bat_priv = netdev_priv(soft_iface);
225762306a36Sopenharmony_ci	hash = bat_priv->bla.claim_hash;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
226062306a36Sopenharmony_ci	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
226162306a36Sopenharmony_ci		ret = -ENOENT;
226262306a36Sopenharmony_ci		goto out;
226362306a36Sopenharmony_ci	}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	while (bucket < hash->size) {
226662306a36Sopenharmony_ci		if (batadv_bla_claim_dump_bucket(msg, portid, cb, primary_if,
226762306a36Sopenharmony_ci						 hash, bucket, &idx))
226862306a36Sopenharmony_ci			break;
226962306a36Sopenharmony_ci		bucket++;
227062306a36Sopenharmony_ci	}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	cb->args[0] = bucket;
227362306a36Sopenharmony_ci	cb->args[1] = idx;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	ret = msg->len;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ciout:
227862306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	dev_put(soft_iface);
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	return ret;
228362306a36Sopenharmony_ci}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci/**
228662306a36Sopenharmony_ci * batadv_bla_backbone_dump_entry() - dump one entry of the backbone table to a
228762306a36Sopenharmony_ci *  netlink socket
228862306a36Sopenharmony_ci * @msg: buffer for the message
228962306a36Sopenharmony_ci * @portid: netlink port
229062306a36Sopenharmony_ci * @cb: Control block containing additional options
229162306a36Sopenharmony_ci * @primary_if: primary interface
229262306a36Sopenharmony_ci * @backbone_gw: entry to dump
229362306a36Sopenharmony_ci *
229462306a36Sopenharmony_ci * Return: 0 or error code.
229562306a36Sopenharmony_ci */
229662306a36Sopenharmony_cistatic int
229762306a36Sopenharmony_cibatadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid,
229862306a36Sopenharmony_ci			       struct netlink_callback *cb,
229962306a36Sopenharmony_ci			       struct batadv_hard_iface *primary_if,
230062306a36Sopenharmony_ci			       struct batadv_bla_backbone_gw *backbone_gw)
230162306a36Sopenharmony_ci{
230262306a36Sopenharmony_ci	const u8 *primary_addr = primary_if->net_dev->dev_addr;
230362306a36Sopenharmony_ci	u16 backbone_crc;
230462306a36Sopenharmony_ci	bool is_own;
230562306a36Sopenharmony_ci	int msecs;
230662306a36Sopenharmony_ci	void *hdr;
230762306a36Sopenharmony_ci	int ret = -EINVAL;
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
231062306a36Sopenharmony_ci			  &batadv_netlink_family, NLM_F_MULTI,
231162306a36Sopenharmony_ci			  BATADV_CMD_GET_BLA_BACKBONE);
231262306a36Sopenharmony_ci	if (!hdr) {
231362306a36Sopenharmony_ci		ret = -ENOBUFS;
231462306a36Sopenharmony_ci		goto out;
231562306a36Sopenharmony_ci	}
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	genl_dump_check_consistent(cb, hdr);
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	is_own = batadv_compare_eth(backbone_gw->orig, primary_addr);
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	spin_lock_bh(&backbone_gw->crc_lock);
232262306a36Sopenharmony_ci	backbone_crc = backbone_gw->crc;
232362306a36Sopenharmony_ci	spin_unlock_bh(&backbone_gw->crc_lock);
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	msecs = jiffies_to_msecs(jiffies - backbone_gw->lasttime);
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	if (is_own)
232862306a36Sopenharmony_ci		if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
232962306a36Sopenharmony_ci			genlmsg_cancel(msg, hdr);
233062306a36Sopenharmony_ci			goto out;
233162306a36Sopenharmony_ci		}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	if (nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,
233462306a36Sopenharmony_ci		    backbone_gw->orig) ||
233562306a36Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_BLA_VID, backbone_gw->vid) ||
233662306a36Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
233762306a36Sopenharmony_ci			backbone_crc) ||
233862306a36Sopenharmony_ci	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {
233962306a36Sopenharmony_ci		genlmsg_cancel(msg, hdr);
234062306a36Sopenharmony_ci		goto out;
234162306a36Sopenharmony_ci	}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	genlmsg_end(msg, hdr);
234462306a36Sopenharmony_ci	ret = 0;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ciout:
234762306a36Sopenharmony_ci	return ret;
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci/**
235162306a36Sopenharmony_ci * batadv_bla_backbone_dump_bucket() - dump one bucket of the backbone table to
235262306a36Sopenharmony_ci *  a netlink socket
235362306a36Sopenharmony_ci * @msg: buffer for the message
235462306a36Sopenharmony_ci * @portid: netlink port
235562306a36Sopenharmony_ci * @cb: Control block containing additional options
235662306a36Sopenharmony_ci * @primary_if: primary interface
235762306a36Sopenharmony_ci * @hash: hash to dump
235862306a36Sopenharmony_ci * @bucket: bucket index to dump
235962306a36Sopenharmony_ci * @idx_skip: How many entries to skip
236062306a36Sopenharmony_ci *
236162306a36Sopenharmony_ci * Return: always 0.
236262306a36Sopenharmony_ci */
236362306a36Sopenharmony_cistatic int
236462306a36Sopenharmony_cibatadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid,
236562306a36Sopenharmony_ci				struct netlink_callback *cb,
236662306a36Sopenharmony_ci				struct batadv_hard_iface *primary_if,
236762306a36Sopenharmony_ci				struct batadv_hashtable *hash,
236862306a36Sopenharmony_ci				unsigned int bucket, int *idx_skip)
236962306a36Sopenharmony_ci{
237062306a36Sopenharmony_ci	struct batadv_bla_backbone_gw *backbone_gw;
237162306a36Sopenharmony_ci	int idx = 0;
237262306a36Sopenharmony_ci	int ret = 0;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	spin_lock_bh(&hash->list_locks[bucket]);
237562306a36Sopenharmony_ci	cb->seq = atomic_read(&hash->generation) << 1 | 1;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	hlist_for_each_entry(backbone_gw, &hash->table[bucket], hash_entry) {
237862306a36Sopenharmony_ci		if (idx++ < *idx_skip)
237962306a36Sopenharmony_ci			continue;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci		ret = batadv_bla_backbone_dump_entry(msg, portid, cb,
238262306a36Sopenharmony_ci						     primary_if, backbone_gw);
238362306a36Sopenharmony_ci		if (ret) {
238462306a36Sopenharmony_ci			*idx_skip = idx - 1;
238562306a36Sopenharmony_ci			goto unlock;
238662306a36Sopenharmony_ci		}
238762306a36Sopenharmony_ci	}
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	*idx_skip = 0;
239062306a36Sopenharmony_ciunlock:
239162306a36Sopenharmony_ci	spin_unlock_bh(&hash->list_locks[bucket]);
239262306a36Sopenharmony_ci	return ret;
239362306a36Sopenharmony_ci}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci/**
239662306a36Sopenharmony_ci * batadv_bla_backbone_dump() - dump backbone table to a netlink socket
239762306a36Sopenharmony_ci * @msg: buffer for the message
239862306a36Sopenharmony_ci * @cb: callback structure containing arguments
239962306a36Sopenharmony_ci *
240062306a36Sopenharmony_ci * Return: message length.
240162306a36Sopenharmony_ci */
240262306a36Sopenharmony_ciint batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)
240362306a36Sopenharmony_ci{
240462306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
240562306a36Sopenharmony_ci	int portid = NETLINK_CB(cb->skb).portid;
240662306a36Sopenharmony_ci	struct net *net = sock_net(cb->skb->sk);
240762306a36Sopenharmony_ci	struct net_device *soft_iface;
240862306a36Sopenharmony_ci	struct batadv_hashtable *hash;
240962306a36Sopenharmony_ci	struct batadv_priv *bat_priv;
241062306a36Sopenharmony_ci	int bucket = cb->args[0];
241162306a36Sopenharmony_ci	int idx = cb->args[1];
241262306a36Sopenharmony_ci	int ifindex;
241362306a36Sopenharmony_ci	int ret = 0;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	ifindex = batadv_netlink_get_ifindex(cb->nlh,
241662306a36Sopenharmony_ci					     BATADV_ATTR_MESH_IFINDEX);
241762306a36Sopenharmony_ci	if (!ifindex)
241862306a36Sopenharmony_ci		return -EINVAL;
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci	soft_iface = dev_get_by_index(net, ifindex);
242162306a36Sopenharmony_ci	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
242262306a36Sopenharmony_ci		ret = -ENODEV;
242362306a36Sopenharmony_ci		goto out;
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	bat_priv = netdev_priv(soft_iface);
242762306a36Sopenharmony_ci	hash = bat_priv->bla.backbone_hash;
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
243062306a36Sopenharmony_ci	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
243162306a36Sopenharmony_ci		ret = -ENOENT;
243262306a36Sopenharmony_ci		goto out;
243362306a36Sopenharmony_ci	}
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	while (bucket < hash->size) {
243662306a36Sopenharmony_ci		if (batadv_bla_backbone_dump_bucket(msg, portid, cb, primary_if,
243762306a36Sopenharmony_ci						    hash, bucket, &idx))
243862306a36Sopenharmony_ci			break;
243962306a36Sopenharmony_ci		bucket++;
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	cb->args[0] = bucket;
244362306a36Sopenharmony_ci	cb->args[1] = idx;
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	ret = msg->len;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ciout:
244862306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	dev_put(soft_iface);
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	return ret;
245362306a36Sopenharmony_ci}
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DAT
245662306a36Sopenharmony_ci/**
245762306a36Sopenharmony_ci * batadv_bla_check_claim() - check if address is claimed
245862306a36Sopenharmony_ci *
245962306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
246062306a36Sopenharmony_ci * @addr: mac address of which the claim status is checked
246162306a36Sopenharmony_ci * @vid: the VLAN ID
246262306a36Sopenharmony_ci *
246362306a36Sopenharmony_ci * addr is checked if this address is claimed by the local device itself.
246462306a36Sopenharmony_ci *
246562306a36Sopenharmony_ci * Return: true if bla is disabled or the mac is claimed by the device,
246662306a36Sopenharmony_ci * false if the device addr is already claimed by another gateway
246762306a36Sopenharmony_ci */
246862306a36Sopenharmony_cibool batadv_bla_check_claim(struct batadv_priv *bat_priv,
246962306a36Sopenharmony_ci			    u8 *addr, unsigned short vid)
247062306a36Sopenharmony_ci{
247162306a36Sopenharmony_ci	struct batadv_bla_claim search_claim;
247262306a36Sopenharmony_ci	struct batadv_bla_claim *claim = NULL;
247362306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
247462306a36Sopenharmony_ci	bool ret = true;
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
247762306a36Sopenharmony_ci		return ret;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
248062306a36Sopenharmony_ci	if (!primary_if)
248162306a36Sopenharmony_ci		return ret;
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	/* First look if the mac address is claimed */
248462306a36Sopenharmony_ci	ether_addr_copy(search_claim.addr, addr);
248562306a36Sopenharmony_ci	search_claim.vid = vid;
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	claim = batadv_claim_hash_find(bat_priv, &search_claim);
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	/* If there is a claim and we are not owner of the claim,
249062306a36Sopenharmony_ci	 * return false.
249162306a36Sopenharmony_ci	 */
249262306a36Sopenharmony_ci	if (claim) {
249362306a36Sopenharmony_ci		if (!batadv_compare_eth(claim->backbone_gw->orig,
249462306a36Sopenharmony_ci					primary_if->net_dev->dev_addr))
249562306a36Sopenharmony_ci			ret = false;
249662306a36Sopenharmony_ci		batadv_claim_put(claim);
249762306a36Sopenharmony_ci	}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
250062306a36Sopenharmony_ci	return ret;
250162306a36Sopenharmony_ci}
250262306a36Sopenharmony_ci#endif
2503