Path: blob/master/net/batman-adv/bridge_loop_avoidance.c
29266 views
// SPDX-License-Identifier: GPL-2.01/* Copyright (C) B.A.T.M.A.N. contributors:2*3* Simon Wunderlich4*/56#include "bridge_loop_avoidance.h"7#include "main.h"89#include <linux/atomic.h>10#include <linux/byteorder/generic.h>11#include <linux/compiler.h>12#include <linux/container_of.h>13#include <linux/crc16.h>14#include <linux/crc32.h>15#include <linux/err.h>16#include <linux/errno.h>17#include <linux/etherdevice.h>18#include <linux/gfp.h>19#include <linux/if_arp.h>20#include <linux/if_ether.h>21#include <linux/if_vlan.h>22#include <linux/jhash.h>23#include <linux/jiffies.h>24#include <linux/kref.h>25#include <linux/list.h>26#include <linux/lockdep.h>27#include <linux/netdevice.h>28#include <linux/netlink.h>29#include <linux/rculist.h>30#include <linux/rcupdate.h>31#include <linux/skbuff.h>32#include <linux/slab.h>33#include <linux/spinlock.h>34#include <linux/sprintf.h>35#include <linux/stddef.h>36#include <linux/string.h>37#include <linux/string_choices.h>38#include <linux/workqueue.h>39#include <net/arp.h>40#include <net/genetlink.h>41#include <net/netlink.h>42#include <uapi/linux/batadv_packet.h>43#include <uapi/linux/batman_adv.h>4445#include "hard-interface.h"46#include "hash.h"47#include "log.h"48#include "netlink.h"49#include "originator.h"50#include "translation-table.h"5152static const u8 batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05};5354static void batadv_bla_periodic_work(struct work_struct *work);55static void56batadv_bla_send_announce(struct batadv_priv *bat_priv,57struct batadv_bla_backbone_gw *backbone_gw);5859/**60* batadv_choose_claim() - choose the right bucket for a claim.61* @data: data to hash62* @size: size of the hash table63*64* Return: the hash index of the claim65*/66static inline u32 batadv_choose_claim(const void *data, u32 size)67{68const struct batadv_bla_claim *claim = data;69u32 hash = 0;7071hash = jhash(&claim->addr, sizeof(claim->addr), hash);72hash = jhash(&claim->vid, sizeof(claim->vid), hash);7374return hash % size;75}7677/**78* batadv_choose_backbone_gw() - choose the right bucket for a backbone gateway.79* @data: data to hash80* @size: size of the hash table81*82* Return: the hash index of the backbone gateway83*/84static inline u32 batadv_choose_backbone_gw(const void *data, u32 size)85{86const struct batadv_bla_backbone_gw *gw;87u32 hash = 0;8889gw = data;90hash = jhash(&gw->orig, sizeof(gw->orig), hash);91hash = jhash(&gw->vid, sizeof(gw->vid), hash);9293return hash % size;94}9596/**97* batadv_compare_backbone_gw() - compare address and vid of two backbone gws98* @node: list node of the first entry to compare99* @data2: pointer to the second backbone gateway100*101* Return: true if the backbones have the same data, false otherwise102*/103static bool batadv_compare_backbone_gw(const struct hlist_node *node,104const void *data2)105{106const void *data1 = container_of(node, struct batadv_bla_backbone_gw,107hash_entry);108const struct batadv_bla_backbone_gw *gw1 = data1;109const struct batadv_bla_backbone_gw *gw2 = data2;110111if (!batadv_compare_eth(gw1->orig, gw2->orig))112return false;113114if (gw1->vid != gw2->vid)115return false;116117return true;118}119120/**121* batadv_compare_claim() - compare address and vid of two claims122* @node: list node of the first entry to compare123* @data2: pointer to the second claims124*125* Return: true if the claim have the same data, 0 otherwise126*/127static bool batadv_compare_claim(const struct hlist_node *node,128const void *data2)129{130const void *data1 = container_of(node, struct batadv_bla_claim,131hash_entry);132const struct batadv_bla_claim *cl1 = data1;133const struct batadv_bla_claim *cl2 = data2;134135if (!batadv_compare_eth(cl1->addr, cl2->addr))136return false;137138if (cl1->vid != cl2->vid)139return false;140141return true;142}143144/**145* batadv_backbone_gw_release() - release backbone gw from lists and queue for146* free after rcu grace period147* @ref: kref pointer of the backbone gw148*/149static void batadv_backbone_gw_release(struct kref *ref)150{151struct batadv_bla_backbone_gw *backbone_gw;152153backbone_gw = container_of(ref, struct batadv_bla_backbone_gw,154refcount);155156kfree_rcu(backbone_gw, rcu);157}158159/**160* batadv_backbone_gw_put() - decrement the backbone gw refcounter and possibly161* release it162* @backbone_gw: backbone gateway to be free'd163*/164static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw)165{166if (!backbone_gw)167return;168169kref_put(&backbone_gw->refcount, batadv_backbone_gw_release);170}171172/**173* batadv_claim_release() - release claim from lists and queue for free after174* rcu grace period175* @ref: kref pointer of the claim176*/177static void batadv_claim_release(struct kref *ref)178{179struct batadv_bla_claim *claim;180struct batadv_bla_backbone_gw *old_backbone_gw;181182claim = container_of(ref, struct batadv_bla_claim, refcount);183184spin_lock_bh(&claim->backbone_lock);185old_backbone_gw = claim->backbone_gw;186claim->backbone_gw = NULL;187spin_unlock_bh(&claim->backbone_lock);188189spin_lock_bh(&old_backbone_gw->crc_lock);190old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);191spin_unlock_bh(&old_backbone_gw->crc_lock);192193batadv_backbone_gw_put(old_backbone_gw);194195kfree_rcu(claim, rcu);196}197198/**199* batadv_claim_put() - decrement the claim refcounter and possibly release it200* @claim: claim to be free'd201*/202static void batadv_claim_put(struct batadv_bla_claim *claim)203{204if (!claim)205return;206207kref_put(&claim->refcount, batadv_claim_release);208}209210/**211* batadv_claim_hash_find() - looks for a claim in the claim hash212* @bat_priv: the bat priv with all the mesh interface information213* @data: search data (may be local/static data)214*215* Return: claim if found or NULL otherwise.216*/217static struct batadv_bla_claim *218batadv_claim_hash_find(struct batadv_priv *bat_priv,219struct batadv_bla_claim *data)220{221struct batadv_hashtable *hash = bat_priv->bla.claim_hash;222struct hlist_head *head;223struct batadv_bla_claim *claim;224struct batadv_bla_claim *claim_tmp = NULL;225int index;226227if (!hash)228return NULL;229230index = batadv_choose_claim(data, hash->size);231head = &hash->table[index];232233rcu_read_lock();234hlist_for_each_entry_rcu(claim, head, hash_entry) {235if (!batadv_compare_claim(&claim->hash_entry, data))236continue;237238if (!kref_get_unless_zero(&claim->refcount))239continue;240241claim_tmp = claim;242break;243}244rcu_read_unlock();245246return claim_tmp;247}248249/**250* batadv_backbone_hash_find() - looks for a backbone gateway in the hash251* @bat_priv: the bat priv with all the mesh interface information252* @addr: the address of the originator253* @vid: the VLAN ID254*255* Return: backbone gateway if found or NULL otherwise256*/257static struct batadv_bla_backbone_gw *258batadv_backbone_hash_find(struct batadv_priv *bat_priv, const u8 *addr,259unsigned short vid)260{261struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;262struct hlist_head *head;263struct batadv_bla_backbone_gw search_entry, *backbone_gw;264struct batadv_bla_backbone_gw *backbone_gw_tmp = NULL;265int index;266267if (!hash)268return NULL;269270ether_addr_copy(search_entry.orig, addr);271search_entry.vid = vid;272273index = batadv_choose_backbone_gw(&search_entry, hash->size);274head = &hash->table[index];275276rcu_read_lock();277hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {278if (!batadv_compare_backbone_gw(&backbone_gw->hash_entry,279&search_entry))280continue;281282if (!kref_get_unless_zero(&backbone_gw->refcount))283continue;284285backbone_gw_tmp = backbone_gw;286break;287}288rcu_read_unlock();289290return backbone_gw_tmp;291}292293/**294* batadv_bla_del_backbone_claims() - delete all claims for a backbone295* @backbone_gw: backbone gateway where the claims should be removed296*/297static void298batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw)299{300struct batadv_hashtable *hash;301struct hlist_node *node_tmp;302struct hlist_head *head;303struct batadv_bla_claim *claim;304int i;305spinlock_t *list_lock; /* protects write access to the hash lists */306307hash = backbone_gw->bat_priv->bla.claim_hash;308if (!hash)309return;310311for (i = 0; i < hash->size; i++) {312head = &hash->table[i];313list_lock = &hash->list_locks[i];314315spin_lock_bh(list_lock);316hlist_for_each_entry_safe(claim, node_tmp,317head, hash_entry) {318if (claim->backbone_gw != backbone_gw)319continue;320321batadv_claim_put(claim);322hlist_del_rcu(&claim->hash_entry);323}324spin_unlock_bh(list_lock);325}326327/* all claims gone, initialize CRC */328spin_lock_bh(&backbone_gw->crc_lock);329backbone_gw->crc = BATADV_BLA_CRC_INIT;330spin_unlock_bh(&backbone_gw->crc_lock);331}332333/**334* batadv_bla_send_claim() - sends a claim frame according to the provided info335* @bat_priv: the bat priv with all the mesh interface information336* @mac: the mac address to be announced within the claim337* @vid: the VLAN ID338* @claimtype: the type of the claim (CLAIM, UNCLAIM, ANNOUNCE, ...)339*/340static void batadv_bla_send_claim(struct batadv_priv *bat_priv, const u8 *mac,341unsigned short vid, int claimtype)342{343struct sk_buff *skb;344struct ethhdr *ethhdr;345struct batadv_hard_iface *primary_if;346struct net_device *mesh_iface;347u8 *hw_src;348struct batadv_bla_claim_dst local_claim_dest;349__be32 zeroip = 0;350351primary_if = batadv_primary_if_get_selected(bat_priv);352if (!primary_if)353return;354355memcpy(&local_claim_dest, &bat_priv->bla.claim_dest,356sizeof(local_claim_dest));357local_claim_dest.type = claimtype;358359mesh_iface = primary_if->mesh_iface;360361skb = arp_create(ARPOP_REPLY, ETH_P_ARP,362/* IP DST: 0.0.0.0 */363zeroip,364primary_if->mesh_iface,365/* IP SRC: 0.0.0.0 */366zeroip,367/* Ethernet DST: Broadcast */368NULL,369/* Ethernet SRC/HW SRC: originator mac */370primary_if->net_dev->dev_addr,371/* HW DST: FF:43:05:XX:YY:YY372* with XX = claim type373* and YY:YY = group id374*/375(u8 *)&local_claim_dest);376377if (!skb)378goto out;379380ethhdr = (struct ethhdr *)skb->data;381hw_src = (u8 *)ethhdr + ETH_HLEN + sizeof(struct arphdr);382383/* now we pretend that the client would have sent this ... */384switch (claimtype) {385case BATADV_CLAIM_TYPE_CLAIM:386/* normal claim frame387* set Ethernet SRC to the clients mac388*/389ether_addr_copy(ethhdr->h_source, mac);390batadv_dbg(BATADV_DBG_BLA, bat_priv,391"%s(): CLAIM %pM on vid %d\n", __func__, mac,392batadv_print_vid(vid));393break;394case BATADV_CLAIM_TYPE_UNCLAIM:395/* unclaim frame396* set HW SRC to the clients mac397*/398ether_addr_copy(hw_src, mac);399batadv_dbg(BATADV_DBG_BLA, bat_priv,400"%s(): UNCLAIM %pM on vid %d\n", __func__, mac,401batadv_print_vid(vid));402break;403case BATADV_CLAIM_TYPE_ANNOUNCE:404/* announcement frame405* set HW SRC to the special mac containing the crc406*/407ether_addr_copy(hw_src, mac);408batadv_dbg(BATADV_DBG_BLA, bat_priv,409"%s(): ANNOUNCE of %pM on vid %d\n", __func__,410ethhdr->h_source, batadv_print_vid(vid));411break;412case BATADV_CLAIM_TYPE_REQUEST:413/* request frame414* set HW SRC and header destination to the receiving backbone415* gws mac416*/417ether_addr_copy(hw_src, mac);418ether_addr_copy(ethhdr->h_dest, mac);419batadv_dbg(BATADV_DBG_BLA, bat_priv,420"%s(): REQUEST of %pM to %pM on vid %d\n", __func__,421ethhdr->h_source, ethhdr->h_dest,422batadv_print_vid(vid));423break;424case BATADV_CLAIM_TYPE_LOOPDETECT:425ether_addr_copy(ethhdr->h_source, mac);426batadv_dbg(BATADV_DBG_BLA, bat_priv,427"%s(): LOOPDETECT of %pM to %pM on vid %d\n",428__func__, ethhdr->h_source, ethhdr->h_dest,429batadv_print_vid(vid));430431break;432}433434if (vid & BATADV_VLAN_HAS_TAG) {435skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),436vid & VLAN_VID_MASK);437if (!skb)438goto out;439}440441skb_reset_mac_header(skb);442skb->protocol = eth_type_trans(skb, mesh_iface);443batadv_inc_counter(bat_priv, BATADV_CNT_RX);444batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,445skb->len + ETH_HLEN);446447netif_rx(skb);448out:449batadv_hardif_put(primary_if);450}451452/**453* batadv_bla_loopdetect_report() - worker for reporting the loop454* @work: work queue item455*456* Throws an uevent, as the loopdetect check function can't do that itself457* since the kernel may sleep while throwing uevents.458*/459static void batadv_bla_loopdetect_report(struct work_struct *work)460{461struct batadv_bla_backbone_gw *backbone_gw;462struct batadv_priv *bat_priv;463char vid_str[6] = { '\0' };464465backbone_gw = container_of(work, struct batadv_bla_backbone_gw,466report_work);467bat_priv = backbone_gw->bat_priv;468469batadv_info(bat_priv->mesh_iface,470"Possible loop on VLAN %d detected which can't be handled by BLA - please check your network setup!\n",471batadv_print_vid(backbone_gw->vid));472snprintf(vid_str, sizeof(vid_str), "%d",473batadv_print_vid(backbone_gw->vid));474vid_str[sizeof(vid_str) - 1] = 0;475476batadv_throw_uevent(bat_priv, BATADV_UEV_BLA, BATADV_UEV_LOOPDETECT,477vid_str);478479batadv_backbone_gw_put(backbone_gw);480}481482/**483* batadv_bla_get_backbone_gw() - finds or creates a backbone gateway484* @bat_priv: the bat priv with all the mesh interface information485* @orig: the mac address of the originator486* @vid: the VLAN ID487* @own_backbone: set if the requested backbone is local488*489* Return: the (possibly created) backbone gateway or NULL on error490*/491static struct batadv_bla_backbone_gw *492batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, const u8 *orig,493unsigned short vid, bool own_backbone)494{495struct batadv_bla_backbone_gw *entry;496struct batadv_orig_node *orig_node;497int hash_added;498499entry = batadv_backbone_hash_find(bat_priv, orig, vid);500501if (entry)502return entry;503504batadv_dbg(BATADV_DBG_BLA, bat_priv,505"%s(): not found (%pM, %d), creating new entry\n", __func__,506orig, batadv_print_vid(vid));507508entry = kzalloc(sizeof(*entry), GFP_ATOMIC);509if (!entry)510return NULL;511512entry->vid = vid;513entry->lasttime = jiffies;514entry->crc = BATADV_BLA_CRC_INIT;515entry->bat_priv = bat_priv;516spin_lock_init(&entry->crc_lock);517atomic_set(&entry->request_sent, 0);518atomic_set(&entry->wait_periods, 0);519ether_addr_copy(entry->orig, orig);520INIT_WORK(&entry->report_work, batadv_bla_loopdetect_report);521kref_init(&entry->refcount);522523kref_get(&entry->refcount);524hash_added = batadv_hash_add(bat_priv->bla.backbone_hash,525batadv_compare_backbone_gw,526batadv_choose_backbone_gw, entry,527&entry->hash_entry);528529if (unlikely(hash_added != 0)) {530/* hash failed, free the structure */531kfree(entry);532return NULL;533}534535/* this is a gateway now, remove any TT entry on this VLAN */536orig_node = batadv_orig_hash_find(bat_priv, orig);537if (orig_node) {538batadv_tt_global_del_orig(bat_priv, orig_node, vid,539"became a backbone gateway");540batadv_orig_node_put(orig_node);541}542543if (own_backbone) {544batadv_bla_send_announce(bat_priv, entry);545546/* this will be decreased in the worker thread */547atomic_inc(&entry->request_sent);548atomic_set(&entry->wait_periods, BATADV_BLA_WAIT_PERIODS);549atomic_inc(&bat_priv->bla.num_requests);550}551552return entry;553}554555/**556* batadv_bla_update_own_backbone_gw() - updates the own backbone gw for a VLAN557* @bat_priv: the bat priv with all the mesh interface information558* @primary_if: the selected primary interface559* @vid: VLAN identifier560*561* update or add the own backbone gw to make sure we announce562* where we receive other backbone gws563*/564static void565batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv,566struct batadv_hard_iface *primary_if,567unsigned short vid)568{569struct batadv_bla_backbone_gw *backbone_gw;570571backbone_gw = batadv_bla_get_backbone_gw(bat_priv,572primary_if->net_dev->dev_addr,573vid, true);574if (unlikely(!backbone_gw))575return;576577backbone_gw->lasttime = jiffies;578batadv_backbone_gw_put(backbone_gw);579}580581/**582* batadv_bla_answer_request() - answer a bla request by sending own claims583* @bat_priv: the bat priv with all the mesh interface information584* @primary_if: interface where the request came on585* @vid: the vid where the request came on586*587* Repeat all of our own claims, and finally send an ANNOUNCE frame588* to allow the requester another check if the CRC is correct now.589*/590static void batadv_bla_answer_request(struct batadv_priv *bat_priv,591struct batadv_hard_iface *primary_if,592unsigned short vid)593{594struct hlist_head *head;595struct batadv_hashtable *hash;596struct batadv_bla_claim *claim;597struct batadv_bla_backbone_gw *backbone_gw;598int i;599600batadv_dbg(BATADV_DBG_BLA, bat_priv,601"%s(): received a claim request, send all of our own claims again\n",602__func__);603604backbone_gw = batadv_backbone_hash_find(bat_priv,605primary_if->net_dev->dev_addr,606vid);607if (!backbone_gw)608return;609610hash = bat_priv->bla.claim_hash;611for (i = 0; i < hash->size; i++) {612head = &hash->table[i];613614rcu_read_lock();615hlist_for_each_entry_rcu(claim, head, hash_entry) {616/* only own claims are interesting */617if (claim->backbone_gw != backbone_gw)618continue;619620batadv_bla_send_claim(bat_priv, claim->addr, claim->vid,621BATADV_CLAIM_TYPE_CLAIM);622}623rcu_read_unlock();624}625626/* finally, send an announcement frame */627batadv_bla_send_announce(bat_priv, backbone_gw);628batadv_backbone_gw_put(backbone_gw);629}630631/**632* batadv_bla_send_request() - send a request to repeat claims633* @backbone_gw: the backbone gateway from whom we are out of sync634*635* When the crc is wrong, ask the backbone gateway for a full table update.636* After the request, it will repeat all of his own claims and finally637* send an announcement claim with which we can check again.638*/639static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)640{641/* first, remove all old entries */642batadv_bla_del_backbone_claims(backbone_gw);643644batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,645"Sending REQUEST to %pM\n", backbone_gw->orig);646647/* send request */648batadv_bla_send_claim(backbone_gw->bat_priv, backbone_gw->orig,649backbone_gw->vid, BATADV_CLAIM_TYPE_REQUEST);650651/* no local broadcasts should be sent or received, for now. */652if (!atomic_read(&backbone_gw->request_sent)) {653atomic_inc(&backbone_gw->bat_priv->bla.num_requests);654atomic_set(&backbone_gw->request_sent, 1);655}656}657658/**659* batadv_bla_send_announce() - Send an announcement frame660* @bat_priv: the bat priv with all the mesh interface information661* @backbone_gw: our backbone gateway which should be announced662*/663static void batadv_bla_send_announce(struct batadv_priv *bat_priv,664struct batadv_bla_backbone_gw *backbone_gw)665{666u8 mac[ETH_ALEN];667__be16 crc;668669memcpy(mac, batadv_announce_mac, 4);670spin_lock_bh(&backbone_gw->crc_lock);671crc = htons(backbone_gw->crc);672spin_unlock_bh(&backbone_gw->crc_lock);673memcpy(&mac[4], &crc, 2);674675batadv_bla_send_claim(bat_priv, mac, backbone_gw->vid,676BATADV_CLAIM_TYPE_ANNOUNCE);677}678679/**680* batadv_bla_add_claim() - Adds a claim in the claim hash681* @bat_priv: the bat priv with all the mesh interface information682* @mac: the mac address of the claim683* @vid: the VLAN ID of the frame684* @backbone_gw: the backbone gateway which claims it685*/686static void batadv_bla_add_claim(struct batadv_priv *bat_priv,687const u8 *mac, const unsigned short vid,688struct batadv_bla_backbone_gw *backbone_gw)689{690struct batadv_bla_backbone_gw *old_backbone_gw;691struct batadv_bla_claim *claim;692struct batadv_bla_claim search_claim;693bool remove_crc = false;694int hash_added;695696ether_addr_copy(search_claim.addr, mac);697search_claim.vid = vid;698claim = batadv_claim_hash_find(bat_priv, &search_claim);699700/* create a new claim entry if it does not exist yet. */701if (!claim) {702claim = kzalloc(sizeof(*claim), GFP_ATOMIC);703if (!claim)704return;705706ether_addr_copy(claim->addr, mac);707spin_lock_init(&claim->backbone_lock);708claim->vid = vid;709claim->lasttime = jiffies;710kref_get(&backbone_gw->refcount);711claim->backbone_gw = backbone_gw;712kref_init(&claim->refcount);713714batadv_dbg(BATADV_DBG_BLA, bat_priv,715"%s(): adding new entry %pM, vid %d to hash ...\n",716__func__, mac, batadv_print_vid(vid));717718kref_get(&claim->refcount);719hash_added = batadv_hash_add(bat_priv->bla.claim_hash,720batadv_compare_claim,721batadv_choose_claim, claim,722&claim->hash_entry);723724if (unlikely(hash_added != 0)) {725/* only local changes happened. */726kfree(claim);727return;728}729} else {730claim->lasttime = jiffies;731if (claim->backbone_gw == backbone_gw)732/* no need to register a new backbone */733goto claim_free_ref;734735batadv_dbg(BATADV_DBG_BLA, bat_priv,736"%s(): changing ownership for %pM, vid %d to gw %pM\n",737__func__, mac, batadv_print_vid(vid),738backbone_gw->orig);739740remove_crc = true;741}742743/* replace backbone_gw atomically and adjust reference counters */744spin_lock_bh(&claim->backbone_lock);745old_backbone_gw = claim->backbone_gw;746kref_get(&backbone_gw->refcount);747claim->backbone_gw = backbone_gw;748spin_unlock_bh(&claim->backbone_lock);749750if (remove_crc) {751/* remove claim address from old backbone_gw */752spin_lock_bh(&old_backbone_gw->crc_lock);753old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);754spin_unlock_bh(&old_backbone_gw->crc_lock);755}756757batadv_backbone_gw_put(old_backbone_gw);758759/* add claim address to new backbone_gw */760spin_lock_bh(&backbone_gw->crc_lock);761backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);762spin_unlock_bh(&backbone_gw->crc_lock);763backbone_gw->lasttime = jiffies;764765claim_free_ref:766batadv_claim_put(claim);767}768769/**770* batadv_bla_claim_get_backbone_gw() - Get valid reference for backbone_gw of771* claim772* @claim: claim whose backbone_gw should be returned773*774* Return: valid reference to claim::backbone_gw775*/776static struct batadv_bla_backbone_gw *777batadv_bla_claim_get_backbone_gw(struct batadv_bla_claim *claim)778{779struct batadv_bla_backbone_gw *backbone_gw;780781spin_lock_bh(&claim->backbone_lock);782backbone_gw = claim->backbone_gw;783kref_get(&backbone_gw->refcount);784spin_unlock_bh(&claim->backbone_lock);785786return backbone_gw;787}788789/**790* batadv_bla_del_claim() - delete a claim from the claim hash791* @bat_priv: the bat priv with all the mesh interface information792* @mac: mac address of the claim to be removed793* @vid: VLAN id for the claim to be removed794*/795static void batadv_bla_del_claim(struct batadv_priv *bat_priv,796const u8 *mac, const unsigned short vid)797{798struct batadv_bla_claim search_claim, *claim;799struct batadv_bla_claim *claim_removed_entry;800struct hlist_node *claim_removed_node;801802ether_addr_copy(search_claim.addr, mac);803search_claim.vid = vid;804claim = batadv_claim_hash_find(bat_priv, &search_claim);805if (!claim)806return;807808batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): %pM, vid %d\n", __func__,809mac, batadv_print_vid(vid));810811claim_removed_node = batadv_hash_remove(bat_priv->bla.claim_hash,812batadv_compare_claim,813batadv_choose_claim, claim);814if (!claim_removed_node)815goto free_claim;816817/* reference from the hash is gone */818claim_removed_entry = hlist_entry(claim_removed_node,819struct batadv_bla_claim, hash_entry);820batadv_claim_put(claim_removed_entry);821822free_claim:823/* don't need the reference from hash_find() anymore */824batadv_claim_put(claim);825}826827/**828* batadv_handle_announce() - check for ANNOUNCE frame829* @bat_priv: the bat priv with all the mesh interface information830* @an_addr: announcement mac address (ARP Sender HW address)831* @backbone_addr: originator address of the sender (Ethernet source MAC)832* @vid: the VLAN ID of the frame833*834* Return: true if handled835*/836static bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,837u8 *backbone_addr, unsigned short vid)838{839struct batadv_bla_backbone_gw *backbone_gw;840u16 backbone_crc, crc;841842if (memcmp(an_addr, batadv_announce_mac, 4) != 0)843return false;844845backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid,846false);847848if (unlikely(!backbone_gw))849return true;850851/* handle as ANNOUNCE frame */852backbone_gw->lasttime = jiffies;853crc = ntohs(*((__force __be16 *)(&an_addr[4])));854855batadv_dbg(BATADV_DBG_BLA, bat_priv,856"%s(): ANNOUNCE vid %d (sent by %pM)... CRC = %#.4x\n",857__func__, batadv_print_vid(vid), backbone_gw->orig, crc);858859spin_lock_bh(&backbone_gw->crc_lock);860backbone_crc = backbone_gw->crc;861spin_unlock_bh(&backbone_gw->crc_lock);862863if (backbone_crc != crc) {864batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,865"%s(): CRC FAILED for %pM/%d (my = %#.4x, sent = %#.4x)\n",866__func__, backbone_gw->orig,867batadv_print_vid(backbone_gw->vid),868backbone_crc, crc);869870batadv_bla_send_request(backbone_gw);871} else {872/* if we have sent a request and the crc was OK,873* we can allow traffic again.874*/875if (atomic_read(&backbone_gw->request_sent)) {876atomic_dec(&backbone_gw->bat_priv->bla.num_requests);877atomic_set(&backbone_gw->request_sent, 0);878}879}880881batadv_backbone_gw_put(backbone_gw);882return true;883}884885/**886* batadv_handle_request() - check for REQUEST frame887* @bat_priv: the bat priv with all the mesh interface information888* @primary_if: the primary hard interface of this batman mesh interface889* @backbone_addr: backbone address to be requested (ARP sender HW MAC)890* @ethhdr: ethernet header of a packet891* @vid: the VLAN ID of the frame892*893* Return: true if handled894*/895static bool batadv_handle_request(struct batadv_priv *bat_priv,896struct batadv_hard_iface *primary_if,897u8 *backbone_addr, struct ethhdr *ethhdr,898unsigned short vid)899{900/* check for REQUEST frame */901if (!batadv_compare_eth(backbone_addr, ethhdr->h_dest))902return false;903904/* sanity check, this should not happen on a normal switch,905* we ignore it in this case.906*/907if (!batadv_compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr))908return true;909910batadv_dbg(BATADV_DBG_BLA, bat_priv,911"%s(): REQUEST vid %d (sent by %pM)...\n",912__func__, batadv_print_vid(vid), ethhdr->h_source);913914batadv_bla_answer_request(bat_priv, primary_if, vid);915return true;916}917918/**919* batadv_handle_unclaim() - check for UNCLAIM frame920* @bat_priv: the bat priv with all the mesh interface information921* @primary_if: the primary hard interface of this batman mesh interface922* @backbone_addr: originator address of the backbone (Ethernet source)923* @claim_addr: Client to be unclaimed (ARP sender HW MAC)924* @vid: the VLAN ID of the frame925*926* Return: true if handled927*/928static bool batadv_handle_unclaim(struct batadv_priv *bat_priv,929struct batadv_hard_iface *primary_if,930const u8 *backbone_addr, const u8 *claim_addr,931unsigned short vid)932{933struct batadv_bla_backbone_gw *backbone_gw;934935/* unclaim in any case if it is our own */936if (primary_if && batadv_compare_eth(backbone_addr,937primary_if->net_dev->dev_addr))938batadv_bla_send_claim(bat_priv, claim_addr, vid,939BATADV_CLAIM_TYPE_UNCLAIM);940941backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);942943if (!backbone_gw)944return true;945946/* this must be an UNCLAIM frame */947batadv_dbg(BATADV_DBG_BLA, bat_priv,948"%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n", __func__,949claim_addr, batadv_print_vid(vid), backbone_gw->orig);950951batadv_bla_del_claim(bat_priv, claim_addr, vid);952batadv_backbone_gw_put(backbone_gw);953return true;954}955956/**957* batadv_handle_claim() - check for CLAIM frame958* @bat_priv: the bat priv with all the mesh interface information959* @primary_if: the primary hard interface of this batman mesh interface960* @backbone_addr: originator address of the backbone (Ethernet Source)961* @claim_addr: client mac address to be claimed (ARP sender HW MAC)962* @vid: the VLAN ID of the frame963*964* Return: true if handled965*/966static bool batadv_handle_claim(struct batadv_priv *bat_priv,967struct batadv_hard_iface *primary_if,968const u8 *backbone_addr, const u8 *claim_addr,969unsigned short vid)970{971struct batadv_bla_backbone_gw *backbone_gw;972973/* register the gateway if not yet available, and add the claim. */974975backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid,976false);977978if (unlikely(!backbone_gw))979return true;980981/* this must be a CLAIM frame */982batadv_bla_add_claim(bat_priv, claim_addr, vid, backbone_gw);983if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))984batadv_bla_send_claim(bat_priv, claim_addr, vid,985BATADV_CLAIM_TYPE_CLAIM);986987/* TODO: we could call something like tt_local_del() here. */988989batadv_backbone_gw_put(backbone_gw);990return true;991}992993/**994* batadv_check_claim_group() - check for claim group membership995* @bat_priv: the bat priv with all the mesh interface information996* @primary_if: the primary interface of this batman interface997* @hw_src: the Hardware source in the ARP Header998* @hw_dst: the Hardware destination in the ARP Header999* @ethhdr: pointer to the Ethernet header of the claim frame1000*1001* checks if it is a claim packet and if it's on the same group.1002* This function also applies the group ID of the sender1003* if it is in the same mesh.1004*1005* Return:1006* 2 - if it is a claim packet and on the same group1007* 1 - if is a claim packet from another group1008* 0 - if it is not a claim packet1009*/1010static int batadv_check_claim_group(struct batadv_priv *bat_priv,1011struct batadv_hard_iface *primary_if,1012u8 *hw_src, u8 *hw_dst,1013struct ethhdr *ethhdr)1014{1015u8 *backbone_addr;1016struct batadv_orig_node *orig_node;1017struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;10181019bla_dst = (struct batadv_bla_claim_dst *)hw_dst;1020bla_dst_own = &bat_priv->bla.claim_dest;10211022/* if announcement packet, use the source,1023* otherwise assume it is in the hw_src1024*/1025switch (bla_dst->type) {1026case BATADV_CLAIM_TYPE_CLAIM:1027backbone_addr = hw_src;1028break;1029case BATADV_CLAIM_TYPE_REQUEST:1030case BATADV_CLAIM_TYPE_ANNOUNCE:1031case BATADV_CLAIM_TYPE_UNCLAIM:1032backbone_addr = ethhdr->h_source;1033break;1034default:1035return 0;1036}10371038/* don't accept claim frames from ourselves */1039if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))1040return 0;10411042/* if its already the same group, it is fine. */1043if (bla_dst->group == bla_dst_own->group)1044return 2;10451046/* lets see if this originator is in our mesh */1047orig_node = batadv_orig_hash_find(bat_priv, backbone_addr);10481049/* don't accept claims from gateways which are not in1050* the same mesh or group.1051*/1052if (!orig_node)1053return 1;10541055/* if our mesh friends mac is bigger, use it for ourselves. */1056if (ntohs(bla_dst->group) > ntohs(bla_dst_own->group)) {1057batadv_dbg(BATADV_DBG_BLA, bat_priv,1058"taking other backbones claim group: %#.4x\n",1059ntohs(bla_dst->group));1060bla_dst_own->group = bla_dst->group;1061}10621063batadv_orig_node_put(orig_node);10641065return 2;1066}10671068/**1069* batadv_bla_process_claim() - Check if this is a claim frame, and process it1070* @bat_priv: the bat priv with all the mesh interface information1071* @primary_if: the primary hard interface of this batman mesh interface1072* @skb: the frame to be checked1073*1074* Return: true if it was a claim frame, otherwise return false to1075* tell the callee that it can use the frame on its own.1076*/1077static bool batadv_bla_process_claim(struct batadv_priv *bat_priv,1078struct batadv_hard_iface *primary_if,1079struct sk_buff *skb)1080{1081struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;1082u8 *hw_src, *hw_dst;1083struct vlan_hdr *vhdr, vhdr_buf;1084struct ethhdr *ethhdr;1085struct arphdr *arphdr;1086unsigned short vid;1087int vlan_depth = 0;1088__be16 proto;1089int headlen;1090int ret;10911092vid = batadv_get_vid(skb, 0);1093ethhdr = eth_hdr(skb);10941095proto = ethhdr->h_proto;1096headlen = ETH_HLEN;1097if (vid & BATADV_VLAN_HAS_TAG) {1098/* Traverse the VLAN/Ethertypes.1099*1100* At this point it is known that the first protocol is a VLAN1101* header, so start checking at the encapsulated protocol.1102*1103* The depth of the VLAN headers is recorded to drop BLA claim1104* frames encapsulated into multiple VLAN headers (QinQ).1105*/1106do {1107vhdr = skb_header_pointer(skb, headlen, VLAN_HLEN,1108&vhdr_buf);1109if (!vhdr)1110return false;11111112proto = vhdr->h_vlan_encapsulated_proto;1113headlen += VLAN_HLEN;1114vlan_depth++;1115} while (proto == htons(ETH_P_8021Q));1116}11171118if (proto != htons(ETH_P_ARP))1119return false; /* not a claim frame */11201121/* this must be a ARP frame. check if it is a claim. */11221123if (unlikely(!pskb_may_pull(skb, headlen + arp_hdr_len(skb->dev))))1124return false;11251126/* pskb_may_pull() may have modified the pointers, get ethhdr again */1127ethhdr = eth_hdr(skb);1128arphdr = (struct arphdr *)((u8 *)ethhdr + headlen);11291130/* Check whether the ARP frame carries a valid1131* IP information1132*/1133if (arphdr->ar_hrd != htons(ARPHRD_ETHER))1134return false;1135if (arphdr->ar_pro != htons(ETH_P_IP))1136return false;1137if (arphdr->ar_hln != ETH_ALEN)1138return false;1139if (arphdr->ar_pln != 4)1140return false;11411142hw_src = (u8 *)arphdr + sizeof(struct arphdr);1143hw_dst = hw_src + ETH_ALEN + 4;1144bla_dst = (struct batadv_bla_claim_dst *)hw_dst;1145bla_dst_own = &bat_priv->bla.claim_dest;11461147/* check if it is a claim frame in general */1148if (memcmp(bla_dst->magic, bla_dst_own->magic,1149sizeof(bla_dst->magic)) != 0)1150return false;11511152/* check if there is a claim frame encapsulated deeper in (QinQ) and1153* drop that, as this is not supported by BLA but should also not be1154* sent via the mesh.1155*/1156if (vlan_depth > 1)1157return true;11581159/* Let the loopdetect frames on the mesh in any case. */1160if (bla_dst->type == BATADV_CLAIM_TYPE_LOOPDETECT)1161return false;11621163/* check if it is a claim frame. */1164ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst,1165ethhdr);1166if (ret == 1)1167batadv_dbg(BATADV_DBG_BLA, bat_priv,1168"%s(): received a claim frame from another group. From: %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",1169__func__, ethhdr->h_source, batadv_print_vid(vid),1170hw_src, hw_dst);11711172if (ret < 2)1173return !!ret;11741175/* become a backbone gw ourselves on this vlan if not happened yet */1176batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);11771178/* check for the different types of claim frames ... */1179switch (bla_dst->type) {1180case BATADV_CLAIM_TYPE_CLAIM:1181if (batadv_handle_claim(bat_priv, primary_if, hw_src,1182ethhdr->h_source, vid))1183return true;1184break;1185case BATADV_CLAIM_TYPE_UNCLAIM:1186if (batadv_handle_unclaim(bat_priv, primary_if,1187ethhdr->h_source, hw_src, vid))1188return true;1189break;11901191case BATADV_CLAIM_TYPE_ANNOUNCE:1192if (batadv_handle_announce(bat_priv, hw_src, ethhdr->h_source,1193vid))1194return true;1195break;1196case BATADV_CLAIM_TYPE_REQUEST:1197if (batadv_handle_request(bat_priv, primary_if, hw_src, ethhdr,1198vid))1199return true;1200break;1201}12021203batadv_dbg(BATADV_DBG_BLA, bat_priv,1204"%s(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",1205__func__, ethhdr->h_source, batadv_print_vid(vid), hw_src,1206hw_dst);1207return true;1208}12091210/**1211* batadv_bla_purge_backbone_gw() - Remove backbone gateways after a timeout or1212* immediately1213* @bat_priv: the bat priv with all the mesh interface information1214* @now: whether the whole hash shall be wiped now1215*1216* Check when we last heard from other nodes, and remove them in case of1217* a time out, or clean all backbone gws if now is set.1218*/1219static void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now)1220{1221struct batadv_bla_backbone_gw *backbone_gw;1222struct hlist_node *node_tmp;1223struct hlist_head *head;1224struct batadv_hashtable *hash;1225spinlock_t *list_lock; /* protects write access to the hash lists */1226int i;12271228hash = bat_priv->bla.backbone_hash;1229if (!hash)1230return;12311232for (i = 0; i < hash->size; i++) {1233head = &hash->table[i];1234list_lock = &hash->list_locks[i];12351236spin_lock_bh(list_lock);1237hlist_for_each_entry_safe(backbone_gw, node_tmp,1238head, hash_entry) {1239if (now)1240goto purge_now;1241if (!batadv_has_timed_out(backbone_gw->lasttime,1242BATADV_BLA_BACKBONE_TIMEOUT))1243continue;12441245batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,1246"%s(): backbone gw %pM timed out\n",1247__func__, backbone_gw->orig);12481249purge_now:1250/* don't wait for the pending request anymore */1251if (atomic_read(&backbone_gw->request_sent))1252atomic_dec(&bat_priv->bla.num_requests);12531254batadv_bla_del_backbone_claims(backbone_gw);12551256hlist_del_rcu(&backbone_gw->hash_entry);1257batadv_backbone_gw_put(backbone_gw);1258}1259spin_unlock_bh(list_lock);1260}1261}12621263/**1264* batadv_bla_purge_claims() - Remove claims after a timeout or immediately1265* @bat_priv: the bat priv with all the mesh interface information1266* @primary_if: the selected primary interface, may be NULL if now is set1267* @now: whether the whole hash shall be wiped now1268*1269* Check when we heard last time from our own claims, and remove them in case of1270* a time out, or clean all claims if now is set1271*/1272static void batadv_bla_purge_claims(struct batadv_priv *bat_priv,1273struct batadv_hard_iface *primary_if,1274int now)1275{1276struct batadv_bla_backbone_gw *backbone_gw;1277struct batadv_bla_claim *claim;1278struct hlist_head *head;1279struct batadv_hashtable *hash;1280int i;12811282hash = bat_priv->bla.claim_hash;1283if (!hash)1284return;12851286for (i = 0; i < hash->size; i++) {1287head = &hash->table[i];12881289rcu_read_lock();1290hlist_for_each_entry_rcu(claim, head, hash_entry) {1291backbone_gw = batadv_bla_claim_get_backbone_gw(claim);1292if (now)1293goto purge_now;12941295if (!batadv_compare_eth(backbone_gw->orig,1296primary_if->net_dev->dev_addr))1297goto skip;12981299if (!batadv_has_timed_out(claim->lasttime,1300BATADV_BLA_CLAIM_TIMEOUT))1301goto skip;13021303batadv_dbg(BATADV_DBG_BLA, bat_priv,1304"%s(): timed out.\n", __func__);13051306purge_now:1307batadv_dbg(BATADV_DBG_BLA, bat_priv,1308"%s(): %pM, vid %d\n", __func__,1309claim->addr, claim->vid);13101311batadv_handle_unclaim(bat_priv, primary_if,1312backbone_gw->orig,1313claim->addr, claim->vid);1314skip:1315batadv_backbone_gw_put(backbone_gw);1316}1317rcu_read_unlock();1318}1319}13201321/**1322* batadv_bla_update_orig_address() - Update the backbone gateways when the own1323* originator address changes1324* @bat_priv: the bat priv with all the mesh interface information1325* @primary_if: the new selected primary_if1326* @oldif: the old primary interface, may be NULL1327*/1328void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,1329struct batadv_hard_iface *primary_if,1330struct batadv_hard_iface *oldif)1331{1332struct batadv_bla_backbone_gw *backbone_gw;1333struct hlist_head *head;1334struct batadv_hashtable *hash;1335__be16 group;1336int i;13371338/* reset bridge loop avoidance group id */1339group = htons(crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN));1340bat_priv->bla.claim_dest.group = group;13411342/* purge everything when bridge loop avoidance is turned off */1343if (!atomic_read(&bat_priv->bridge_loop_avoidance))1344oldif = NULL;13451346if (!oldif) {1347batadv_bla_purge_claims(bat_priv, NULL, 1);1348batadv_bla_purge_backbone_gw(bat_priv, 1);1349return;1350}13511352hash = bat_priv->bla.backbone_hash;1353if (!hash)1354return;13551356for (i = 0; i < hash->size; i++) {1357head = &hash->table[i];13581359rcu_read_lock();1360hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {1361/* own orig still holds the old value. */1362if (!batadv_compare_eth(backbone_gw->orig,1363oldif->net_dev->dev_addr))1364continue;13651366ether_addr_copy(backbone_gw->orig,1367primary_if->net_dev->dev_addr);1368/* send an announce frame so others will ask for our1369* claims and update their tables.1370*/1371batadv_bla_send_announce(bat_priv, backbone_gw);1372}1373rcu_read_unlock();1374}1375}13761377/**1378* batadv_bla_send_loopdetect() - send a loopdetect frame1379* @bat_priv: the bat priv with all the mesh interface information1380* @backbone_gw: the backbone gateway for which a loop should be detected1381*1382* To detect loops that the bridge loop avoidance can't handle, send a loop1383* detection packet on the backbone. Unlike other BLA frames, this frame will1384* be allowed on the mesh by other nodes. If it is received on the mesh, this1385* indicates that there is a loop.1386*/1387static void1388batadv_bla_send_loopdetect(struct batadv_priv *bat_priv,1389struct batadv_bla_backbone_gw *backbone_gw)1390{1391batadv_dbg(BATADV_DBG_BLA, bat_priv, "Send loopdetect frame for vid %d\n",1392backbone_gw->vid);1393batadv_bla_send_claim(bat_priv, bat_priv->bla.loopdetect_addr,1394backbone_gw->vid, BATADV_CLAIM_TYPE_LOOPDETECT);1395}13961397/**1398* batadv_bla_status_update() - purge bla interfaces if necessary1399* @net_dev: the mesh interface net device1400*/1401void batadv_bla_status_update(struct net_device *net_dev)1402{1403struct batadv_priv *bat_priv = netdev_priv(net_dev);1404struct batadv_hard_iface *primary_if;14051406primary_if = batadv_primary_if_get_selected(bat_priv);1407if (!primary_if)1408return;14091410/* this function already purges everything when bla is disabled,1411* so just call that one.1412*/1413batadv_bla_update_orig_address(bat_priv, primary_if, primary_if);1414batadv_hardif_put(primary_if);1415}14161417/**1418* batadv_bla_periodic_work() - performs periodic bla work1419* @work: kernel work struct1420*1421* periodic work to do:1422* * purge structures when they are too old1423* * send announcements1424*/1425static void batadv_bla_periodic_work(struct work_struct *work)1426{1427struct delayed_work *delayed_work;1428struct batadv_priv *bat_priv;1429struct batadv_priv_bla *priv_bla;1430struct hlist_head *head;1431struct batadv_bla_backbone_gw *backbone_gw;1432struct batadv_hashtable *hash;1433struct batadv_hard_iface *primary_if;1434bool send_loopdetect = false;1435int i;14361437delayed_work = to_delayed_work(work);1438priv_bla = container_of(delayed_work, struct batadv_priv_bla, work);1439bat_priv = container_of(priv_bla, struct batadv_priv, bla);1440primary_if = batadv_primary_if_get_selected(bat_priv);1441if (!primary_if)1442goto out;14431444batadv_bla_purge_claims(bat_priv, primary_if, 0);1445batadv_bla_purge_backbone_gw(bat_priv, 0);14461447if (!atomic_read(&bat_priv->bridge_loop_avoidance))1448goto out;14491450if (atomic_dec_and_test(&bat_priv->bla.loopdetect_next)) {1451/* set a new random mac address for the next bridge loop1452* detection frames. Set the locally administered bit to avoid1453* collisions with users mac addresses.1454*/1455eth_random_addr(bat_priv->bla.loopdetect_addr);1456bat_priv->bla.loopdetect_addr[0] = 0xba;1457bat_priv->bla.loopdetect_addr[1] = 0xbe;1458bat_priv->bla.loopdetect_lasttime = jiffies;1459atomic_set(&bat_priv->bla.loopdetect_next,1460BATADV_BLA_LOOPDETECT_PERIODS);14611462/* mark for sending loop detect on all VLANs */1463send_loopdetect = true;1464}14651466hash = bat_priv->bla.backbone_hash;1467if (!hash)1468goto out;14691470for (i = 0; i < hash->size; i++) {1471head = &hash->table[i];14721473rcu_read_lock();1474hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {1475if (!batadv_compare_eth(backbone_gw->orig,1476primary_if->net_dev->dev_addr))1477continue;14781479backbone_gw->lasttime = jiffies;14801481batadv_bla_send_announce(bat_priv, backbone_gw);1482if (send_loopdetect)1483batadv_bla_send_loopdetect(bat_priv,1484backbone_gw);14851486/* request_sent is only set after creation to avoid1487* problems when we are not yet known as backbone gw1488* in the backbone.1489*1490* We can reset this now after we waited some periods1491* to give bridge forward delays and bla group forming1492* some grace time.1493*/14941495if (atomic_read(&backbone_gw->request_sent) == 0)1496continue;14971498if (!atomic_dec_and_test(&backbone_gw->wait_periods))1499continue;15001501atomic_dec(&backbone_gw->bat_priv->bla.num_requests);1502atomic_set(&backbone_gw->request_sent, 0);1503}1504rcu_read_unlock();1505}1506out:1507batadv_hardif_put(primary_if);15081509queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,1510msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));1511}15121513/* The hash for claim and backbone hash receive the same key because they1514* are getting initialized by hash_new with the same key. Reinitializing1515* them with to different keys to allow nested locking without generating1516* lockdep warnings1517*/1518static struct lock_class_key batadv_claim_hash_lock_class_key;1519static struct lock_class_key batadv_backbone_hash_lock_class_key;15201521/**1522* batadv_bla_init() - initialize all bla structures1523* @bat_priv: the bat priv with all the mesh interface information1524*1525* Return: 0 on success, < 0 on error.1526*/1527int batadv_bla_init(struct batadv_priv *bat_priv)1528{1529int i;1530u8 claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00};1531struct batadv_hard_iface *primary_if;1532u16 crc;1533unsigned long entrytime;15341535spin_lock_init(&bat_priv->bla.bcast_duplist_lock);15361537batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hash registering\n");15381539/* setting claim destination address */1540memcpy(&bat_priv->bla.claim_dest.magic, claim_dest, 3);1541bat_priv->bla.claim_dest.type = 0;1542primary_if = batadv_primary_if_get_selected(bat_priv);1543if (primary_if) {1544crc = crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN);1545bat_priv->bla.claim_dest.group = htons(crc);1546batadv_hardif_put(primary_if);1547} else {1548bat_priv->bla.claim_dest.group = 0; /* will be set later */1549}15501551/* initialize the duplicate list */1552entrytime = jiffies - msecs_to_jiffies(BATADV_DUPLIST_TIMEOUT);1553for (i = 0; i < BATADV_DUPLIST_SIZE; i++)1554bat_priv->bla.bcast_duplist[i].entrytime = entrytime;1555bat_priv->bla.bcast_duplist_curr = 0;15561557atomic_set(&bat_priv->bla.loopdetect_next,1558BATADV_BLA_LOOPDETECT_PERIODS);15591560if (bat_priv->bla.claim_hash)1561return 0;15621563bat_priv->bla.claim_hash = batadv_hash_new(128);1564if (!bat_priv->bla.claim_hash)1565return -ENOMEM;15661567bat_priv->bla.backbone_hash = batadv_hash_new(32);1568if (!bat_priv->bla.backbone_hash) {1569batadv_hash_destroy(bat_priv->bla.claim_hash);1570return -ENOMEM;1571}15721573batadv_hash_set_lock_class(bat_priv->bla.claim_hash,1574&batadv_claim_hash_lock_class_key);1575batadv_hash_set_lock_class(bat_priv->bla.backbone_hash,1576&batadv_backbone_hash_lock_class_key);15771578batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hashes initialized\n");15791580INIT_DELAYED_WORK(&bat_priv->bla.work, batadv_bla_periodic_work);15811582queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,1583msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));1584return 0;1585}15861587/**1588* batadv_skb_crc32() - calculate CRC32 of the whole packet and skip bytes in1589* the header1590* @skb: skb pointing to fragmented socket buffers1591* @payload_ptr: Pointer to position inside the head buffer of the skb1592* marking the start of the data to be CRC'ed1593*1594* payload_ptr must always point to an address in the skb head buffer and not to1595* a fragment.1596*1597* Return: big endian crc32c of the checksummed data1598*/1599static __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr)1600{1601unsigned int to = skb->len;1602unsigned int consumed = 0;1603struct skb_seq_state st;1604unsigned int from;1605unsigned int len;1606const u8 *data;1607u32 crc = 0;16081609from = (unsigned int)(payload_ptr - skb->data);16101611skb_prepare_seq_read(skb, from, to, &st);1612while ((len = skb_seq_read(consumed, &data, &st)) != 0) {1613crc = crc32c(crc, data, len);1614consumed += len;1615}16161617return htonl(crc);1618}16191620/**1621* batadv_bla_check_duplist() - Check if a frame is in the broadcast dup.1622* @bat_priv: the bat priv with all the mesh interface information1623* @skb: contains the multicast packet to be checked1624* @payload_ptr: pointer to position inside the head buffer of the skb1625* marking the start of the data to be CRC'ed1626* @orig: originator mac address, NULL if unknown1627*1628* Check if it is on our broadcast list. Another gateway might have sent the1629* same packet because it is connected to the same backbone, so we have to1630* remove this duplicate.1631*1632* This is performed by checking the CRC, which will tell us1633* with a good chance that it is the same packet. If it is furthermore1634* sent by another host, drop it. We allow equal packets from1635* the same host however as this might be intended.1636*1637* Return: true if a packet is in the duplicate list, false otherwise.1638*/1639static bool batadv_bla_check_duplist(struct batadv_priv *bat_priv,1640struct sk_buff *skb, u8 *payload_ptr,1641const u8 *orig)1642{1643struct batadv_bcast_duplist_entry *entry;1644bool ret = false;1645int i, curr;1646__be32 crc;16471648/* calculate the crc ... */1649crc = batadv_skb_crc32(skb, payload_ptr);16501651spin_lock_bh(&bat_priv->bla.bcast_duplist_lock);16521653for (i = 0; i < BATADV_DUPLIST_SIZE; i++) {1654curr = (bat_priv->bla.bcast_duplist_curr + i);1655curr %= BATADV_DUPLIST_SIZE;1656entry = &bat_priv->bla.bcast_duplist[curr];16571658/* we can stop searching if the entry is too old ;1659* later entries will be even older1660*/1661if (batadv_has_timed_out(entry->entrytime,1662BATADV_DUPLIST_TIMEOUT))1663break;16641665if (entry->crc != crc)1666continue;16671668/* are the originators both known and not anonymous? */1669if (orig && !is_zero_ether_addr(orig) &&1670!is_zero_ether_addr(entry->orig)) {1671/* If known, check if the new frame came from1672* the same originator:1673* We are safe to take identical frames from the1674* same orig, if known, as multiplications in1675* the mesh are detected via the (orig, seqno) pair.1676* So we can be a bit more liberal here and allow1677* identical frames from the same orig which the source1678* host might have sent multiple times on purpose.1679*/1680if (batadv_compare_eth(entry->orig, orig))1681continue;1682}16831684/* this entry seems to match: same crc, not too old,1685* and from another gw. therefore return true to forbid it.1686*/1687ret = true;1688goto out;1689}1690/* not found, add a new entry (overwrite the oldest entry)1691* and allow it, its the first occurrence.1692*/1693curr = (bat_priv->bla.bcast_duplist_curr + BATADV_DUPLIST_SIZE - 1);1694curr %= BATADV_DUPLIST_SIZE;1695entry = &bat_priv->bla.bcast_duplist[curr];1696entry->crc = crc;1697entry->entrytime = jiffies;16981699/* known originator */1700if (orig)1701ether_addr_copy(entry->orig, orig);1702/* anonymous originator */1703else1704eth_zero_addr(entry->orig);17051706bat_priv->bla.bcast_duplist_curr = curr;17071708out:1709spin_unlock_bh(&bat_priv->bla.bcast_duplist_lock);17101711return ret;1712}17131714/**1715* batadv_bla_check_ucast_duplist() - Check if a frame is in the broadcast dup.1716* @bat_priv: the bat priv with all the mesh interface information1717* @skb: contains the multicast packet to be checked, decapsulated from a1718* unicast_packet1719*1720* Check if it is on our broadcast list. Another gateway might have sent the1721* same packet because it is connected to the same backbone, so we have to1722* remove this duplicate.1723*1724* Return: true if a packet is in the duplicate list, false otherwise.1725*/1726static bool batadv_bla_check_ucast_duplist(struct batadv_priv *bat_priv,1727struct sk_buff *skb)1728{1729return batadv_bla_check_duplist(bat_priv, skb, (u8 *)skb->data, NULL);1730}17311732/**1733* batadv_bla_check_bcast_duplist() - Check if a frame is in the broadcast dup.1734* @bat_priv: the bat priv with all the mesh interface information1735* @skb: contains the bcast_packet to be checked1736*1737* Check if it is on our broadcast list. Another gateway might have sent the1738* same packet because it is connected to the same backbone, so we have to1739* remove this duplicate.1740*1741* Return: true if a packet is in the duplicate list, false otherwise.1742*/1743bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,1744struct sk_buff *skb)1745{1746struct batadv_bcast_packet *bcast_packet;1747u8 *payload_ptr;17481749bcast_packet = (struct batadv_bcast_packet *)skb->data;1750payload_ptr = (u8 *)(bcast_packet + 1);17511752return batadv_bla_check_duplist(bat_priv, skb, payload_ptr,1753bcast_packet->orig);1754}17551756/**1757* batadv_bla_is_backbone_gw_orig() - Check if the originator is a gateway for1758* the VLAN identified by vid.1759* @bat_priv: the bat priv with all the mesh interface information1760* @orig: originator mac address1761* @vid: VLAN identifier1762*1763* Return: true if orig is a backbone for this vid, false otherwise.1764*/1765bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig,1766unsigned short vid)1767{1768struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;1769struct hlist_head *head;1770struct batadv_bla_backbone_gw *backbone_gw;1771int i;17721773if (!atomic_read(&bat_priv->bridge_loop_avoidance))1774return false;17751776if (!hash)1777return false;17781779for (i = 0; i < hash->size; i++) {1780head = &hash->table[i];17811782rcu_read_lock();1783hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {1784if (batadv_compare_eth(backbone_gw->orig, orig) &&1785backbone_gw->vid == vid) {1786rcu_read_unlock();1787return true;1788}1789}1790rcu_read_unlock();1791}17921793return false;1794}17951796/**1797* batadv_bla_is_backbone_gw() - check if originator is a backbone gw for a VLAN1798* @skb: the frame to be checked1799* @orig_node: the orig_node of the frame1800* @hdr_size: maximum length of the frame1801*1802* Return: true if the orig_node is also a gateway on the mesh interface,1803* otherwise it returns false.1804*/1805bool batadv_bla_is_backbone_gw(struct sk_buff *skb,1806struct batadv_orig_node *orig_node, int hdr_size)1807{1808struct batadv_bla_backbone_gw *backbone_gw;1809unsigned short vid;18101811if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))1812return false;18131814/* first, find out the vid. */1815if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))1816return false;18171818vid = batadv_get_vid(skb, hdr_size);18191820/* see if this originator is a backbone gw for this VLAN */1821backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,1822orig_node->orig, vid);1823if (!backbone_gw)1824return false;18251826batadv_backbone_gw_put(backbone_gw);1827return true;1828}18291830/**1831* batadv_bla_free() - free all bla structures1832* @bat_priv: the bat priv with all the mesh interface information1833*1834* for meshinterface free or module unload1835*/1836void batadv_bla_free(struct batadv_priv *bat_priv)1837{1838struct batadv_hard_iface *primary_if;18391840cancel_delayed_work_sync(&bat_priv->bla.work);1841primary_if = batadv_primary_if_get_selected(bat_priv);18421843if (bat_priv->bla.claim_hash) {1844batadv_bla_purge_claims(bat_priv, primary_if, 1);1845batadv_hash_destroy(bat_priv->bla.claim_hash);1846bat_priv->bla.claim_hash = NULL;1847}1848if (bat_priv->bla.backbone_hash) {1849batadv_bla_purge_backbone_gw(bat_priv, 1);1850batadv_hash_destroy(bat_priv->bla.backbone_hash);1851bat_priv->bla.backbone_hash = NULL;1852}1853batadv_hardif_put(primary_if);1854}18551856/**1857* batadv_bla_loopdetect_check() - check and handle a detected loop1858* @bat_priv: the bat priv with all the mesh interface information1859* @skb: the packet to check1860* @primary_if: interface where the request came on1861* @vid: the VLAN ID of the frame1862*1863* Checks if this packet is a loop detect frame which has been sent by us,1864* throws an uevent and logs the event if that is the case.1865*1866* Return: true if it is a loop detect frame which is to be dropped, false1867* otherwise.1868*/1869static bool1870batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,1871struct batadv_hard_iface *primary_if,1872unsigned short vid)1873{1874struct batadv_bla_backbone_gw *backbone_gw;1875struct ethhdr *ethhdr;1876bool ret;18771878ethhdr = eth_hdr(skb);18791880/* Only check for the MAC address and skip more checks here for1881* performance reasons - this function is on the hotpath, after all.1882*/1883if (!batadv_compare_eth(ethhdr->h_source,1884bat_priv->bla.loopdetect_addr))1885return false;18861887/* If the packet came too late, don't forward it on the mesh1888* but don't consider that as loop. It might be a coincidence.1889*/1890if (batadv_has_timed_out(bat_priv->bla.loopdetect_lasttime,1891BATADV_BLA_LOOPDETECT_TIMEOUT))1892return true;18931894backbone_gw = batadv_bla_get_backbone_gw(bat_priv,1895primary_if->net_dev->dev_addr,1896vid, true);1897if (unlikely(!backbone_gw))1898return true;18991900ret = queue_work(batadv_event_workqueue, &backbone_gw->report_work);19011902/* backbone_gw is unreferenced in the report work function1903* if queue_work() call was successful1904*/1905if (!ret)1906batadv_backbone_gw_put(backbone_gw);19071908return true;1909}19101911/**1912* batadv_bla_rx() - check packets coming from the mesh.1913* @bat_priv: the bat priv with all the mesh interface information1914* @skb: the frame to be checked1915* @vid: the VLAN ID of the frame1916* @packet_type: the batman packet type this frame came in1917*1918* batadv_bla_rx avoidance checks if:1919* * we have to race for a claim1920* * if the frame is allowed on the LAN1921*1922* In these cases, the skb is further handled by this function1923*1924* Return: true if handled, otherwise it returns false and the caller shall1925* further process the skb.1926*/1927bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,1928unsigned short vid, int packet_type)1929{1930struct batadv_bla_backbone_gw *backbone_gw;1931struct ethhdr *ethhdr;1932struct batadv_bla_claim search_claim, *claim = NULL;1933struct batadv_hard_iface *primary_if;1934bool own_claim;1935bool ret;19361937ethhdr = eth_hdr(skb);19381939primary_if = batadv_primary_if_get_selected(bat_priv);1940if (!primary_if)1941goto handled;19421943if (!atomic_read(&bat_priv->bridge_loop_avoidance))1944goto allow;19451946if (batadv_bla_loopdetect_check(bat_priv, skb, primary_if, vid))1947goto handled;19481949if (unlikely(atomic_read(&bat_priv->bla.num_requests)))1950/* don't allow multicast packets while requests are in flight */1951if (is_multicast_ether_addr(ethhdr->h_dest))1952/* Both broadcast flooding or multicast-via-unicasts1953* delivery might send to multiple backbone gateways1954* sharing the same LAN and therefore need to coordinate1955* which backbone gateway forwards into the LAN,1956* by claiming the payload source address.1957*1958* Broadcast flooding and multicast-via-unicasts1959* delivery use the following two batman packet types.1960* Note: explicitly exclude BATADV_UNICAST_4ADDR,1961* as the DHCP gateway feature will send explicitly1962* to only one BLA gateway, so the claiming process1963* should be avoided there.1964*/1965if (packet_type == BATADV_BCAST ||1966packet_type == BATADV_UNICAST)1967goto handled;19681969/* potential duplicates from foreign BLA backbone gateways via1970* multicast-in-unicast packets1971*/1972if (is_multicast_ether_addr(ethhdr->h_dest) &&1973packet_type == BATADV_UNICAST &&1974batadv_bla_check_ucast_duplist(bat_priv, skb))1975goto handled;19761977ether_addr_copy(search_claim.addr, ethhdr->h_source);1978search_claim.vid = vid;1979claim = batadv_claim_hash_find(bat_priv, &search_claim);19801981if (!claim) {1982bool local = batadv_is_my_client(bat_priv, ethhdr->h_source, vid);19831984/* possible optimization: race for a claim */1985/* No claim exists yet, claim it for us!1986*/19871988batadv_dbg(BATADV_DBG_BLA, bat_priv,1989"%s(): Unclaimed MAC %pM found. Claim it. Local: %s\n",1990__func__, ethhdr->h_source, str_yes_no(local));1991batadv_handle_claim(bat_priv, primary_if,1992primary_if->net_dev->dev_addr,1993ethhdr->h_source, vid);1994goto allow;1995}19961997/* if it is our own claim ... */1998backbone_gw = batadv_bla_claim_get_backbone_gw(claim);1999own_claim = batadv_compare_eth(backbone_gw->orig,2000primary_if->net_dev->dev_addr);2001batadv_backbone_gw_put(backbone_gw);20022003if (own_claim) {2004/* ... allow it in any case */2005claim->lasttime = jiffies;2006goto allow;2007}20082009/* if it is a multicast ... */2010if (is_multicast_ether_addr(ethhdr->h_dest) &&2011(packet_type == BATADV_BCAST || packet_type == BATADV_UNICAST)) {2012/* ... drop it. the responsible gateway is in charge.2013*2014* We need to check packet type because with the gateway2015* feature, broadcasts (like DHCP requests) may be sent2016* using a unicast 4 address packet type. See comment above.2017*/2018goto handled;2019} else {2020/* seems the client considers us as its best gateway.2021* send a claim and update the claim table2022* immediately.2023*/2024batadv_handle_claim(bat_priv, primary_if,2025primary_if->net_dev->dev_addr,2026ethhdr->h_source, vid);2027goto allow;2028}2029allow:2030batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);2031ret = false;2032goto out;20332034handled:2035kfree_skb(skb);2036ret = true;20372038out:2039batadv_hardif_put(primary_if);2040batadv_claim_put(claim);2041return ret;2042}20432044/**2045* batadv_bla_tx() - check packets going into the mesh2046* @bat_priv: the bat priv with all the mesh interface information2047* @skb: the frame to be checked2048* @vid: the VLAN ID of the frame2049*2050* batadv_bla_tx checks if:2051* * a claim was received which has to be processed2052* * the frame is allowed on the mesh2053*2054* in these cases, the skb is further handled by this function.2055*2056* This call might reallocate skb data.2057*2058* Return: true if handled, otherwise it returns false and the caller shall2059* further process the skb.2060*/2061bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,2062unsigned short vid)2063{2064struct ethhdr *ethhdr;2065struct batadv_bla_claim search_claim, *claim = NULL;2066struct batadv_bla_backbone_gw *backbone_gw;2067struct batadv_hard_iface *primary_if;2068bool client_roamed;2069bool ret = false;20702071primary_if = batadv_primary_if_get_selected(bat_priv);2072if (!primary_if)2073goto out;20742075if (!atomic_read(&bat_priv->bridge_loop_avoidance))2076goto allow;20772078if (batadv_bla_process_claim(bat_priv, primary_if, skb))2079goto handled;20802081ethhdr = eth_hdr(skb);20822083if (unlikely(atomic_read(&bat_priv->bla.num_requests)))2084/* don't allow broadcasts while requests are in flight */2085if (is_multicast_ether_addr(ethhdr->h_dest))2086goto handled;20872088ether_addr_copy(search_claim.addr, ethhdr->h_source);2089search_claim.vid = vid;20902091claim = batadv_claim_hash_find(bat_priv, &search_claim);20922093/* if no claim exists, allow it. */2094if (!claim)2095goto allow;20962097/* check if we are responsible. */2098backbone_gw = batadv_bla_claim_get_backbone_gw(claim);2099client_roamed = batadv_compare_eth(backbone_gw->orig,2100primary_if->net_dev->dev_addr);2101batadv_backbone_gw_put(backbone_gw);21022103if (client_roamed) {2104/* if yes, the client has roamed and we have2105* to unclaim it.2106*/2107if (batadv_has_timed_out(claim->lasttime, 100)) {2108/* only unclaim if the last claim entry is2109* older than 100 ms to make sure we really2110* have a roaming client here.2111*/2112batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Roaming client %pM detected. Unclaim it.\n",2113__func__, ethhdr->h_source);2114batadv_handle_unclaim(bat_priv, primary_if,2115primary_if->net_dev->dev_addr,2116ethhdr->h_source, vid);2117goto allow;2118} else {2119batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Race for claim %pM detected. Drop packet.\n",2120__func__, ethhdr->h_source);2121goto handled;2122}2123}21242125/* check if it is a multicast/broadcast frame */2126if (is_multicast_ether_addr(ethhdr->h_dest)) {2127/* drop it. the responsible gateway has forwarded it into2128* the backbone network.2129*/2130goto handled;2131} else {2132/* we must allow it. at least if we are2133* responsible for the DESTINATION.2134*/2135goto allow;2136}2137allow:2138batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);2139ret = false;2140goto out;2141handled:2142ret = true;2143out:2144batadv_hardif_put(primary_if);2145batadv_claim_put(claim);2146return ret;2147}21482149/**2150* batadv_bla_claim_dump_entry() - dump one entry of the claim table2151* to a netlink socket2152* @msg: buffer for the message2153* @portid: netlink port2154* @cb: Control block containing additional options2155* @primary_if: primary interface2156* @claim: entry to dump2157*2158* Return: 0 or error code.2159*/2160static int2161batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,2162struct netlink_callback *cb,2163struct batadv_hard_iface *primary_if,2164struct batadv_bla_claim *claim)2165{2166const u8 *primary_addr = primary_if->net_dev->dev_addr;2167u16 backbone_crc;2168bool is_own;2169void *hdr;2170int ret = -EINVAL;21712172hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,2173&batadv_netlink_family, NLM_F_MULTI,2174BATADV_CMD_GET_BLA_CLAIM);2175if (!hdr) {2176ret = -ENOBUFS;2177goto out;2178}21792180genl_dump_check_consistent(cb, hdr);21812182is_own = batadv_compare_eth(claim->backbone_gw->orig,2183primary_addr);21842185spin_lock_bh(&claim->backbone_gw->crc_lock);2186backbone_crc = claim->backbone_gw->crc;2187spin_unlock_bh(&claim->backbone_gw->crc_lock);21882189if (is_own)2190if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {2191genlmsg_cancel(msg, hdr);2192goto out;2193}21942195if (nla_put(msg, BATADV_ATTR_BLA_ADDRESS, ETH_ALEN, claim->addr) ||2196nla_put_u16(msg, BATADV_ATTR_BLA_VID, claim->vid) ||2197nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,2198claim->backbone_gw->orig) ||2199nla_put_u16(msg, BATADV_ATTR_BLA_CRC,2200backbone_crc)) {2201genlmsg_cancel(msg, hdr);2202goto out;2203}22042205genlmsg_end(msg, hdr);2206ret = 0;22072208out:2209return ret;2210}22112212/**2213* batadv_bla_claim_dump_bucket() - dump one bucket of the claim table2214* to a netlink socket2215* @msg: buffer for the message2216* @portid: netlink port2217* @cb: Control block containing additional options2218* @primary_if: primary interface2219* @hash: hash to dump2220* @bucket: bucket index to dump2221* @idx_skip: How many entries to skip2222*2223* Return: always 0.2224*/2225static int2226batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid,2227struct netlink_callback *cb,2228struct batadv_hard_iface *primary_if,2229struct batadv_hashtable *hash, unsigned int bucket,2230int *idx_skip)2231{2232struct batadv_bla_claim *claim;2233int idx = 0;2234int ret = 0;22352236spin_lock_bh(&hash->list_locks[bucket]);2237cb->seq = atomic_read(&hash->generation) << 1 | 1;22382239hlist_for_each_entry(claim, &hash->table[bucket], hash_entry) {2240if (idx++ < *idx_skip)2241continue;22422243ret = batadv_bla_claim_dump_entry(msg, portid, cb,2244primary_if, claim);2245if (ret) {2246*idx_skip = idx - 1;2247goto unlock;2248}2249}22502251*idx_skip = 0;2252unlock:2253spin_unlock_bh(&hash->list_locks[bucket]);2254return ret;2255}22562257/**2258* batadv_bla_claim_dump() - dump claim table to a netlink socket2259* @msg: buffer for the message2260* @cb: callback structure containing arguments2261*2262* Return: message length.2263*/2264int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)2265{2266struct batadv_hard_iface *primary_if = NULL;2267int portid = NETLINK_CB(cb->skb).portid;2268struct net_device *mesh_iface;2269struct batadv_hashtable *hash;2270struct batadv_priv *bat_priv;2271int bucket = cb->args[0];2272int idx = cb->args[1];2273int ret = 0;22742275mesh_iface = batadv_netlink_get_meshif(cb);2276if (IS_ERR(mesh_iface))2277return PTR_ERR(mesh_iface);22782279bat_priv = netdev_priv(mesh_iface);2280hash = bat_priv->bla.claim_hash;22812282primary_if = batadv_primary_if_get_selected(bat_priv);2283if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {2284ret = -ENOENT;2285goto out;2286}22872288while (bucket < hash->size) {2289if (batadv_bla_claim_dump_bucket(msg, portid, cb, primary_if,2290hash, bucket, &idx))2291break;2292bucket++;2293}22942295cb->args[0] = bucket;2296cb->args[1] = idx;22972298ret = msg->len;22992300out:2301batadv_hardif_put(primary_if);23022303dev_put(mesh_iface);23042305return ret;2306}23072308/**2309* batadv_bla_backbone_dump_entry() - dump one entry of the backbone table to a2310* netlink socket2311* @msg: buffer for the message2312* @portid: netlink port2313* @cb: Control block containing additional options2314* @primary_if: primary interface2315* @backbone_gw: entry to dump2316*2317* Return: 0 or error code.2318*/2319static int2320batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid,2321struct netlink_callback *cb,2322struct batadv_hard_iface *primary_if,2323struct batadv_bla_backbone_gw *backbone_gw)2324{2325const u8 *primary_addr = primary_if->net_dev->dev_addr;2326u16 backbone_crc;2327bool is_own;2328int msecs;2329void *hdr;2330int ret = -EINVAL;23312332hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,2333&batadv_netlink_family, NLM_F_MULTI,2334BATADV_CMD_GET_BLA_BACKBONE);2335if (!hdr) {2336ret = -ENOBUFS;2337goto out;2338}23392340genl_dump_check_consistent(cb, hdr);23412342is_own = batadv_compare_eth(backbone_gw->orig, primary_addr);23432344spin_lock_bh(&backbone_gw->crc_lock);2345backbone_crc = backbone_gw->crc;2346spin_unlock_bh(&backbone_gw->crc_lock);23472348msecs = jiffies_to_msecs(jiffies - backbone_gw->lasttime);23492350if (is_own)2351if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {2352genlmsg_cancel(msg, hdr);2353goto out;2354}23552356if (nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,2357backbone_gw->orig) ||2358nla_put_u16(msg, BATADV_ATTR_BLA_VID, backbone_gw->vid) ||2359nla_put_u16(msg, BATADV_ATTR_BLA_CRC,2360backbone_crc) ||2361nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {2362genlmsg_cancel(msg, hdr);2363goto out;2364}23652366genlmsg_end(msg, hdr);2367ret = 0;23682369out:2370return ret;2371}23722373/**2374* batadv_bla_backbone_dump_bucket() - dump one bucket of the backbone table to2375* a netlink socket2376* @msg: buffer for the message2377* @portid: netlink port2378* @cb: Control block containing additional options2379* @primary_if: primary interface2380* @hash: hash to dump2381* @bucket: bucket index to dump2382* @idx_skip: How many entries to skip2383*2384* Return: always 0.2385*/2386static int2387batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid,2388struct netlink_callback *cb,2389struct batadv_hard_iface *primary_if,2390struct batadv_hashtable *hash,2391unsigned int bucket, int *idx_skip)2392{2393struct batadv_bla_backbone_gw *backbone_gw;2394int idx = 0;2395int ret = 0;23962397spin_lock_bh(&hash->list_locks[bucket]);2398cb->seq = atomic_read(&hash->generation) << 1 | 1;23992400hlist_for_each_entry(backbone_gw, &hash->table[bucket], hash_entry) {2401if (idx++ < *idx_skip)2402continue;24032404ret = batadv_bla_backbone_dump_entry(msg, portid, cb,2405primary_if, backbone_gw);2406if (ret) {2407*idx_skip = idx - 1;2408goto unlock;2409}2410}24112412*idx_skip = 0;2413unlock:2414spin_unlock_bh(&hash->list_locks[bucket]);2415return ret;2416}24172418/**2419* batadv_bla_backbone_dump() - dump backbone table to a netlink socket2420* @msg: buffer for the message2421* @cb: callback structure containing arguments2422*2423* Return: message length.2424*/2425int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)2426{2427struct batadv_hard_iface *primary_if = NULL;2428int portid = NETLINK_CB(cb->skb).portid;2429struct net_device *mesh_iface;2430struct batadv_hashtable *hash;2431struct batadv_priv *bat_priv;2432int bucket = cb->args[0];2433int idx = cb->args[1];2434int ret = 0;24352436mesh_iface = batadv_netlink_get_meshif(cb);2437if (IS_ERR(mesh_iface))2438return PTR_ERR(mesh_iface);24392440bat_priv = netdev_priv(mesh_iface);2441hash = bat_priv->bla.backbone_hash;24422443primary_if = batadv_primary_if_get_selected(bat_priv);2444if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {2445ret = -ENOENT;2446goto out;2447}24482449while (bucket < hash->size) {2450if (batadv_bla_backbone_dump_bucket(msg, portid, cb, primary_if,2451hash, bucket, &idx))2452break;2453bucket++;2454}24552456cb->args[0] = bucket;2457cb->args[1] = idx;24582459ret = msg->len;24602461out:2462batadv_hardif_put(primary_if);24632464dev_put(mesh_iface);24652466return ret;2467}24682469#ifdef CONFIG_BATMAN_ADV_DAT2470/**2471* batadv_bla_check_claim() - check if address is claimed2472*2473* @bat_priv: the bat priv with all the mesh interface information2474* @addr: mac address of which the claim status is checked2475* @vid: the VLAN ID2476*2477* addr is checked if this address is claimed by the local device itself.2478*2479* Return: true if bla is disabled or the mac is claimed by the device,2480* false if the device addr is already claimed by another gateway2481*/2482bool batadv_bla_check_claim(struct batadv_priv *bat_priv,2483u8 *addr, unsigned short vid)2484{2485struct batadv_bla_claim search_claim;2486struct batadv_bla_claim *claim = NULL;2487struct batadv_hard_iface *primary_if = NULL;2488bool ret = true;24892490if (!atomic_read(&bat_priv->bridge_loop_avoidance))2491return ret;24922493primary_if = batadv_primary_if_get_selected(bat_priv);2494if (!primary_if)2495return ret;24962497/* First look if the mac address is claimed */2498ether_addr_copy(search_claim.addr, addr);2499search_claim.vid = vid;25002501claim = batadv_claim_hash_find(bat_priv, &search_claim);25022503/* If there is a claim and we are not owner of the claim,2504* return false.2505*/2506if (claim) {2507if (!batadv_compare_eth(claim->backbone_gw->orig,2508primary_if->net_dev->dev_addr))2509ret = false;2510batadv_claim_put(claim);2511}25122513batadv_hardif_put(primary_if);2514return ret;2515}2516#endif251725182519