Path: blob/master/net/batman-adv/distributed-arp-table.c
26289 views
// SPDX-License-Identifier: GPL-2.01/* Copyright (C) B.A.T.M.A.N. contributors:2*3* Antonio Quartulli4*/56#include "distributed-arp-table.h"7#include "main.h"89#include <linux/atomic.h>10#include <linux/bitops.h>11#include <linux/byteorder/generic.h>12#include <linux/container_of.h>13#include <linux/err.h>14#include <linux/errno.h>15#include <linux/etherdevice.h>16#include <linux/gfp.h>17#include <linux/if_arp.h>18#include <linux/if_ether.h>19#include <linux/if_vlan.h>20#include <linux/in.h>21#include <linux/ip.h>22#include <linux/jiffies.h>23#include <linux/kref.h>24#include <linux/list.h>25#include <linux/netlink.h>26#include <linux/rculist.h>27#include <linux/rcupdate.h>28#include <linux/skbuff.h>29#include <linux/slab.h>30#include <linux/spinlock.h>31#include <linux/stddef.h>32#include <linux/string.h>33#include <linux/udp.h>34#include <linux/unaligned.h>35#include <linux/workqueue.h>36#include <net/arp.h>37#include <net/genetlink.h>38#include <net/netlink.h>39#include <uapi/linux/batman_adv.h>4041#include "bridge_loop_avoidance.h"42#include "hard-interface.h"43#include "hash.h"44#include "log.h"45#include "netlink.h"46#include "originator.h"47#include "send.h"48#include "translation-table.h"49#include "tvlv.h"5051enum batadv_bootpop {52BATADV_BOOTREPLY = 2,53};5455enum batadv_boothtype {56BATADV_HTYPE_ETHERNET = 1,57};5859enum batadv_dhcpoptioncode {60BATADV_DHCP_OPT_PAD = 0,61BATADV_DHCP_OPT_MSG_TYPE = 53,62BATADV_DHCP_OPT_END = 255,63};6465enum batadv_dhcptype {66BATADV_DHCPACK = 5,67};6869/* { 99, 130, 83, 99 } */70#define BATADV_DHCP_MAGIC 16694854117172struct batadv_dhcp_packet {73__u8 op;74__u8 htype;75__u8 hlen;76__u8 hops;77__be32 xid;78__be16 secs;79__be16 flags;80__be32 ciaddr;81__be32 yiaddr;82__be32 siaddr;83__be32 giaddr;84__u8 chaddr[16];85__u8 sname[64];86__u8 file[128];87__be32 magic;88/* __u8 options[]; */89};9091#define BATADV_DHCP_YIADDR_LEN sizeof(((struct batadv_dhcp_packet *)0)->yiaddr)92#define BATADV_DHCP_CHADDR_LEN sizeof(((struct batadv_dhcp_packet *)0)->chaddr)9394static void batadv_dat_purge(struct work_struct *work);9596/**97* batadv_dat_start_timer() - initialise the DAT periodic worker98* @bat_priv: the bat priv with all the mesh interface information99*/100static void batadv_dat_start_timer(struct batadv_priv *bat_priv)101{102queue_delayed_work(batadv_event_workqueue, &bat_priv->dat.work,103msecs_to_jiffies(10000));104}105106/**107* batadv_dat_entry_release() - release dat_entry from lists and queue for free108* after rcu grace period109* @ref: kref pointer of the dat_entry110*/111static void batadv_dat_entry_release(struct kref *ref)112{113struct batadv_dat_entry *dat_entry;114115dat_entry = container_of(ref, struct batadv_dat_entry, refcount);116117kfree_rcu(dat_entry, rcu);118}119120/**121* batadv_dat_entry_put() - decrement the dat_entry refcounter and possibly122* release it123* @dat_entry: dat_entry to be free'd124*/125static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry)126{127if (!dat_entry)128return;129130kref_put(&dat_entry->refcount, batadv_dat_entry_release);131}132133/**134* batadv_dat_to_purge() - check whether a dat_entry has to be purged or not135* @dat_entry: the entry to check136*137* Return: true if the entry has to be purged now, false otherwise.138*/139static bool batadv_dat_to_purge(struct batadv_dat_entry *dat_entry)140{141return batadv_has_timed_out(dat_entry->last_update,142BATADV_DAT_ENTRY_TIMEOUT);143}144145/**146* __batadv_dat_purge() - delete entries from the DAT local storage147* @bat_priv: the bat priv with all the mesh interface information148* @to_purge: function in charge to decide whether an entry has to be purged or149* not. This function takes the dat_entry as argument and has to150* returns a boolean value: true is the entry has to be deleted,151* false otherwise152*153* Loops over each entry in the DAT local storage and deletes it if and only if154* the to_purge function passed as argument returns true.155*/156static void __batadv_dat_purge(struct batadv_priv *bat_priv,157bool (*to_purge)(struct batadv_dat_entry *))158{159spinlock_t *list_lock; /* protects write access to the hash lists */160struct batadv_dat_entry *dat_entry;161struct hlist_node *node_tmp;162struct hlist_head *head;163u32 i;164165if (!bat_priv->dat.hash)166return;167168for (i = 0; i < bat_priv->dat.hash->size; i++) {169head = &bat_priv->dat.hash->table[i];170list_lock = &bat_priv->dat.hash->list_locks[i];171172spin_lock_bh(list_lock);173hlist_for_each_entry_safe(dat_entry, node_tmp, head,174hash_entry) {175/* if a helper function has been passed as parameter,176* ask it if the entry has to be purged or not177*/178if (to_purge && !to_purge(dat_entry))179continue;180181hlist_del_rcu(&dat_entry->hash_entry);182batadv_dat_entry_put(dat_entry);183}184spin_unlock_bh(list_lock);185}186}187188/**189* batadv_dat_purge() - periodic task that deletes old entries from the local190* DAT hash table191* @work: kernel work struct192*/193static void batadv_dat_purge(struct work_struct *work)194{195struct delayed_work *delayed_work;196struct batadv_priv_dat *priv_dat;197struct batadv_priv *bat_priv;198199delayed_work = to_delayed_work(work);200priv_dat = container_of(delayed_work, struct batadv_priv_dat, work);201bat_priv = container_of(priv_dat, struct batadv_priv, dat);202203__batadv_dat_purge(bat_priv, batadv_dat_to_purge);204batadv_dat_start_timer(bat_priv);205}206207/**208* batadv_compare_dat() - comparing function used in the local DAT hash table209* @node: node in the local table210* @data2: second object to compare the node to211*212* Return: true if the two entries are the same, false otherwise.213*/214static bool batadv_compare_dat(const struct hlist_node *node, const void *data2)215{216const void *data1 = container_of(node, struct batadv_dat_entry,217hash_entry);218219return memcmp(data1, data2, sizeof(__be32)) == 0;220}221222/**223* batadv_arp_hw_src() - extract the hw_src field from an ARP packet224* @skb: ARP packet225* @hdr_size: size of the possible header before the ARP packet226*227* Return: the value of the hw_src field in the ARP packet.228*/229static u8 *batadv_arp_hw_src(struct sk_buff *skb, int hdr_size)230{231u8 *addr;232233addr = (u8 *)(skb->data + hdr_size);234addr += ETH_HLEN + sizeof(struct arphdr);235236return addr;237}238239/**240* batadv_arp_ip_src() - extract the ip_src field from an ARP packet241* @skb: ARP packet242* @hdr_size: size of the possible header before the ARP packet243*244* Return: the value of the ip_src field in the ARP packet.245*/246static __be32 batadv_arp_ip_src(struct sk_buff *skb, int hdr_size)247{248return *(__force __be32 *)(batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN);249}250251/**252* batadv_arp_hw_dst() - extract the hw_dst field from an ARP packet253* @skb: ARP packet254* @hdr_size: size of the possible header before the ARP packet255*256* Return: the value of the hw_dst field in the ARP packet.257*/258static u8 *batadv_arp_hw_dst(struct sk_buff *skb, int hdr_size)259{260return batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN + 4;261}262263/**264* batadv_arp_ip_dst() - extract the ip_dst field from an ARP packet265* @skb: ARP packet266* @hdr_size: size of the possible header before the ARP packet267*268* Return: the value of the ip_dst field in the ARP packet.269*/270static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size)271{272u8 *dst = batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN * 2 + 4;273274return *(__force __be32 *)dst;275}276277/**278* batadv_hash_dat() - compute the hash value for an IP address279* @data: data to hash280* @size: size of the hash table281*282* Return: the selected index in the hash table for the given data.283*/284static u32 batadv_hash_dat(const void *data, u32 size)285{286u32 hash = 0;287const struct batadv_dat_entry *dat = data;288const unsigned char *key;289__be16 vid;290u32 i;291292key = (__force const unsigned char *)&dat->ip;293for (i = 0; i < sizeof(dat->ip); i++) {294hash += key[i];295hash += (hash << 10);296hash ^= (hash >> 6);297}298299vid = htons(dat->vid);300key = (__force const unsigned char *)&vid;301for (i = 0; i < sizeof(dat->vid); i++) {302hash += key[i];303hash += (hash << 10);304hash ^= (hash >> 6);305}306307hash += (hash << 3);308hash ^= (hash >> 11);309hash += (hash << 15);310311return hash % size;312}313314/**315* batadv_dat_entry_hash_find() - look for a given dat_entry in the local hash316* table317* @bat_priv: the bat priv with all the mesh interface information318* @ip: search key319* @vid: VLAN identifier320*321* Return: the dat_entry if found, NULL otherwise.322*/323static struct batadv_dat_entry *324batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,325unsigned short vid)326{327struct hlist_head *head;328struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL;329struct batadv_hashtable *hash = bat_priv->dat.hash;330u32 index;331332if (!hash)333return NULL;334335to_find.ip = ip;336to_find.vid = vid;337338index = batadv_hash_dat(&to_find, hash->size);339head = &hash->table[index];340341rcu_read_lock();342hlist_for_each_entry_rcu(dat_entry, head, hash_entry) {343if (dat_entry->ip != ip)344continue;345346if (!kref_get_unless_zero(&dat_entry->refcount))347continue;348349dat_entry_tmp = dat_entry;350break;351}352rcu_read_unlock();353354return dat_entry_tmp;355}356357/**358* batadv_dat_entry_add() - add a new dat entry or update it if already exists359* @bat_priv: the bat priv with all the mesh interface information360* @ip: ipv4 to add/edit361* @mac_addr: mac address to assign to the given ipv4362* @vid: VLAN identifier363*/364static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,365u8 *mac_addr, unsigned short vid)366{367struct batadv_dat_entry *dat_entry;368int hash_added;369370dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid);371/* if this entry is already known, just update it */372if (dat_entry) {373if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))374ether_addr_copy(dat_entry->mac_addr, mac_addr);375dat_entry->last_update = jiffies;376batadv_dbg(BATADV_DBG_DAT, bat_priv,377"Entry updated: %pI4 %pM (vid: %d)\n",378&dat_entry->ip, dat_entry->mac_addr,379batadv_print_vid(vid));380goto out;381}382383dat_entry = kmalloc(sizeof(*dat_entry), GFP_ATOMIC);384if (!dat_entry)385goto out;386387dat_entry->ip = ip;388dat_entry->vid = vid;389ether_addr_copy(dat_entry->mac_addr, mac_addr);390dat_entry->last_update = jiffies;391kref_init(&dat_entry->refcount);392393kref_get(&dat_entry->refcount);394hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat,395batadv_hash_dat, dat_entry,396&dat_entry->hash_entry);397398if (unlikely(hash_added != 0)) {399/* remove the reference for the hash */400batadv_dat_entry_put(dat_entry);401goto out;402}403404batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n",405&dat_entry->ip, dat_entry->mac_addr, batadv_print_vid(vid));406407out:408batadv_dat_entry_put(dat_entry);409}410411#ifdef CONFIG_BATMAN_ADV_DEBUG412413/**414* batadv_dbg_arp() - print a debug message containing all the ARP packet415* details416* @bat_priv: the bat priv with all the mesh interface information417* @skb: ARP packet418* @hdr_size: size of the possible header before the ARP packet419* @msg: message to print together with the debugging information420*/421static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,422int hdr_size, char *msg)423{424struct batadv_unicast_4addr_packet *unicast_4addr_packet;425struct batadv_bcast_packet *bcast_pkt;426u8 *orig_addr;427__be32 ip_src, ip_dst;428429if (msg)430batadv_dbg(BATADV_DBG_DAT, bat_priv, "%s\n", msg);431432ip_src = batadv_arp_ip_src(skb, hdr_size);433ip_dst = batadv_arp_ip_dst(skb, hdr_size);434batadv_dbg(BATADV_DBG_DAT, bat_priv,435"ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]\n",436batadv_arp_hw_src(skb, hdr_size), &ip_src,437batadv_arp_hw_dst(skb, hdr_size), &ip_dst);438439if (hdr_size < sizeof(struct batadv_unicast_packet))440return;441442unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;443444switch (unicast_4addr_packet->u.packet_type) {445case BATADV_UNICAST:446batadv_dbg(BATADV_DBG_DAT, bat_priv,447"* encapsulated within a UNICAST packet\n");448break;449case BATADV_UNICAST_4ADDR:450batadv_dbg(BATADV_DBG_DAT, bat_priv,451"* encapsulated within a UNICAST_4ADDR packet (src: %pM)\n",452unicast_4addr_packet->src);453switch (unicast_4addr_packet->subtype) {454case BATADV_P_DAT_DHT_PUT:455batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: DAT_DHT_PUT\n");456break;457case BATADV_P_DAT_DHT_GET:458batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: DAT_DHT_GET\n");459break;460case BATADV_P_DAT_CACHE_REPLY:461batadv_dbg(BATADV_DBG_DAT, bat_priv,462"* type: DAT_CACHE_REPLY\n");463break;464case BATADV_P_DATA:465batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: DATA\n");466break;467default:468batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: Unknown (%u)!\n",469unicast_4addr_packet->u.packet_type);470}471break;472case BATADV_BCAST:473bcast_pkt = (struct batadv_bcast_packet *)unicast_4addr_packet;474orig_addr = bcast_pkt->orig;475batadv_dbg(BATADV_DBG_DAT, bat_priv,476"* encapsulated within a BCAST packet (src: %pM)\n",477orig_addr);478break;479default:480batadv_dbg(BATADV_DBG_DAT, bat_priv,481"* encapsulated within an unknown packet type (0x%x)\n",482unicast_4addr_packet->u.packet_type);483}484}485486#else487488static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,489int hdr_size, char *msg)490{491}492493#endif /* CONFIG_BATMAN_ADV_DEBUG */494495/**496* batadv_is_orig_node_eligible() - check whether a node can be a DHT candidate497* @res: the array with the already selected candidates498* @select: number of already selected candidates499* @tmp_max: address of the currently evaluated node500* @max: current round max address501* @last_max: address of the last selected candidate502* @candidate: orig_node under evaluation503* @max_orig_node: last selected candidate504*505* Return: true if the node has been elected as next candidate or false506* otherwise.507*/508static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res,509int select, batadv_dat_addr_t tmp_max,510batadv_dat_addr_t max,511batadv_dat_addr_t last_max,512struct batadv_orig_node *candidate,513struct batadv_orig_node *max_orig_node)514{515bool ret = false;516int j;517518/* check if orig node candidate is running DAT */519if (!test_bit(BATADV_ORIG_CAPA_HAS_DAT, &candidate->capabilities))520goto out;521522/* Check if this node has already been selected... */523for (j = 0; j < select; j++)524if (res[j].orig_node == candidate)525break;526/* ..and possibly skip it */527if (j < select)528goto out;529/* sanity check: has it already been selected? This should not happen */530if (tmp_max > last_max)531goto out;532/* check if during this iteration an originator with a closer dht533* address has already been found534*/535if (tmp_max < max)536goto out;537/* this is an hash collision with the temporary selected node. Choose538* the one with the lowest address539*/540if (tmp_max == max && max_orig_node &&541batadv_compare_eth(candidate->orig, max_orig_node->orig))542goto out;543544ret = true;545out:546return ret;547}548549/**550* batadv_choose_next_candidate() - select the next DHT candidate551* @bat_priv: the bat priv with all the mesh interface information552* @cands: candidates array553* @select: number of candidates already present in the array554* @ip_key: key to look up in the DHT555* @last_max: pointer where the address of the selected candidate will be saved556*/557static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,558struct batadv_dat_candidate *cands,559int select, batadv_dat_addr_t ip_key,560batadv_dat_addr_t *last_max)561{562batadv_dat_addr_t max = 0;563batadv_dat_addr_t tmp_max = 0;564struct batadv_orig_node *orig_node, *max_orig_node = NULL;565struct batadv_hashtable *hash = bat_priv->orig_hash;566struct hlist_head *head;567int i;568569/* if no node is eligible as candidate, leave the candidate type as570* NOT_FOUND571*/572cands[select].type = BATADV_DAT_CANDIDATE_NOT_FOUND;573574/* iterate over the originator list and find the node with the closest575* dat_address which has not been selected yet576*/577for (i = 0; i < hash->size; i++) {578head = &hash->table[i];579580rcu_read_lock();581hlist_for_each_entry_rcu(orig_node, head, hash_entry) {582/* the dht space is a ring using unsigned addresses */583tmp_max = BATADV_DAT_ADDR_MAX - orig_node->dat_addr +584ip_key;585586if (!batadv_is_orig_node_eligible(cands, select,587tmp_max, max,588*last_max, orig_node,589max_orig_node))590continue;591592if (!kref_get_unless_zero(&orig_node->refcount))593continue;594595max = tmp_max;596batadv_orig_node_put(max_orig_node);597max_orig_node = orig_node;598}599rcu_read_unlock();600}601if (max_orig_node) {602cands[select].type = BATADV_DAT_CANDIDATE_ORIG;603cands[select].orig_node = max_orig_node;604batadv_dbg(BATADV_DBG_DAT, bat_priv,605"dat_select_candidates() %d: selected %pM addr=%u dist=%u\n",606select, max_orig_node->orig, max_orig_node->dat_addr,607max);608}609*last_max = max;610}611612/**613* batadv_dat_select_candidates() - select the nodes which the DHT message has614* to be sent to615* @bat_priv: the bat priv with all the mesh interface information616* @ip_dst: ipv4 to look up in the DHT617* @vid: VLAN identifier618*619* An originator O is selected if and only if its DHT_ID value is one of three620* closest values (from the LEFT, with wrap around if needed) then the hash621* value of the key. ip_dst is the key.622*623* Return: the candidate array of size BATADV_DAT_CANDIDATE_NUM.624*/625static struct batadv_dat_candidate *626batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,627unsigned short vid)628{629int select;630batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key;631struct batadv_dat_candidate *res;632struct batadv_dat_entry dat;633634if (!bat_priv->orig_hash)635return NULL;636637res = kmalloc_array(BATADV_DAT_CANDIDATES_NUM, sizeof(*res),638GFP_ATOMIC);639if (!res)640return NULL;641642dat.ip = ip_dst;643dat.vid = vid;644ip_key = (batadv_dat_addr_t)batadv_hash_dat(&dat,645BATADV_DAT_ADDR_MAX);646647batadv_dbg(BATADV_DBG_DAT, bat_priv,648"%s(): IP=%pI4 hash(IP)=%u\n", __func__, &ip_dst,649ip_key);650651for (select = 0; select < BATADV_DAT_CANDIDATES_NUM; select++)652batadv_choose_next_candidate(bat_priv, res, select, ip_key,653&last_max);654655return res;656}657658/**659* batadv_dat_forward_data() - copy and send payload to the selected candidates660* @bat_priv: the bat priv with all the mesh interface information661* @skb: payload to send662* @ip: the DHT key663* @vid: VLAN identifier664* @packet_subtype: unicast4addr packet subtype to use665*666* This function copies the skb with pskb_copy() and is sent as a unicast packet667* to each of the selected candidates.668*669* Return: true if the packet is sent to at least one candidate, false670* otherwise.671*/672static bool batadv_dat_forward_data(struct batadv_priv *bat_priv,673struct sk_buff *skb, __be32 ip,674unsigned short vid, int packet_subtype)675{676int i;677bool ret = false;678int send_status;679struct batadv_neigh_node *neigh_node = NULL;680struct sk_buff *tmp_skb;681struct batadv_dat_candidate *cand;682683cand = batadv_dat_select_candidates(bat_priv, ip, vid);684if (!cand)685return ret;686687batadv_dbg(BATADV_DBG_DAT, bat_priv, "DHT_SEND for %pI4\n", &ip);688689for (i = 0; i < BATADV_DAT_CANDIDATES_NUM; i++) {690if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND)691continue;692693neigh_node = batadv_orig_router_get(cand[i].orig_node,694BATADV_IF_DEFAULT);695if (!neigh_node)696goto free_orig;697698tmp_skb = pskb_copy_for_clone(skb, GFP_ATOMIC);699if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb,700cand[i].orig_node,701packet_subtype)) {702kfree_skb(tmp_skb);703goto free_neigh;704}705706send_status = batadv_send_unicast_skb(tmp_skb, neigh_node);707if (send_status == NET_XMIT_SUCCESS) {708/* count the sent packet */709switch (packet_subtype) {710case BATADV_P_DAT_DHT_GET:711batadv_inc_counter(bat_priv,712BATADV_CNT_DAT_GET_TX);713break;714case BATADV_P_DAT_DHT_PUT:715batadv_inc_counter(bat_priv,716BATADV_CNT_DAT_PUT_TX);717break;718}719720/* packet sent to a candidate: return true */721ret = true;722}723free_neigh:724batadv_neigh_node_put(neigh_node);725free_orig:726batadv_orig_node_put(cand[i].orig_node);727}728729kfree(cand);730return ret;731}732733/**734* batadv_dat_tvlv_container_update() - update the dat tvlv container after dat735* setting change736* @bat_priv: the bat priv with all the mesh interface information737*/738static void batadv_dat_tvlv_container_update(struct batadv_priv *bat_priv)739{740char dat_mode;741742dat_mode = atomic_read(&bat_priv->distributed_arp_table);743744switch (dat_mode) {745case 0:746batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_DAT, 1);747break;748case 1:749batadv_tvlv_container_register(bat_priv, BATADV_TVLV_DAT, 1,750NULL, 0);751break;752}753}754755/**756* batadv_dat_status_update() - update the dat tvlv container after dat757* setting change758* @net_dev: the mesh interface net device759*/760void batadv_dat_status_update(struct net_device *net_dev)761{762struct batadv_priv *bat_priv = netdev_priv(net_dev);763764batadv_dat_tvlv_container_update(bat_priv);765}766767/**768* batadv_dat_tvlv_ogm_handler_v1() - process incoming dat tvlv container769* @bat_priv: the bat priv with all the mesh interface information770* @orig: the orig_node of the ogm771* @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)772* @tvlv_value: tvlv buffer containing the gateway data773* @tvlv_value_len: tvlv buffer length774*/775static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,776struct batadv_orig_node *orig,777u8 flags,778void *tvlv_value, u16 tvlv_value_len)779{780if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND)781clear_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities);782else783set_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities);784}785786/**787* batadv_dat_hash_free() - free the local DAT hash table788* @bat_priv: the bat priv with all the mesh interface information789*/790static void batadv_dat_hash_free(struct batadv_priv *bat_priv)791{792if (!bat_priv->dat.hash)793return;794795__batadv_dat_purge(bat_priv, NULL);796797batadv_hash_destroy(bat_priv->dat.hash);798799bat_priv->dat.hash = NULL;800}801802/**803* batadv_dat_init() - initialise the DAT internals804* @bat_priv: the bat priv with all the mesh interface information805*806* Return: 0 in case of success, a negative error code otherwise807*/808int batadv_dat_init(struct batadv_priv *bat_priv)809{810if (bat_priv->dat.hash)811return 0;812813bat_priv->dat.hash = batadv_hash_new(1024);814815if (!bat_priv->dat.hash)816return -ENOMEM;817818INIT_DELAYED_WORK(&bat_priv->dat.work, batadv_dat_purge);819batadv_dat_start_timer(bat_priv);820821batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1,822NULL, NULL, BATADV_TVLV_DAT, 1,823BATADV_TVLV_HANDLER_OGM_CIFNOTFND);824batadv_dat_tvlv_container_update(bat_priv);825return 0;826}827828/**829* batadv_dat_free() - free the DAT internals830* @bat_priv: the bat priv with all the mesh interface information831*/832void batadv_dat_free(struct batadv_priv *bat_priv)833{834batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_DAT, 1);835batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_DAT, 1);836837cancel_delayed_work_sync(&bat_priv->dat.work);838839batadv_dat_hash_free(bat_priv);840}841842/**843* batadv_dat_cache_dump_entry() - dump one entry of the DAT cache table to a844* netlink socket845* @msg: buffer for the message846* @portid: netlink port847* @cb: Control block containing additional options848* @dat_entry: entry to dump849*850* Return: 0 or error code.851*/852static int853batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,854struct netlink_callback *cb,855struct batadv_dat_entry *dat_entry)856{857int msecs;858void *hdr;859860hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,861&batadv_netlink_family, NLM_F_MULTI,862BATADV_CMD_GET_DAT_CACHE);863if (!hdr)864return -ENOBUFS;865866genl_dump_check_consistent(cb, hdr);867868msecs = jiffies_to_msecs(jiffies - dat_entry->last_update);869870if (nla_put_in_addr(msg, BATADV_ATTR_DAT_CACHE_IP4ADDRESS,871dat_entry->ip) ||872nla_put(msg, BATADV_ATTR_DAT_CACHE_HWADDRESS, ETH_ALEN,873dat_entry->mac_addr) ||874nla_put_u16(msg, BATADV_ATTR_DAT_CACHE_VID, dat_entry->vid) ||875nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {876genlmsg_cancel(msg, hdr);877return -EMSGSIZE;878}879880genlmsg_end(msg, hdr);881return 0;882}883884/**885* batadv_dat_cache_dump_bucket() - dump one bucket of the DAT cache table to886* a netlink socket887* @msg: buffer for the message888* @portid: netlink port889* @cb: Control block containing additional options890* @hash: hash to dump891* @bucket: bucket index to dump892* @idx_skip: How many entries to skip893*894* Return: 0 or error code.895*/896static int897batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid,898struct netlink_callback *cb,899struct batadv_hashtable *hash, unsigned int bucket,900int *idx_skip)901{902struct batadv_dat_entry *dat_entry;903int idx = 0;904905spin_lock_bh(&hash->list_locks[bucket]);906cb->seq = atomic_read(&hash->generation) << 1 | 1;907908hlist_for_each_entry(dat_entry, &hash->table[bucket], hash_entry) {909if (idx < *idx_skip)910goto skip;911912if (batadv_dat_cache_dump_entry(msg, portid, cb, dat_entry)) {913spin_unlock_bh(&hash->list_locks[bucket]);914*idx_skip = idx;915916return -EMSGSIZE;917}918919skip:920idx++;921}922spin_unlock_bh(&hash->list_locks[bucket]);923924return 0;925}926927/**928* batadv_dat_cache_dump() - dump DAT cache table to a netlink socket929* @msg: buffer for the message930* @cb: callback structure containing arguments931*932* Return: message length.933*/934int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)935{936struct batadv_hard_iface *primary_if = NULL;937int portid = NETLINK_CB(cb->skb).portid;938struct net_device *mesh_iface;939struct batadv_hashtable *hash;940struct batadv_priv *bat_priv;941int bucket = cb->args[0];942int idx = cb->args[1];943int ret = 0;944945mesh_iface = batadv_netlink_get_meshif(cb);946if (IS_ERR(mesh_iface))947return PTR_ERR(mesh_iface);948949bat_priv = netdev_priv(mesh_iface);950hash = bat_priv->dat.hash;951952primary_if = batadv_primary_if_get_selected(bat_priv);953if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {954ret = -ENOENT;955goto out;956}957958while (bucket < hash->size) {959if (batadv_dat_cache_dump_bucket(msg, portid, cb, hash, bucket,960&idx))961break;962963bucket++;964idx = 0;965}966967cb->args[0] = bucket;968cb->args[1] = idx;969970ret = msg->len;971972out:973batadv_hardif_put(primary_if);974975dev_put(mesh_iface);976977return ret;978}979980/**981* batadv_arp_get_type() - parse an ARP packet and gets the type982* @bat_priv: the bat priv with all the mesh interface information983* @skb: packet to analyse984* @hdr_size: size of the possible header before the ARP packet in the skb985*986* Return: the ARP type if the skb contains a valid ARP packet, 0 otherwise.987*/988static u16 batadv_arp_get_type(struct batadv_priv *bat_priv,989struct sk_buff *skb, int hdr_size)990{991struct arphdr *arphdr;992struct ethhdr *ethhdr;993__be32 ip_src, ip_dst;994u8 *hw_src, *hw_dst;995u16 type = 0;996997/* pull the ethernet header */998if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN)))999goto out;10001001ethhdr = (struct ethhdr *)(skb->data + hdr_size);10021003if (ethhdr->h_proto != htons(ETH_P_ARP))1004goto out;10051006/* pull the ARP payload */1007if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN +1008arp_hdr_len(skb->dev))))1009goto out;10101011arphdr = (struct arphdr *)(skb->data + hdr_size + ETH_HLEN);10121013/* check whether the ARP packet carries a valid IP information */1014if (arphdr->ar_hrd != htons(ARPHRD_ETHER))1015goto out;10161017if (arphdr->ar_pro != htons(ETH_P_IP))1018goto out;10191020if (arphdr->ar_hln != ETH_ALEN)1021goto out;10221023if (arphdr->ar_pln != 4)1024goto out;10251026/* Check for bad reply/request. If the ARP message is not sane, DAT1027* will simply ignore it1028*/1029ip_src = batadv_arp_ip_src(skb, hdr_size);1030ip_dst = batadv_arp_ip_dst(skb, hdr_size);1031if (ipv4_is_loopback(ip_src) || ipv4_is_multicast(ip_src) ||1032ipv4_is_loopback(ip_dst) || ipv4_is_multicast(ip_dst) ||1033ipv4_is_zeronet(ip_src) || ipv4_is_lbcast(ip_src) ||1034ipv4_is_zeronet(ip_dst) || ipv4_is_lbcast(ip_dst))1035goto out;10361037hw_src = batadv_arp_hw_src(skb, hdr_size);1038if (is_zero_ether_addr(hw_src) || is_multicast_ether_addr(hw_src))1039goto out;10401041/* don't care about the destination MAC address in ARP requests */1042if (arphdr->ar_op != htons(ARPOP_REQUEST)) {1043hw_dst = batadv_arp_hw_dst(skb, hdr_size);1044if (is_zero_ether_addr(hw_dst) ||1045is_multicast_ether_addr(hw_dst))1046goto out;1047}10481049type = ntohs(arphdr->ar_op);1050out:1051return type;1052}10531054/**1055* batadv_dat_get_vid() - extract the VLAN identifier from skb if any1056* @skb: the buffer containing the packet to extract the VID from1057* @hdr_size: the size of the batman-adv header encapsulating the packet1058*1059* Return: If the packet embedded in the skb is vlan tagged this function1060* returns the VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS1061* is returned.1062*/1063static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size)1064{1065unsigned short vid;10661067vid = batadv_get_vid(skb, *hdr_size);10681069/* ARP parsing functions jump forward of hdr_size + ETH_HLEN.1070* If the header contained in the packet is a VLAN one (which is longer)1071* hdr_size is updated so that the functions will still skip the1072* correct amount of bytes.1073*/1074if (vid & BATADV_VLAN_HAS_TAG)1075*hdr_size += VLAN_HLEN;10761077return vid;1078}10791080/**1081* batadv_dat_arp_create_reply() - create an ARP Reply1082* @bat_priv: the bat priv with all the mesh interface information1083* @ip_src: ARP sender IP1084* @ip_dst: ARP target IP1085* @hw_src: Ethernet source and ARP sender MAC1086* @hw_dst: Ethernet destination and ARP target MAC1087* @vid: VLAN identifier (optional, set to zero otherwise)1088*1089* Creates an ARP Reply from the given values, optionally encapsulated in a1090* VLAN header.1091*1092* Return: An skb containing an ARP Reply.1093*/1094static struct sk_buff *1095batadv_dat_arp_create_reply(struct batadv_priv *bat_priv, __be32 ip_src,1096__be32 ip_dst, u8 *hw_src, u8 *hw_dst,1097unsigned short vid)1098{1099struct sk_buff *skb;11001101skb = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_dst, bat_priv->mesh_iface,1102ip_src, hw_dst, hw_src, hw_dst);1103if (!skb)1104return NULL;11051106skb_reset_mac_header(skb);11071108if (vid & BATADV_VLAN_HAS_TAG)1109skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),1110vid & VLAN_VID_MASK);11111112return skb;1113}11141115/**1116* batadv_dat_snoop_outgoing_arp_request() - snoop the ARP request and try to1117* answer using DAT1118* @bat_priv: the bat priv with all the mesh interface information1119* @skb: packet to check1120*1121* Return: true if the message has been sent to the dht candidates, false1122* otherwise. In case of a positive return value the message has to be enqueued1123* to permit the fallback.1124*/1125bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,1126struct sk_buff *skb)1127{1128u16 type = 0;1129__be32 ip_dst, ip_src;1130u8 *hw_src;1131bool ret = false;1132struct batadv_dat_entry *dat_entry = NULL;1133struct sk_buff *skb_new;1134struct net_device *mesh_iface = bat_priv->mesh_iface;1135int hdr_size = 0;1136unsigned short vid;11371138if (!atomic_read(&bat_priv->distributed_arp_table))1139goto out;11401141vid = batadv_dat_get_vid(skb, &hdr_size);11421143type = batadv_arp_get_type(bat_priv, skb, hdr_size);1144/* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast1145* message to the selected DHT candidates1146*/1147if (type != ARPOP_REQUEST)1148goto out;11491150batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing outgoing ARP REQUEST");11511152ip_src = batadv_arp_ip_src(skb, hdr_size);1153hw_src = batadv_arp_hw_src(skb, hdr_size);1154ip_dst = batadv_arp_ip_dst(skb, hdr_size);11551156batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);11571158dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);1159if (dat_entry) {1160/* If the ARP request is destined for a local client the local1161* client will answer itself. DAT would only generate a1162* duplicate packet.1163*1164* Moreover, if the mesh-interface is enslaved into a bridge, an1165* additional DAT answer may trigger kernel warnings about1166* a packet coming from the wrong port.1167*/1168if (batadv_is_my_client(bat_priv, dat_entry->mac_addr, vid)) {1169ret = true;1170goto out;1171}11721173/* If BLA is enabled, only send ARP replies if we have claimed1174* the destination for the ARP request or if no one else of1175* the backbone gws belonging to our backbone has claimed the1176* destination.1177*/1178if (!batadv_bla_check_claim(bat_priv,1179dat_entry->mac_addr, vid)) {1180batadv_dbg(BATADV_DBG_DAT, bat_priv,1181"Device %pM claimed by another backbone gw. Don't send ARP reply!",1182dat_entry->mac_addr);1183ret = true;1184goto out;1185}11861187skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,1188dat_entry->mac_addr,1189hw_src, vid);1190if (!skb_new)1191goto out;11921193skb_new->protocol = eth_type_trans(skb_new, mesh_iface);11941195batadv_inc_counter(bat_priv, BATADV_CNT_RX);1196batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,1197skb->len + ETH_HLEN + hdr_size);11981199netif_rx(skb_new);1200batadv_dbg(BATADV_DBG_DAT, bat_priv, "ARP request replied locally\n");1201ret = true;1202} else {1203/* Send the request to the DHT */1204ret = batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,1205BATADV_P_DAT_DHT_GET);1206}1207out:1208batadv_dat_entry_put(dat_entry);1209return ret;1210}12111212/**1213* batadv_dat_snoop_incoming_arp_request() - snoop the ARP request and try to1214* answer using the local DAT storage1215* @bat_priv: the bat priv with all the mesh interface information1216* @skb: packet to check1217* @hdr_size: size of the encapsulation header1218*1219* Return: true if the request has been answered, false otherwise.1220*/1221bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,1222struct sk_buff *skb, int hdr_size)1223{1224u16 type;1225__be32 ip_src, ip_dst;1226u8 *hw_src;1227struct sk_buff *skb_new;1228struct batadv_dat_entry *dat_entry = NULL;1229bool ret = false;1230unsigned short vid;1231int err;12321233if (!atomic_read(&bat_priv->distributed_arp_table))1234goto out;12351236vid = batadv_dat_get_vid(skb, &hdr_size);12371238type = batadv_arp_get_type(bat_priv, skb, hdr_size);1239if (type != ARPOP_REQUEST)1240goto out;12411242hw_src = batadv_arp_hw_src(skb, hdr_size);1243ip_src = batadv_arp_ip_src(skb, hdr_size);1244ip_dst = batadv_arp_ip_dst(skb, hdr_size);12451246batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing incoming ARP REQUEST");12471248batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);12491250dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);1251if (!dat_entry)1252goto out;12531254skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,1255dat_entry->mac_addr, hw_src, vid);1256if (!skb_new)1257goto out;12581259/* To preserve backwards compatibility, the node has choose the outgoing1260* format based on the incoming request packet type. The assumption is1261* that a node not using the 4addr packet format doesn't support it.1262*/1263if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))1264err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new,1265BATADV_P_DAT_CACHE_REPLY,1266NULL, vid);1267else1268err = batadv_send_skb_via_tt(bat_priv, skb_new, NULL, vid);12691270if (err != NET_XMIT_DROP) {1271batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);1272ret = true;1273}1274out:1275batadv_dat_entry_put(dat_entry);1276if (ret)1277kfree_skb(skb);1278return ret;1279}12801281/**1282* batadv_dat_snoop_outgoing_arp_reply() - snoop the ARP reply and fill the DHT1283* @bat_priv: the bat priv with all the mesh interface information1284* @skb: packet to check1285*/1286void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,1287struct sk_buff *skb)1288{1289u16 type;1290__be32 ip_src, ip_dst;1291u8 *hw_src, *hw_dst;1292int hdr_size = 0;1293unsigned short vid;12941295if (!atomic_read(&bat_priv->distributed_arp_table))1296return;12971298vid = batadv_dat_get_vid(skb, &hdr_size);12991300type = batadv_arp_get_type(bat_priv, skb, hdr_size);1301if (type != ARPOP_REPLY)1302return;13031304batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing outgoing ARP REPLY");13051306hw_src = batadv_arp_hw_src(skb, hdr_size);1307ip_src = batadv_arp_ip_src(skb, hdr_size);1308hw_dst = batadv_arp_hw_dst(skb, hdr_size);1309ip_dst = batadv_arp_ip_dst(skb, hdr_size);13101311batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);1312batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);13131314/* Send the ARP reply to the candidates for both the IP addresses that1315* the node obtained from the ARP reply1316*/1317batadv_dat_forward_data(bat_priv, skb, ip_src, vid,1318BATADV_P_DAT_DHT_PUT);1319batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,1320BATADV_P_DAT_DHT_PUT);1321}13221323/**1324* batadv_dat_snoop_incoming_arp_reply() - snoop the ARP reply and fill the1325* local DAT storage only1326* @bat_priv: the bat priv with all the mesh interface information1327* @skb: packet to check1328* @hdr_size: size of the encapsulation header1329*1330* Return: true if the packet was snooped and consumed by DAT. False if the1331* packet has to be delivered to the interface1332*/1333bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,1334struct sk_buff *skb, int hdr_size)1335{1336struct batadv_dat_entry *dat_entry = NULL;1337u16 type;1338__be32 ip_src, ip_dst;1339u8 *hw_src, *hw_dst;1340bool dropped = false;1341unsigned short vid;13421343if (!atomic_read(&bat_priv->distributed_arp_table))1344goto out;13451346vid = batadv_dat_get_vid(skb, &hdr_size);13471348type = batadv_arp_get_type(bat_priv, skb, hdr_size);1349if (type != ARPOP_REPLY)1350goto out;13511352batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing incoming ARP REPLY");13531354hw_src = batadv_arp_hw_src(skb, hdr_size);1355ip_src = batadv_arp_ip_src(skb, hdr_size);1356hw_dst = batadv_arp_hw_dst(skb, hdr_size);1357ip_dst = batadv_arp_ip_dst(skb, hdr_size);13581359/* If ip_dst is already in cache and has the right mac address,1360* drop this frame if this ARP reply is destined for us because it's1361* most probably an ARP reply generated by another node of the DHT.1362* We have most probably received already a reply earlier. Delivering1363* this frame would lead to doubled receive of an ARP reply.1364*/1365dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_src, vid);1366if (dat_entry && batadv_compare_eth(hw_src, dat_entry->mac_addr)) {1367batadv_dbg(BATADV_DBG_DAT, bat_priv, "Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n",1368hw_src, &ip_src, hw_dst, &ip_dst,1369dat_entry->mac_addr, &dat_entry->ip);1370dropped = true;1371}13721373/* Update our internal cache with both the IP addresses the node got1374* within the ARP reply1375*/1376batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);1377batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);13781379if (dropped)1380goto out;13811382/* If BLA is enabled, only forward ARP replies if we have claimed the1383* source of the ARP reply or if no one else of the same backbone has1384* already claimed that client. This prevents that different gateways1385* to the same backbone all forward the ARP reply leading to multiple1386* replies in the backbone.1387*/1388if (!batadv_bla_check_claim(bat_priv, hw_src, vid)) {1389batadv_dbg(BATADV_DBG_DAT, bat_priv,1390"Device %pM claimed by another backbone gw. Drop ARP reply.\n",1391hw_src);1392dropped = true;1393goto out;1394}13951396/* if this REPLY is directed to a client of mine, let's deliver the1397* packet to the interface1398*/1399dropped = !batadv_is_my_client(bat_priv, hw_dst, vid);14001401/* if this REPLY is sent on behalf of a client of mine, let's drop the1402* packet because the client will reply by itself1403*/1404dropped |= batadv_is_my_client(bat_priv, hw_src, vid);1405out:1406if (dropped)1407kfree_skb(skb);1408batadv_dat_entry_put(dat_entry);1409/* if dropped == false -> deliver to the interface */1410return dropped;1411}14121413/**1414* batadv_dat_check_dhcp_ipudp() - check skb for IP+UDP headers valid for DHCP1415* @skb: the packet to check1416* @ip_src: a buffer to store the IPv4 source address in1417*1418* Checks whether the given skb has an IP and UDP header valid for a DHCP1419* message from a DHCP server. And if so, stores the IPv4 source address in1420* the provided buffer.1421*1422* Return: True if valid, false otherwise.1423*/1424static bool1425batadv_dat_check_dhcp_ipudp(struct sk_buff *skb, __be32 *ip_src)1426{1427unsigned int offset = skb_network_offset(skb);1428struct udphdr *udphdr, _udphdr;1429struct iphdr *iphdr, _iphdr;14301431iphdr = skb_header_pointer(skb, offset, sizeof(_iphdr), &_iphdr);1432if (!iphdr || iphdr->version != 4 || iphdr->ihl * 4 < sizeof(_iphdr))1433return false;14341435if (iphdr->protocol != IPPROTO_UDP)1436return false;14371438offset += iphdr->ihl * 4;1439skb_set_transport_header(skb, offset);14401441udphdr = skb_header_pointer(skb, offset, sizeof(_udphdr), &_udphdr);1442if (!udphdr || udphdr->source != htons(67))1443return false;14441445*ip_src = get_unaligned(&iphdr->saddr);14461447return true;1448}14491450/**1451* batadv_dat_check_dhcp() - examine packet for valid DHCP message1452* @skb: the packet to check1453* @proto: ethernet protocol hint (behind a potential vlan)1454* @ip_src: a buffer to store the IPv4 source address in1455*1456* Checks whether the given skb is a valid DHCP packet. And if so, stores the1457* IPv4 source address in the provided buffer.1458*1459* Caller needs to ensure that the skb network header is set correctly.1460*1461* Return: If skb is a valid DHCP packet, then returns its op code1462* (e.g. BOOTREPLY vs. BOOTREQUEST). Otherwise returns -EINVAL.1463*/1464static int1465batadv_dat_check_dhcp(struct sk_buff *skb, __be16 proto, __be32 *ip_src)1466{1467__be32 *magic, _magic;1468unsigned int offset;1469struct {1470__u8 op;1471__u8 htype;1472__u8 hlen;1473__u8 hops;1474} *dhcp_h, _dhcp_h;14751476if (proto != htons(ETH_P_IP))1477return -EINVAL;14781479if (!batadv_dat_check_dhcp_ipudp(skb, ip_src))1480return -EINVAL;14811482offset = skb_transport_offset(skb) + sizeof(struct udphdr);1483if (skb->len < offset + sizeof(struct batadv_dhcp_packet))1484return -EINVAL;14851486dhcp_h = skb_header_pointer(skb, offset, sizeof(_dhcp_h), &_dhcp_h);1487if (!dhcp_h || dhcp_h->htype != BATADV_HTYPE_ETHERNET ||1488dhcp_h->hlen != ETH_ALEN)1489return -EINVAL;14901491offset += offsetof(struct batadv_dhcp_packet, magic);14921493magic = skb_header_pointer(skb, offset, sizeof(_magic), &_magic);1494if (!magic || get_unaligned(magic) != htonl(BATADV_DHCP_MAGIC))1495return -EINVAL;14961497return dhcp_h->op;1498}14991500/**1501* batadv_dat_get_dhcp_message_type() - get message type of a DHCP packet1502* @skb: the DHCP packet to parse1503*1504* Iterates over the DHCP options of the given DHCP packet to find a1505* DHCP Message Type option and parse it.1506*1507* Caller needs to ensure that the given skb is a valid DHCP packet and1508* that the skb transport header is set correctly.1509*1510* Return: The found DHCP message type value, if found. -EINVAL otherwise.1511*/1512static int batadv_dat_get_dhcp_message_type(struct sk_buff *skb)1513{1514unsigned int offset = skb_transport_offset(skb) + sizeof(struct udphdr);1515u8 *type, _type;1516struct {1517u8 type;1518u8 len;1519} *tl, _tl;15201521offset += sizeof(struct batadv_dhcp_packet);15221523while ((tl = skb_header_pointer(skb, offset, sizeof(_tl), &_tl))) {1524if (tl->type == BATADV_DHCP_OPT_MSG_TYPE)1525break;15261527if (tl->type == BATADV_DHCP_OPT_END)1528break;15291530if (tl->type == BATADV_DHCP_OPT_PAD)1531offset++;1532else1533offset += tl->len + sizeof(_tl);1534}15351536/* Option Overload Code not supported */1537if (!tl || tl->type != BATADV_DHCP_OPT_MSG_TYPE ||1538tl->len != sizeof(_type))1539return -EINVAL;15401541offset += sizeof(_tl);15421543type = skb_header_pointer(skb, offset, sizeof(_type), &_type);1544if (!type)1545return -EINVAL;15461547return *type;1548}15491550/**1551* batadv_dat_dhcp_get_yiaddr() - get yiaddr from a DHCP packet1552* @skb: the DHCP packet to parse1553* @buf: a buffer to store the yiaddr in1554*1555* Caller needs to ensure that the given skb is a valid DHCP packet and1556* that the skb transport header is set correctly.1557*1558* Return: True on success, false otherwise.1559*/1560static bool batadv_dat_dhcp_get_yiaddr(struct sk_buff *skb, __be32 *buf)1561{1562unsigned int offset = skb_transport_offset(skb) + sizeof(struct udphdr);1563__be32 *yiaddr;15641565offset += offsetof(struct batadv_dhcp_packet, yiaddr);1566yiaddr = skb_header_pointer(skb, offset, BATADV_DHCP_YIADDR_LEN, buf);15671568if (!yiaddr)1569return false;15701571if (yiaddr != buf)1572*buf = get_unaligned(yiaddr);15731574return true;1575}15761577/**1578* batadv_dat_get_dhcp_chaddr() - get chaddr from a DHCP packet1579* @skb: the DHCP packet to parse1580* @buf: a buffer to store the chaddr in1581*1582* Caller needs to ensure that the given skb is a valid DHCP packet and1583* that the skb transport header is set correctly.1584*1585* Return: True on success, false otherwise1586*/1587static bool batadv_dat_get_dhcp_chaddr(struct sk_buff *skb, u8 *buf)1588{1589unsigned int offset = skb_transport_offset(skb) + sizeof(struct udphdr);1590u8 *chaddr;15911592offset += offsetof(struct batadv_dhcp_packet, chaddr);1593chaddr = skb_header_pointer(skb, offset, BATADV_DHCP_CHADDR_LEN, buf);15941595if (!chaddr)1596return false;15971598if (chaddr != buf)1599memcpy(buf, chaddr, BATADV_DHCP_CHADDR_LEN);16001601return true;1602}16031604/**1605* batadv_dat_put_dhcp() - puts addresses from a DHCP packet into the DHT and1606* DAT cache1607* @bat_priv: the bat priv with all the mesh interface information1608* @chaddr: the DHCP client MAC address1609* @yiaddr: the DHCP client IP address1610* @hw_dst: the DHCP server MAC address1611* @ip_dst: the DHCP server IP address1612* @vid: VLAN identifier1613*1614* Adds given MAC/IP pairs to the local DAT cache and propagates them further1615* into the DHT.1616*1617* For the DHT propagation, client MAC + IP will appear as the ARP Reply1618* transmitter (and hw_dst/ip_dst as the target).1619*/1620static void batadv_dat_put_dhcp(struct batadv_priv *bat_priv, u8 *chaddr,1621__be32 yiaddr, u8 *hw_dst, __be32 ip_dst,1622unsigned short vid)1623{1624struct sk_buff *skb;16251626skb = batadv_dat_arp_create_reply(bat_priv, yiaddr, ip_dst, chaddr,1627hw_dst, vid);1628if (!skb)1629return;16301631skb_set_network_header(skb, ETH_HLEN);16321633batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);1634batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);16351636batadv_dat_forward_data(bat_priv, skb, yiaddr, vid,1637BATADV_P_DAT_DHT_PUT);1638batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,1639BATADV_P_DAT_DHT_PUT);16401641consume_skb(skb);16421643batadv_dbg(BATADV_DBG_DAT, bat_priv,1644"Snooped from outgoing DHCPACK (server address): %pI4, %pM (vid: %i)\n",1645&ip_dst, hw_dst, batadv_print_vid(vid));1646batadv_dbg(BATADV_DBG_DAT, bat_priv,1647"Snooped from outgoing DHCPACK (client address): %pI4, %pM (vid: %i)\n",1648&yiaddr, chaddr, batadv_print_vid(vid));1649}16501651/**1652* batadv_dat_check_dhcp_ack() - examine packet for valid DHCP message1653* @skb: the packet to check1654* @proto: ethernet protocol hint (behind a potential vlan)1655* @ip_src: a buffer to store the IPv4 source address in1656* @chaddr: a buffer to store the DHCP Client Hardware Address in1657* @yiaddr: a buffer to store the DHCP Your IP Address in1658*1659* Checks whether the given skb is a valid DHCPACK. And if so, stores the1660* IPv4 server source address (ip_src), client MAC address (chaddr) and client1661* IPv4 address (yiaddr) in the provided buffers.1662*1663* Caller needs to ensure that the skb network header is set correctly.1664*1665* Return: True if the skb is a valid DHCPACK. False otherwise.1666*/1667static bool1668batadv_dat_check_dhcp_ack(struct sk_buff *skb, __be16 proto, __be32 *ip_src,1669u8 *chaddr, __be32 *yiaddr)1670{1671int type;16721673type = batadv_dat_check_dhcp(skb, proto, ip_src);1674if (type != BATADV_BOOTREPLY)1675return false;16761677type = batadv_dat_get_dhcp_message_type(skb);1678if (type != BATADV_DHCPACK)1679return false;16801681if (!batadv_dat_dhcp_get_yiaddr(skb, yiaddr))1682return false;16831684if (!batadv_dat_get_dhcp_chaddr(skb, chaddr))1685return false;16861687return true;1688}16891690/**1691* batadv_dat_snoop_outgoing_dhcp_ack() - snoop DHCPACK and fill DAT with it1692* @bat_priv: the bat priv with all the mesh interface information1693* @skb: the packet to snoop1694* @proto: ethernet protocol hint (behind a potential vlan)1695* @vid: VLAN identifier1696*1697* This function first checks whether the given skb is a valid DHCPACK. If1698* so then its source MAC and IP as well as its DHCP Client Hardware Address1699* field and DHCP Your IP Address field are added to the local DAT cache and1700* propagated into the DHT.1701*1702* Caller needs to ensure that the skb mac and network headers are set1703* correctly.1704*/1705void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv,1706struct sk_buff *skb,1707__be16 proto,1708unsigned short vid)1709{1710u8 chaddr[BATADV_DHCP_CHADDR_LEN];1711__be32 ip_src, yiaddr;17121713if (!atomic_read(&bat_priv->distributed_arp_table))1714return;17151716if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr))1717return;17181719batadv_dat_put_dhcp(bat_priv, chaddr, yiaddr, eth_hdr(skb)->h_source,1720ip_src, vid);1721}17221723/**1724* batadv_dat_snoop_incoming_dhcp_ack() - snoop DHCPACK and fill DAT cache1725* @bat_priv: the bat priv with all the mesh interface information1726* @skb: the packet to snoop1727* @hdr_size: header size, up to the tail of the batman-adv header1728*1729* This function first checks whether the given skb is a valid DHCPACK. If1730* so then its source MAC and IP as well as its DHCP Client Hardware Address1731* field and DHCP Your IP Address field are added to the local DAT cache.1732*/1733void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,1734struct sk_buff *skb, int hdr_size)1735{1736u8 chaddr[BATADV_DHCP_CHADDR_LEN];1737struct ethhdr *ethhdr;1738__be32 ip_src, yiaddr;1739unsigned short vid;1740__be16 proto;1741u8 *hw_src;17421743if (!atomic_read(&bat_priv->distributed_arp_table))1744return;17451746if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN)))1747return;17481749ethhdr = (struct ethhdr *)(skb->data + hdr_size);1750skb_set_network_header(skb, hdr_size + ETH_HLEN);1751proto = ethhdr->h_proto;17521753if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr))1754return;17551756hw_src = ethhdr->h_source;1757vid = batadv_dat_get_vid(skb, &hdr_size);17581759batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);1760batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);17611762batadv_dbg(BATADV_DBG_DAT, bat_priv,1763"Snooped from incoming DHCPACK (server address): %pI4, %pM (vid: %i)\n",1764&ip_src, hw_src, batadv_print_vid(vid));1765batadv_dbg(BATADV_DBG_DAT, bat_priv,1766"Snooped from incoming DHCPACK (client address): %pI4, %pM (vid: %i)\n",1767&yiaddr, chaddr, batadv_print_vid(vid));1768}17691770/**1771* batadv_dat_drop_broadcast_packet() - check if an ARP request has to be1772* dropped (because the node has already obtained the reply via DAT) or not1773* @bat_priv: the bat priv with all the mesh interface information1774* @forw_packet: the broadcast packet1775*1776* Return: true if the node can drop the packet, false otherwise.1777*/1778bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,1779struct batadv_forw_packet *forw_packet)1780{1781u16 type;1782__be32 ip_dst;1783struct batadv_dat_entry *dat_entry = NULL;1784bool ret = false;1785int hdr_size = sizeof(struct batadv_bcast_packet);1786unsigned short vid;17871788if (!atomic_read(&bat_priv->distributed_arp_table))1789goto out;17901791/* If this packet is an ARP_REQUEST and the node already has the1792* information that it is going to ask, then the packet can be dropped1793*/1794if (batadv_forw_packet_is_rebroadcast(forw_packet))1795goto out;17961797vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size);17981799type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size);1800if (type != ARPOP_REQUEST)1801goto out;18021803ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size);1804dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);1805/* check if the node already got this entry */1806if (!dat_entry) {1807batadv_dbg(BATADV_DBG_DAT, bat_priv,1808"ARP Request for %pI4: fallback\n", &ip_dst);1809goto out;1810}18111812batadv_dbg(BATADV_DBG_DAT, bat_priv,1813"ARP Request for %pI4: fallback prevented\n", &ip_dst);1814ret = true;18151816out:1817batadv_dat_entry_put(dat_entry);1818return ret;1819}182018211822