18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (C) 2007-2020 B.A.T.M.A.N. contributors: 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Marek Lindner, Simon Wunderlich 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "bat_iv_ogm.h" 88c2ecf20Sopenharmony_ci#include "main.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/atomic.h> 118c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 128c2ecf20Sopenharmony_ci#include <linux/bitops.h> 138c2ecf20Sopenharmony_ci#include <linux/bug.h> 148c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h> 158c2ecf20Sopenharmony_ci#include <linux/cache.h> 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/gfp.h> 198c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 228c2ecf20Sopenharmony_ci#include <linux/kernel.h> 238c2ecf20Sopenharmony_ci#include <linux/kref.h> 248c2ecf20Sopenharmony_ci#include <linux/list.h> 258c2ecf20Sopenharmony_ci#include <linux/lockdep.h> 268c2ecf20Sopenharmony_ci#include <linux/mutex.h> 278c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 288c2ecf20Sopenharmony_ci#include <linux/netlink.h> 298c2ecf20Sopenharmony_ci#include <linux/pkt_sched.h> 308c2ecf20Sopenharmony_ci#include <linux/prandom.h> 318c2ecf20Sopenharmony_ci#include <linux/printk.h> 328c2ecf20Sopenharmony_ci#include <linux/random.h> 338c2ecf20Sopenharmony_ci#include <linux/rculist.h> 348c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 358c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 368c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 398c2ecf20Sopenharmony_ci#include <linux/stddef.h> 408c2ecf20Sopenharmony_ci#include <linux/string.h> 418c2ecf20Sopenharmony_ci#include <linux/types.h> 428c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 438c2ecf20Sopenharmony_ci#include <net/genetlink.h> 448c2ecf20Sopenharmony_ci#include <net/netlink.h> 458c2ecf20Sopenharmony_ci#include <uapi/linux/batadv_packet.h> 468c2ecf20Sopenharmony_ci#include <uapi/linux/batman_adv.h> 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#include "bat_algo.h" 498c2ecf20Sopenharmony_ci#include "bitarray.h" 508c2ecf20Sopenharmony_ci#include "gateway_client.h" 518c2ecf20Sopenharmony_ci#include "hard-interface.h" 528c2ecf20Sopenharmony_ci#include "hash.h" 538c2ecf20Sopenharmony_ci#include "log.h" 548c2ecf20Sopenharmony_ci#include "netlink.h" 558c2ecf20Sopenharmony_ci#include "network-coding.h" 568c2ecf20Sopenharmony_ci#include "originator.h" 578c2ecf20Sopenharmony_ci#include "routing.h" 588c2ecf20Sopenharmony_ci#include "send.h" 598c2ecf20Sopenharmony_ci#include "translation-table.h" 608c2ecf20Sopenharmony_ci#include "tvlv.h" 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * enum batadv_dup_status - duplicate status 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cienum batadv_dup_status { 688c2ecf20Sopenharmony_ci /** @BATADV_NO_DUP: the packet is no duplicate */ 698c2ecf20Sopenharmony_ci BATADV_NO_DUP = 0, 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /** 728c2ecf20Sopenharmony_ci * @BATADV_ORIG_DUP: OGM is a duplicate in the originator (but not for 738c2ecf20Sopenharmony_ci * the neighbor) 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci BATADV_ORIG_DUP, 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /** @BATADV_NEIGH_DUP: OGM is a duplicate for the neighbor */ 788c2ecf20Sopenharmony_ci BATADV_NEIGH_DUP, 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /** 818c2ecf20Sopenharmony_ci * @BATADV_PROTECTED: originator is currently protected (after reboot) 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci BATADV_PROTECTED, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/** 878c2ecf20Sopenharmony_ci * batadv_ring_buffer_set() - update the ring buffer with the given value 888c2ecf20Sopenharmony_ci * @lq_recv: pointer to the ring buffer 898c2ecf20Sopenharmony_ci * @lq_index: index to store the value at 908c2ecf20Sopenharmony_ci * @value: value to store in the ring buffer 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic void batadv_ring_buffer_set(u8 lq_recv[], u8 *lq_index, u8 value) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci lq_recv[*lq_index] = value; 958c2ecf20Sopenharmony_ci *lq_index = (*lq_index + 1) % BATADV_TQ_GLOBAL_WINDOW_SIZE; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * batadv_ring_buffer_avg() - compute the average of all non-zero values stored 1008c2ecf20Sopenharmony_ci * in the given ring buffer 1018c2ecf20Sopenharmony_ci * @lq_recv: pointer to the ring buffer 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Return: computed average value. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic u8 batadv_ring_buffer_avg(const u8 lq_recv[]) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci const u8 *ptr; 1088c2ecf20Sopenharmony_ci u16 count = 0; 1098c2ecf20Sopenharmony_ci u16 i = 0; 1108c2ecf20Sopenharmony_ci u16 sum = 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci ptr = lq_recv; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci while (i < BATADV_TQ_GLOBAL_WINDOW_SIZE) { 1158c2ecf20Sopenharmony_ci if (*ptr != 0) { 1168c2ecf20Sopenharmony_ci count++; 1178c2ecf20Sopenharmony_ci sum += *ptr; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci i++; 1218c2ecf20Sopenharmony_ci ptr++; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (count == 0) 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return (u8)(sum / count); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/** 1318c2ecf20Sopenharmony_ci * batadv_iv_ogm_orig_get() - retrieve or create (if does not exist) an 1328c2ecf20Sopenharmony_ci * originator 1338c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 1348c2ecf20Sopenharmony_ci * @addr: mac address of the originator 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * Return: the originator object corresponding to the passed mac address or NULL 1378c2ecf20Sopenharmony_ci * on failure. 1388c2ecf20Sopenharmony_ci * If the object does not exist, it is created and initialised. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_cistatic struct batadv_orig_node * 1418c2ecf20Sopenharmony_cibatadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node; 1448c2ecf20Sopenharmony_ci int hash_added; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci orig_node = batadv_orig_hash_find(bat_priv, addr); 1478c2ecf20Sopenharmony_ci if (orig_node) 1488c2ecf20Sopenharmony_ci return orig_node; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci orig_node = batadv_orig_node_new(bat_priv, addr); 1518c2ecf20Sopenharmony_ci if (!orig_node) 1528c2ecf20Sopenharmony_ci return NULL; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci spin_lock_init(&orig_node->bat_iv.ogm_cnt_lock); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci kref_get(&orig_node->refcount); 1578c2ecf20Sopenharmony_ci hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig, 1588c2ecf20Sopenharmony_ci batadv_choose_orig, orig_node, 1598c2ecf20Sopenharmony_ci &orig_node->hash_entry); 1608c2ecf20Sopenharmony_ci if (hash_added != 0) 1618c2ecf20Sopenharmony_ci goto free_orig_node_hash; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return orig_node; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cifree_orig_node_hash: 1668c2ecf20Sopenharmony_ci /* reference for batadv_hash_add */ 1678c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_node); 1688c2ecf20Sopenharmony_ci /* reference from batadv_orig_node_new */ 1698c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_node); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return NULL; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic struct batadv_neigh_node * 1758c2ecf20Sopenharmony_cibatadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, 1768c2ecf20Sopenharmony_ci const u8 *neigh_addr, 1778c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node, 1788c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_neigh) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci neigh_node = batadv_neigh_node_get_or_create(orig_node, 1838c2ecf20Sopenharmony_ci hard_iface, neigh_addr); 1848c2ecf20Sopenharmony_ci if (!neigh_node) 1858c2ecf20Sopenharmony_ci goto out; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci neigh_node->orig_node = orig_neigh; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ciout: 1908c2ecf20Sopenharmony_ci return neigh_node; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet; 1968c2ecf20Sopenharmony_ci unsigned char *ogm_buff; 1978c2ecf20Sopenharmony_ci u32 random_seqno; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* randomize initial seqno to avoid collision */ 2028c2ecf20Sopenharmony_ci get_random_bytes(&random_seqno, sizeof(random_seqno)); 2038c2ecf20Sopenharmony_ci atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN; 2068c2ecf20Sopenharmony_ci ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC); 2078c2ecf20Sopenharmony_ci if (!ogm_buff) { 2088c2ecf20Sopenharmony_ci mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); 2098c2ecf20Sopenharmony_ci return -ENOMEM; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci hard_iface->bat_iv.ogm_buff = ogm_buff; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff; 2158c2ecf20Sopenharmony_ci batadv_ogm_packet->packet_type = BATADV_IV_OGM; 2168c2ecf20Sopenharmony_ci batadv_ogm_packet->version = BATADV_COMPAT_VERSION; 2178c2ecf20Sopenharmony_ci batadv_ogm_packet->ttl = 2; 2188c2ecf20Sopenharmony_ci batadv_ogm_packet->flags = BATADV_NO_FLAGS; 2198c2ecf20Sopenharmony_ci batadv_ogm_packet->reserved = 0; 2208c2ecf20Sopenharmony_ci batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci kfree(hard_iface->bat_iv.ogm_buff); 2328c2ecf20Sopenharmony_ci hard_iface->bat_iv.ogm_buff = NULL; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet; 2408c2ecf20Sopenharmony_ci void *ogm_buff; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ogm_buff = hard_iface->bat_iv.ogm_buff; 2458c2ecf20Sopenharmony_ci if (!ogm_buff) 2468c2ecf20Sopenharmony_ci goto unlock; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci batadv_ogm_packet = ogm_buff; 2498c2ecf20Sopenharmony_ci ether_addr_copy(batadv_ogm_packet->orig, 2508c2ecf20Sopenharmony_ci hard_iface->net_dev->dev_addr); 2518c2ecf20Sopenharmony_ci ether_addr_copy(batadv_ogm_packet->prev_sender, 2528c2ecf20Sopenharmony_ci hard_iface->net_dev->dev_addr); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciunlock: 2558c2ecf20Sopenharmony_ci mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void 2598c2ecf20Sopenharmony_cibatadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet; 2628c2ecf20Sopenharmony_ci void *ogm_buff; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ogm_buff = hard_iface->bat_iv.ogm_buff; 2678c2ecf20Sopenharmony_ci if (!ogm_buff) 2688c2ecf20Sopenharmony_ci goto unlock; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci batadv_ogm_packet = ogm_buff; 2718c2ecf20Sopenharmony_ci batadv_ogm_packet->ttl = BATADV_TTL; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ciunlock: 2748c2ecf20Sopenharmony_ci mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/* when do we schedule our own ogm to be sent */ 2788c2ecf20Sopenharmony_cistatic unsigned long 2798c2ecf20Sopenharmony_cibatadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci unsigned int msecs; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER; 2848c2ecf20Sopenharmony_ci msecs += prandom_u32_max(2 * BATADV_JITTER); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return jiffies + msecs_to_jiffies(msecs); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci/* when do we schedule a ogm packet to be sent */ 2908c2ecf20Sopenharmony_cistatic unsigned long batadv_iv_ogm_fwd_send_time(void) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci return jiffies + msecs_to_jiffies(prandom_u32_max(BATADV_JITTER / 2)); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* apply hop penalty for a normal link */ 2968c2ecf20Sopenharmony_cistatic u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci int hop_penalty = atomic_read(&bat_priv->hop_penalty); 2998c2ecf20Sopenharmony_ci int new_tq; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci new_tq = tq * (BATADV_TQ_MAX_VALUE - hop_penalty); 3028c2ecf20Sopenharmony_ci new_tq /= BATADV_TQ_MAX_VALUE; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return new_tq; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/** 3088c2ecf20Sopenharmony_ci * batadv_iv_ogm_aggr_packet() - checks if there is another OGM attached 3098c2ecf20Sopenharmony_ci * @buff_pos: current position in the skb 3108c2ecf20Sopenharmony_ci * @packet_len: total length of the skb 3118c2ecf20Sopenharmony_ci * @ogm_packet: potential OGM in buffer 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Return: true if there is enough space for another OGM, false otherwise. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_cistatic bool 3168c2ecf20Sopenharmony_cibatadv_iv_ogm_aggr_packet(int buff_pos, int packet_len, 3178c2ecf20Sopenharmony_ci const struct batadv_ogm_packet *ogm_packet) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int next_buff_pos = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* check if there is enough space for the header */ 3228c2ecf20Sopenharmony_ci next_buff_pos += buff_pos + sizeof(*ogm_packet); 3238c2ecf20Sopenharmony_ci if (next_buff_pos > packet_len) 3248c2ecf20Sopenharmony_ci return false; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* check if there is enough space for the optional TVLV */ 3278c2ecf20Sopenharmony_ci next_buff_pos += ntohs(ogm_packet->tvlv_len); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return (next_buff_pos <= packet_len) && 3308c2ecf20Sopenharmony_ci (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* send a batman ogm to a given interface */ 3348c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, 3358c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); 3388c2ecf20Sopenharmony_ci const char *fwd_str; 3398c2ecf20Sopenharmony_ci u8 packet_num; 3408c2ecf20Sopenharmony_ci s16 buff_pos; 3418c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet; 3428c2ecf20Sopenharmony_ci struct sk_buff *skb; 3438c2ecf20Sopenharmony_ci u8 *packet_pos; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_ACTIVE) 3468c2ecf20Sopenharmony_ci return; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci packet_num = 0; 3498c2ecf20Sopenharmony_ci buff_pos = 0; 3508c2ecf20Sopenharmony_ci packet_pos = forw_packet->skb->data; 3518c2ecf20Sopenharmony_ci batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* adjust all flags and log packets */ 3548c2ecf20Sopenharmony_ci while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len, 3558c2ecf20Sopenharmony_ci batadv_ogm_packet)) { 3568c2ecf20Sopenharmony_ci /* we might have aggregated direct link packets with an 3578c2ecf20Sopenharmony_ci * ordinary base packet 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci if (forw_packet->direct_link_flags & BIT(packet_num) && 3608c2ecf20Sopenharmony_ci forw_packet->if_incoming == hard_iface) 3618c2ecf20Sopenharmony_ci batadv_ogm_packet->flags |= BATADV_DIRECTLINK; 3628c2ecf20Sopenharmony_ci else 3638c2ecf20Sopenharmony_ci batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (packet_num > 0 || !forw_packet->own) 3668c2ecf20Sopenharmony_ci fwd_str = "Forwarding"; 3678c2ecf20Sopenharmony_ci else 3688c2ecf20Sopenharmony_ci fwd_str = "Sending own"; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 3718c2ecf20Sopenharmony_ci "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s) on interface %s [%pM]\n", 3728c2ecf20Sopenharmony_ci fwd_str, (packet_num > 0 ? "aggregated " : ""), 3738c2ecf20Sopenharmony_ci batadv_ogm_packet->orig, 3748c2ecf20Sopenharmony_ci ntohl(batadv_ogm_packet->seqno), 3758c2ecf20Sopenharmony_ci batadv_ogm_packet->tq, batadv_ogm_packet->ttl, 3768c2ecf20Sopenharmony_ci ((batadv_ogm_packet->flags & BATADV_DIRECTLINK) ? 3778c2ecf20Sopenharmony_ci "on" : "off"), 3788c2ecf20Sopenharmony_ci hard_iface->net_dev->name, 3798c2ecf20Sopenharmony_ci hard_iface->net_dev->dev_addr); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci buff_pos += BATADV_OGM_HLEN; 3828c2ecf20Sopenharmony_ci buff_pos += ntohs(batadv_ogm_packet->tvlv_len); 3838c2ecf20Sopenharmony_ci packet_num++; 3848c2ecf20Sopenharmony_ci packet_pos = forw_packet->skb->data + buff_pos; 3858c2ecf20Sopenharmony_ci batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* create clone because function is called more than once */ 3898c2ecf20Sopenharmony_ci skb = skb_clone(forw_packet->skb, GFP_ATOMIC); 3908c2ecf20Sopenharmony_ci if (skb) { 3918c2ecf20Sopenharmony_ci batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX); 3928c2ecf20Sopenharmony_ci batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES, 3938c2ecf20Sopenharmony_ci skb->len + ETH_HLEN); 3948c2ecf20Sopenharmony_ci batadv_send_broadcast_skb(skb, hard_iface); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci/* send a batman ogm packet */ 3998c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct net_device *soft_iface; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (!forw_packet->if_incoming) { 4048c2ecf20Sopenharmony_ci pr_err("Error - can't forward packet: incoming iface not specified\n"); 4058c2ecf20Sopenharmony_ci return; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci soft_iface = forw_packet->if_incoming->soft_iface; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (WARN_ON(!forw_packet->if_outgoing)) 4118c2ecf20Sopenharmony_ci return; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (forw_packet->if_outgoing->soft_iface != soft_iface) { 4148c2ecf20Sopenharmony_ci pr_warn("%s: soft interface switch for queued OGM\n", __func__); 4158c2ecf20Sopenharmony_ci return; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE) 4198c2ecf20Sopenharmony_ci return; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* only for one specific outgoing interface */ 4228c2ecf20Sopenharmony_ci batadv_iv_ogm_send_to_if(forw_packet, forw_packet->if_outgoing); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci/** 4268c2ecf20Sopenharmony_ci * batadv_iv_ogm_can_aggregate() - find out if an OGM can be aggregated on an 4278c2ecf20Sopenharmony_ci * existing forward packet 4288c2ecf20Sopenharmony_ci * @new_bat_ogm_packet: OGM packet to be aggregated 4298c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 4308c2ecf20Sopenharmony_ci * @packet_len: (total) length of the OGM 4318c2ecf20Sopenharmony_ci * @send_time: timestamp (jiffies) when the packet is to be sent 4328c2ecf20Sopenharmony_ci * @directlink: true if this is a direct link packet 4338c2ecf20Sopenharmony_ci * @if_incoming: interface where the packet was received 4348c2ecf20Sopenharmony_ci * @if_outgoing: interface for which the retransmission should be considered 4358c2ecf20Sopenharmony_ci * @forw_packet: the forwarded packet which should be checked 4368c2ecf20Sopenharmony_ci * 4378c2ecf20Sopenharmony_ci * Return: true if new_packet can be aggregated with forw_packet 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_cistatic bool 4408c2ecf20Sopenharmony_cibatadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet, 4418c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv, 4428c2ecf20Sopenharmony_ci int packet_len, unsigned long send_time, 4438c2ecf20Sopenharmony_ci bool directlink, 4448c2ecf20Sopenharmony_ci const struct batadv_hard_iface *if_incoming, 4458c2ecf20Sopenharmony_ci const struct batadv_hard_iface *if_outgoing, 4468c2ecf20Sopenharmony_ci const struct batadv_forw_packet *forw_packet) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet; 4498c2ecf20Sopenharmony_ci int aggregated_bytes = forw_packet->packet_len + packet_len; 4508c2ecf20Sopenharmony_ci struct batadv_hard_iface *primary_if = NULL; 4518c2ecf20Sopenharmony_ci bool res = false; 4528c2ecf20Sopenharmony_ci unsigned long aggregation_end_time; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci batadv_ogm_packet = (struct batadv_ogm_packet *)forw_packet->skb->data; 4558c2ecf20Sopenharmony_ci aggregation_end_time = send_time; 4568c2ecf20Sopenharmony_ci aggregation_end_time += msecs_to_jiffies(BATADV_MAX_AGGREGATION_MS); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* we can aggregate the current packet to this aggregated packet 4598c2ecf20Sopenharmony_ci * if: 4608c2ecf20Sopenharmony_ci * 4618c2ecf20Sopenharmony_ci * - the send time is within our MAX_AGGREGATION_MS time 4628c2ecf20Sopenharmony_ci * - the resulting packet wont be bigger than 4638c2ecf20Sopenharmony_ci * MAX_AGGREGATION_BYTES 4648c2ecf20Sopenharmony_ci * otherwise aggregation is not possible 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci if (!time_before(send_time, forw_packet->send_time) || 4678c2ecf20Sopenharmony_ci !time_after_eq(aggregation_end_time, forw_packet->send_time)) 4688c2ecf20Sopenharmony_ci return false; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (aggregated_bytes > BATADV_MAX_AGGREGATION_BYTES) 4718c2ecf20Sopenharmony_ci return false; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* packet is not leaving on the same interface. */ 4748c2ecf20Sopenharmony_ci if (forw_packet->if_outgoing != if_outgoing) 4758c2ecf20Sopenharmony_ci return false; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* check aggregation compatibility 4788c2ecf20Sopenharmony_ci * -> direct link packets are broadcasted on 4798c2ecf20Sopenharmony_ci * their interface only 4808c2ecf20Sopenharmony_ci * -> aggregate packet if the current packet is 4818c2ecf20Sopenharmony_ci * a "global" packet as well as the base 4828c2ecf20Sopenharmony_ci * packet 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 4858c2ecf20Sopenharmony_ci if (!primary_if) 4868c2ecf20Sopenharmony_ci return false; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* packets without direct link flag and high TTL 4898c2ecf20Sopenharmony_ci * are flooded through the net 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ci if (!directlink && 4928c2ecf20Sopenharmony_ci !(batadv_ogm_packet->flags & BATADV_DIRECTLINK) && 4938c2ecf20Sopenharmony_ci batadv_ogm_packet->ttl != 1 && 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* own packets originating non-primary 4968c2ecf20Sopenharmony_ci * interfaces leave only that interface 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci (!forw_packet->own || 4998c2ecf20Sopenharmony_ci forw_packet->if_incoming == primary_if)) { 5008c2ecf20Sopenharmony_ci res = true; 5018c2ecf20Sopenharmony_ci goto out; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* if the incoming packet is sent via this one 5058c2ecf20Sopenharmony_ci * interface only - we still can aggregate 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ci if (directlink && 5088c2ecf20Sopenharmony_ci new_bat_ogm_packet->ttl == 1 && 5098c2ecf20Sopenharmony_ci forw_packet->if_incoming == if_incoming && 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* packets from direct neighbors or 5128c2ecf20Sopenharmony_ci * own secondary interface packets 5138c2ecf20Sopenharmony_ci * (= secondary interface packets in general) 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci (batadv_ogm_packet->flags & BATADV_DIRECTLINK || 5168c2ecf20Sopenharmony_ci (forw_packet->own && 5178c2ecf20Sopenharmony_ci forw_packet->if_incoming != primary_if))) { 5188c2ecf20Sopenharmony_ci res = true; 5198c2ecf20Sopenharmony_ci goto out; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ciout: 5238c2ecf20Sopenharmony_ci if (primary_if) 5248c2ecf20Sopenharmony_ci batadv_hardif_put(primary_if); 5258c2ecf20Sopenharmony_ci return res; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci/** 5298c2ecf20Sopenharmony_ci * batadv_iv_ogm_aggregate_new() - create a new aggregated packet and add this 5308c2ecf20Sopenharmony_ci * packet to it. 5318c2ecf20Sopenharmony_ci * @packet_buff: pointer to the OGM 5328c2ecf20Sopenharmony_ci * @packet_len: (total) length of the OGM 5338c2ecf20Sopenharmony_ci * @send_time: timestamp (jiffies) when the packet is to be sent 5348c2ecf20Sopenharmony_ci * @direct_link: whether this OGM has direct link status 5358c2ecf20Sopenharmony_ci * @if_incoming: interface where the packet was received 5368c2ecf20Sopenharmony_ci * @if_outgoing: interface for which the retransmission should be considered 5378c2ecf20Sopenharmony_ci * @own_packet: true if it is a self-generated ogm 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, 5408c2ecf20Sopenharmony_ci int packet_len, unsigned long send_time, 5418c2ecf20Sopenharmony_ci bool direct_link, 5428c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming, 5438c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing, 5448c2ecf20Sopenharmony_ci int own_packet) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 5478c2ecf20Sopenharmony_ci struct batadv_forw_packet *forw_packet_aggr; 5488c2ecf20Sopenharmony_ci struct sk_buff *skb; 5498c2ecf20Sopenharmony_ci unsigned char *skb_buff; 5508c2ecf20Sopenharmony_ci unsigned int skb_size; 5518c2ecf20Sopenharmony_ci atomic_t *queue_left = own_packet ? NULL : &bat_priv->batman_queue_left; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->aggregated_ogms) && 5548c2ecf20Sopenharmony_ci packet_len < BATADV_MAX_AGGREGATION_BYTES) 5558c2ecf20Sopenharmony_ci skb_size = BATADV_MAX_AGGREGATION_BYTES; 5568c2ecf20Sopenharmony_ci else 5578c2ecf20Sopenharmony_ci skb_size = packet_len; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci skb_size += ETH_HLEN; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci skb = netdev_alloc_skb_ip_align(NULL, skb_size); 5628c2ecf20Sopenharmony_ci if (!skb) 5638c2ecf20Sopenharmony_ci return; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing, 5668c2ecf20Sopenharmony_ci queue_left, bat_priv, skb); 5678c2ecf20Sopenharmony_ci if (!forw_packet_aggr) { 5688c2ecf20Sopenharmony_ci kfree_skb(skb); 5698c2ecf20Sopenharmony_ci return; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci forw_packet_aggr->skb->priority = TC_PRIO_CONTROL; 5738c2ecf20Sopenharmony_ci skb_reserve(forw_packet_aggr->skb, ETH_HLEN); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci skb_buff = skb_put(forw_packet_aggr->skb, packet_len); 5768c2ecf20Sopenharmony_ci forw_packet_aggr->packet_len = packet_len; 5778c2ecf20Sopenharmony_ci memcpy(skb_buff, packet_buff, packet_len); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci forw_packet_aggr->own = own_packet; 5808c2ecf20Sopenharmony_ci forw_packet_aggr->direct_link_flags = BATADV_NO_FLAGS; 5818c2ecf20Sopenharmony_ci forw_packet_aggr->send_time = send_time; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* save packet direct link flag status */ 5848c2ecf20Sopenharmony_ci if (direct_link) 5858c2ecf20Sopenharmony_ci forw_packet_aggr->direct_link_flags |= 1; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, 5888c2ecf20Sopenharmony_ci batadv_iv_send_outstanding_bat_ogm_packet); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci batadv_forw_packet_ogmv1_queue(bat_priv, forw_packet_aggr, send_time); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/* aggregate a new packet into the existing ogm packet */ 5948c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr, 5958c2ecf20Sopenharmony_ci const unsigned char *packet_buff, 5968c2ecf20Sopenharmony_ci int packet_len, bool direct_link) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci unsigned long new_direct_link_flag; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci skb_put_data(forw_packet_aggr->skb, packet_buff, packet_len); 6018c2ecf20Sopenharmony_ci forw_packet_aggr->packet_len += packet_len; 6028c2ecf20Sopenharmony_ci forw_packet_aggr->num_packets++; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* save packet direct link flag status */ 6058c2ecf20Sopenharmony_ci if (direct_link) { 6068c2ecf20Sopenharmony_ci new_direct_link_flag = BIT(forw_packet_aggr->num_packets); 6078c2ecf20Sopenharmony_ci forw_packet_aggr->direct_link_flags |= new_direct_link_flag; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/** 6128c2ecf20Sopenharmony_ci * batadv_iv_ogm_queue_add() - queue up an OGM for transmission 6138c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 6148c2ecf20Sopenharmony_ci * @packet_buff: pointer to the OGM 6158c2ecf20Sopenharmony_ci * @packet_len: (total) length of the OGM 6168c2ecf20Sopenharmony_ci * @if_incoming: interface where the packet was received 6178c2ecf20Sopenharmony_ci * @if_outgoing: interface for which the retransmission should be considered 6188c2ecf20Sopenharmony_ci * @own_packet: true if it is a self-generated ogm 6198c2ecf20Sopenharmony_ci * @send_time: timestamp (jiffies) when the packet is to be sent 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, 6228c2ecf20Sopenharmony_ci unsigned char *packet_buff, 6238c2ecf20Sopenharmony_ci int packet_len, 6248c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming, 6258c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing, 6268c2ecf20Sopenharmony_ci int own_packet, unsigned long send_time) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci /* _aggr -> pointer to the packet we want to aggregate with 6298c2ecf20Sopenharmony_ci * _pos -> pointer to the position in the queue 6308c2ecf20Sopenharmony_ci */ 6318c2ecf20Sopenharmony_ci struct batadv_forw_packet *forw_packet_aggr = NULL; 6328c2ecf20Sopenharmony_ci struct batadv_forw_packet *forw_packet_pos = NULL; 6338c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet; 6348c2ecf20Sopenharmony_ci bool direct_link; 6358c2ecf20Sopenharmony_ci unsigned long max_aggregation_jiffies; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff; 6388c2ecf20Sopenharmony_ci direct_link = !!(batadv_ogm_packet->flags & BATADV_DIRECTLINK); 6398c2ecf20Sopenharmony_ci max_aggregation_jiffies = msecs_to_jiffies(BATADV_MAX_AGGREGATION_MS); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* find position for the packet in the forward queue */ 6428c2ecf20Sopenharmony_ci spin_lock_bh(&bat_priv->forw_bat_list_lock); 6438c2ecf20Sopenharmony_ci /* own packets are not to be aggregated */ 6448c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->aggregated_ogms) && !own_packet) { 6458c2ecf20Sopenharmony_ci hlist_for_each_entry(forw_packet_pos, 6468c2ecf20Sopenharmony_ci &bat_priv->forw_bat_list, list) { 6478c2ecf20Sopenharmony_ci if (batadv_iv_ogm_can_aggregate(batadv_ogm_packet, 6488c2ecf20Sopenharmony_ci bat_priv, packet_len, 6498c2ecf20Sopenharmony_ci send_time, direct_link, 6508c2ecf20Sopenharmony_ci if_incoming, 6518c2ecf20Sopenharmony_ci if_outgoing, 6528c2ecf20Sopenharmony_ci forw_packet_pos)) { 6538c2ecf20Sopenharmony_ci forw_packet_aggr = forw_packet_pos; 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* nothing to aggregate with - either aggregation disabled or no 6608c2ecf20Sopenharmony_ci * suitable aggregation packet found 6618c2ecf20Sopenharmony_ci */ 6628c2ecf20Sopenharmony_ci if (!forw_packet_aggr) { 6638c2ecf20Sopenharmony_ci /* the following section can run without the lock */ 6648c2ecf20Sopenharmony_ci spin_unlock_bh(&bat_priv->forw_bat_list_lock); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* if we could not aggregate this packet with one of the others 6678c2ecf20Sopenharmony_ci * we hold it back for a while, so that it might be aggregated 6688c2ecf20Sopenharmony_ci * later on 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci if (!own_packet && atomic_read(&bat_priv->aggregated_ogms)) 6718c2ecf20Sopenharmony_ci send_time += max_aggregation_jiffies; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci batadv_iv_ogm_aggregate_new(packet_buff, packet_len, 6748c2ecf20Sopenharmony_ci send_time, direct_link, 6758c2ecf20Sopenharmony_ci if_incoming, if_outgoing, 6768c2ecf20Sopenharmony_ci own_packet); 6778c2ecf20Sopenharmony_ci } else { 6788c2ecf20Sopenharmony_ci batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff, 6798c2ecf20Sopenharmony_ci packet_len, direct_link); 6808c2ecf20Sopenharmony_ci spin_unlock_bh(&bat_priv->forw_bat_list_lock); 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, 6858c2ecf20Sopenharmony_ci const struct ethhdr *ethhdr, 6868c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet, 6878c2ecf20Sopenharmony_ci bool is_single_hop_neigh, 6888c2ecf20Sopenharmony_ci bool is_from_best_next_hop, 6898c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming, 6908c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 6938c2ecf20Sopenharmony_ci u16 tvlv_len; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (batadv_ogm_packet->ttl <= 1) { 6968c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n"); 6978c2ecf20Sopenharmony_ci return; 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (!is_from_best_next_hop) { 7018c2ecf20Sopenharmony_ci /* Mark the forwarded packet when it is not coming from our 7028c2ecf20Sopenharmony_ci * best next hop. We still need to forward the packet for our 7038c2ecf20Sopenharmony_ci * neighbor link quality detection to work in case the packet 7048c2ecf20Sopenharmony_ci * originated from a single hop neighbor. Otherwise we can 7058c2ecf20Sopenharmony_ci * simply drop the ogm. 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_ci if (is_single_hop_neigh) 7088c2ecf20Sopenharmony_ci batadv_ogm_packet->flags |= BATADV_NOT_BEST_NEXT_HOP; 7098c2ecf20Sopenharmony_ci else 7108c2ecf20Sopenharmony_ci return; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci tvlv_len = ntohs(batadv_ogm_packet->tvlv_len); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci batadv_ogm_packet->ttl--; 7168c2ecf20Sopenharmony_ci ether_addr_copy(batadv_ogm_packet->prev_sender, ethhdr->h_source); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* apply hop penalty */ 7198c2ecf20Sopenharmony_ci batadv_ogm_packet->tq = batadv_hop_penalty(batadv_ogm_packet->tq, 7208c2ecf20Sopenharmony_ci bat_priv); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 7238c2ecf20Sopenharmony_ci "Forwarding packet: tq: %i, ttl: %i\n", 7248c2ecf20Sopenharmony_ci batadv_ogm_packet->tq, batadv_ogm_packet->ttl); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (is_single_hop_neigh) 7278c2ecf20Sopenharmony_ci batadv_ogm_packet->flags |= BATADV_DIRECTLINK; 7288c2ecf20Sopenharmony_ci else 7298c2ecf20Sopenharmony_ci batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet, 7328c2ecf20Sopenharmony_ci BATADV_OGM_HLEN + tvlv_len, 7338c2ecf20Sopenharmony_ci if_incoming, if_outgoing, 0, 7348c2ecf20Sopenharmony_ci batadv_iv_ogm_fwd_send_time()); 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci/** 7388c2ecf20Sopenharmony_ci * batadv_iv_ogm_slide_own_bcast_window() - bitshift own OGM broadcast windows 7398c2ecf20Sopenharmony_ci * for the given interface 7408c2ecf20Sopenharmony_ci * @hard_iface: the interface for which the windows have to be shifted 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_cistatic void 7438c2ecf20Sopenharmony_cibatadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); 7468c2ecf20Sopenharmony_ci struct batadv_hashtable *hash = bat_priv->orig_hash; 7478c2ecf20Sopenharmony_ci struct hlist_head *head; 7488c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node; 7498c2ecf20Sopenharmony_ci struct batadv_orig_ifinfo *orig_ifinfo; 7508c2ecf20Sopenharmony_ci unsigned long *word; 7518c2ecf20Sopenharmony_ci u32 i; 7528c2ecf20Sopenharmony_ci u8 *w; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci for (i = 0; i < hash->size; i++) { 7558c2ecf20Sopenharmony_ci head = &hash->table[i]; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci rcu_read_lock(); 7588c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(orig_node, head, hash_entry) { 7598c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(orig_ifinfo, 7608c2ecf20Sopenharmony_ci &orig_node->ifinfo_list, 7618c2ecf20Sopenharmony_ci list) { 7628c2ecf20Sopenharmony_ci if (orig_ifinfo->if_outgoing != hard_iface) 7638c2ecf20Sopenharmony_ci continue; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); 7668c2ecf20Sopenharmony_ci word = orig_ifinfo->bat_iv.bcast_own; 7678c2ecf20Sopenharmony_ci batadv_bit_get_packet(bat_priv, word, 1, 0); 7688c2ecf20Sopenharmony_ci w = &orig_ifinfo->bat_iv.bcast_own_sum; 7698c2ecf20Sopenharmony_ci *w = bitmap_weight(word, 7708c2ecf20Sopenharmony_ci BATADV_TQ_LOCAL_WINDOW_SIZE); 7718c2ecf20Sopenharmony_ci spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci rcu_read_unlock(); 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci/** 7798c2ecf20Sopenharmony_ci * batadv_iv_ogm_schedule_buff() - schedule submission of hardif ogm buffer 7808c2ecf20Sopenharmony_ci * @hard_iface: interface whose ogm buffer should be transmitted 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); 7858c2ecf20Sopenharmony_ci unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff; 7868c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet; 7878c2ecf20Sopenharmony_ci struct batadv_hard_iface *primary_if, *tmp_hard_iface; 7888c2ecf20Sopenharmony_ci int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; 7898c2ecf20Sopenharmony_ci u32 seqno; 7908c2ecf20Sopenharmony_ci u16 tvlv_len = 0; 7918c2ecf20Sopenharmony_ci unsigned long send_time; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* interface already disabled by batadv_iv_ogm_iface_disable */ 7968c2ecf20Sopenharmony_ci if (!*ogm_buff) 7978c2ecf20Sopenharmony_ci return; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* the interface gets activated here to avoid race conditions between 8008c2ecf20Sopenharmony_ci * the moment of activating the interface in 8018c2ecf20Sopenharmony_ci * hardif_activate_interface() where the originator mac is set and 8028c2ecf20Sopenharmony_ci * outdated packets (especially uninitialized mac addresses) in the 8038c2ecf20Sopenharmony_ci * packet queue 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_ci if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED) 8068c2ecf20Sopenharmony_ci hard_iface->if_status = BATADV_IF_ACTIVE; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (hard_iface == primary_if) { 8118c2ecf20Sopenharmony_ci /* tt changes have to be committed before the tvlv data is 8128c2ecf20Sopenharmony_ci * appended as it may alter the tt tvlv container 8138c2ecf20Sopenharmony_ci */ 8148c2ecf20Sopenharmony_ci batadv_tt_local_commit_changes(bat_priv); 8158c2ecf20Sopenharmony_ci tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, 8168c2ecf20Sopenharmony_ci ogm_buff_len, 8178c2ecf20Sopenharmony_ci BATADV_OGM_HLEN); 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff); 8218c2ecf20Sopenharmony_ci batadv_ogm_packet->tvlv_len = htons(tvlv_len); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* change sequence number to network order */ 8248c2ecf20Sopenharmony_ci seqno = (u32)atomic_read(&hard_iface->bat_iv.ogm_seqno); 8258c2ecf20Sopenharmony_ci batadv_ogm_packet->seqno = htonl(seqno); 8268c2ecf20Sopenharmony_ci atomic_inc(&hard_iface->bat_iv.ogm_seqno); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci batadv_iv_ogm_slide_own_bcast_window(hard_iface); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci send_time = batadv_iv_ogm_emit_send_time(bat_priv); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (hard_iface != primary_if) { 8338c2ecf20Sopenharmony_ci /* OGMs from secondary interfaces are only scheduled on their 8348c2ecf20Sopenharmony_ci * respective interfaces. 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len, 8378c2ecf20Sopenharmony_ci hard_iface, hard_iface, 1, send_time); 8388c2ecf20Sopenharmony_ci goto out; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* OGMs from primary interfaces are scheduled on all 8428c2ecf20Sopenharmony_ci * interfaces. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci rcu_read_lock(); 8458c2ecf20Sopenharmony_ci list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) { 8468c2ecf20Sopenharmony_ci if (tmp_hard_iface->soft_iface != hard_iface->soft_iface) 8478c2ecf20Sopenharmony_ci continue; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&tmp_hard_iface->refcount)) 8508c2ecf20Sopenharmony_ci continue; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, 8538c2ecf20Sopenharmony_ci *ogm_buff_len, hard_iface, 8548c2ecf20Sopenharmony_ci tmp_hard_iface, 1, send_time); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci batadv_hardif_put(tmp_hard_iface); 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci rcu_read_unlock(); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ciout: 8618c2ecf20Sopenharmony_ci if (primary_if) 8628c2ecf20Sopenharmony_ci batadv_hardif_put(primary_if); 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci if (hard_iface->if_status == BATADV_IF_NOT_IN_USE || 8688c2ecf20Sopenharmony_ci hard_iface->if_status == BATADV_IF_TO_BE_REMOVED) 8698c2ecf20Sopenharmony_ci return; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); 8728c2ecf20Sopenharmony_ci batadv_iv_ogm_schedule_buff(hard_iface); 8738c2ecf20Sopenharmony_ci mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci/** 8778c2ecf20Sopenharmony_ci * batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over interface 8788c2ecf20Sopenharmony_ci * @orig_node: originator which reproadcasted the OGMs directly 8798c2ecf20Sopenharmony_ci * @if_outgoing: interface which transmitted the original OGM and received the 8808c2ecf20Sopenharmony_ci * direct rebroadcast 8818c2ecf20Sopenharmony_ci * 8828c2ecf20Sopenharmony_ci * Return: Number of replied (rebroadcasted) OGMs which were transmitted by 8838c2ecf20Sopenharmony_ci * an originator and directly (without intermediate hop) received by a specific 8848c2ecf20Sopenharmony_ci * interface 8858c2ecf20Sopenharmony_ci */ 8868c2ecf20Sopenharmony_cistatic u8 batadv_iv_orig_ifinfo_sum(struct batadv_orig_node *orig_node, 8878c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct batadv_orig_ifinfo *orig_ifinfo; 8908c2ecf20Sopenharmony_ci u8 sum; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing); 8938c2ecf20Sopenharmony_ci if (!orig_ifinfo) 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); 8978c2ecf20Sopenharmony_ci sum = orig_ifinfo->bat_iv.bcast_own_sum; 8988c2ecf20Sopenharmony_ci spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci batadv_orig_ifinfo_put(orig_ifinfo); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return sum; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci/** 9068c2ecf20Sopenharmony_ci * batadv_iv_ogm_orig_update() - use OGM to update corresponding data in an 9078c2ecf20Sopenharmony_ci * originator 9088c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 9098c2ecf20Sopenharmony_ci * @orig_node: the orig node who originally emitted the ogm packet 9108c2ecf20Sopenharmony_ci * @orig_ifinfo: ifinfo for the outgoing interface of the orig_node 9118c2ecf20Sopenharmony_ci * @ethhdr: Ethernet header of the OGM 9128c2ecf20Sopenharmony_ci * @batadv_ogm_packet: the ogm packet 9138c2ecf20Sopenharmony_ci * @if_incoming: interface where the packet was received 9148c2ecf20Sopenharmony_ci * @if_outgoing: interface for which the retransmission should be considered 9158c2ecf20Sopenharmony_ci * @dup_status: the duplicate status of this ogm packet. 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_cistatic void 9188c2ecf20Sopenharmony_cibatadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, 9198c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node, 9208c2ecf20Sopenharmony_ci struct batadv_orig_ifinfo *orig_ifinfo, 9218c2ecf20Sopenharmony_ci const struct ethhdr *ethhdr, 9228c2ecf20Sopenharmony_ci const struct batadv_ogm_packet *batadv_ogm_packet, 9238c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming, 9248c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing, 9258c2ecf20Sopenharmony_ci enum batadv_dup_status dup_status) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; 9288c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *router_ifinfo = NULL; 9298c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node = NULL; 9308c2ecf20Sopenharmony_ci struct batadv_neigh_node *tmp_neigh_node = NULL; 9318c2ecf20Sopenharmony_ci struct batadv_neigh_node *router = NULL; 9328c2ecf20Sopenharmony_ci u8 sum_orig, sum_neigh; 9338c2ecf20Sopenharmony_ci u8 *neigh_addr; 9348c2ecf20Sopenharmony_ci u8 tq_avg; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 9378c2ecf20Sopenharmony_ci "%s(): Searching and updating originator entry of received packet\n", 9388c2ecf20Sopenharmony_ci __func__); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci rcu_read_lock(); 9418c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(tmp_neigh_node, 9428c2ecf20Sopenharmony_ci &orig_node->neigh_list, list) { 9438c2ecf20Sopenharmony_ci neigh_addr = tmp_neigh_node->addr; 9448c2ecf20Sopenharmony_ci if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && 9458c2ecf20Sopenharmony_ci tmp_neigh_node->if_incoming == if_incoming && 9468c2ecf20Sopenharmony_ci kref_get_unless_zero(&tmp_neigh_node->refcount)) { 9478c2ecf20Sopenharmony_ci if (WARN(neigh_node, "too many matching neigh_nodes")) 9488c2ecf20Sopenharmony_ci batadv_neigh_node_put(neigh_node); 9498c2ecf20Sopenharmony_ci neigh_node = tmp_neigh_node; 9508c2ecf20Sopenharmony_ci continue; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (dup_status != BATADV_NO_DUP) 9548c2ecf20Sopenharmony_ci continue; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* only update the entry for this outgoing interface */ 9578c2ecf20Sopenharmony_ci neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node, 9588c2ecf20Sopenharmony_ci if_outgoing); 9598c2ecf20Sopenharmony_ci if (!neigh_ifinfo) 9608c2ecf20Sopenharmony_ci continue; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci spin_lock_bh(&tmp_neigh_node->ifinfo_lock); 9638c2ecf20Sopenharmony_ci batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv, 9648c2ecf20Sopenharmony_ci &neigh_ifinfo->bat_iv.tq_index, 0); 9658c2ecf20Sopenharmony_ci tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv); 9668c2ecf20Sopenharmony_ci neigh_ifinfo->bat_iv.tq_avg = tq_avg; 9678c2ecf20Sopenharmony_ci spin_unlock_bh(&tmp_neigh_node->ifinfo_lock); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(neigh_ifinfo); 9708c2ecf20Sopenharmony_ci neigh_ifinfo = NULL; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (!neigh_node) { 9748c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_tmp; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci orig_tmp = batadv_iv_ogm_orig_get(bat_priv, ethhdr->h_source); 9778c2ecf20Sopenharmony_ci if (!orig_tmp) 9788c2ecf20Sopenharmony_ci goto unlock; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci neigh_node = batadv_iv_ogm_neigh_new(if_incoming, 9818c2ecf20Sopenharmony_ci ethhdr->h_source, 9828c2ecf20Sopenharmony_ci orig_node, orig_tmp); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_tmp); 9858c2ecf20Sopenharmony_ci if (!neigh_node) 9868c2ecf20Sopenharmony_ci goto unlock; 9878c2ecf20Sopenharmony_ci } else { 9888c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 9898c2ecf20Sopenharmony_ci "Updating existing last-hop neighbor of originator\n"); 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci rcu_read_unlock(); 9938c2ecf20Sopenharmony_ci neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); 9948c2ecf20Sopenharmony_ci if (!neigh_ifinfo) 9958c2ecf20Sopenharmony_ci goto out; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci neigh_node->last_seen = jiffies; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci spin_lock_bh(&neigh_node->ifinfo_lock); 10008c2ecf20Sopenharmony_ci batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv, 10018c2ecf20Sopenharmony_ci &neigh_ifinfo->bat_iv.tq_index, 10028c2ecf20Sopenharmony_ci batadv_ogm_packet->tq); 10038c2ecf20Sopenharmony_ci tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv); 10048c2ecf20Sopenharmony_ci neigh_ifinfo->bat_iv.tq_avg = tq_avg; 10058c2ecf20Sopenharmony_ci spin_unlock_bh(&neigh_node->ifinfo_lock); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (dup_status == BATADV_NO_DUP) { 10088c2ecf20Sopenharmony_ci orig_ifinfo->last_ttl = batadv_ogm_packet->ttl; 10098c2ecf20Sopenharmony_ci neigh_ifinfo->last_ttl = batadv_ogm_packet->ttl; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* if this neighbor already is our next hop there is nothing 10138c2ecf20Sopenharmony_ci * to change 10148c2ecf20Sopenharmony_ci */ 10158c2ecf20Sopenharmony_ci router = batadv_orig_router_get(orig_node, if_outgoing); 10168c2ecf20Sopenharmony_ci if (router == neigh_node) 10178c2ecf20Sopenharmony_ci goto out; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (router) { 10208c2ecf20Sopenharmony_ci router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); 10218c2ecf20Sopenharmony_ci if (!router_ifinfo) 10228c2ecf20Sopenharmony_ci goto out; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* if this neighbor does not offer a better TQ we won't 10258c2ecf20Sopenharmony_ci * consider it 10268c2ecf20Sopenharmony_ci */ 10278c2ecf20Sopenharmony_ci if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg) 10288c2ecf20Sopenharmony_ci goto out; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* if the TQ is the same and the link not more symmetric we 10328c2ecf20Sopenharmony_ci * won't consider it either 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_ci if (router_ifinfo && 10358c2ecf20Sopenharmony_ci neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg) { 10368c2ecf20Sopenharmony_ci sum_orig = batadv_iv_orig_ifinfo_sum(router->orig_node, 10378c2ecf20Sopenharmony_ci router->if_incoming); 10388c2ecf20Sopenharmony_ci sum_neigh = batadv_iv_orig_ifinfo_sum(neigh_node->orig_node, 10398c2ecf20Sopenharmony_ci neigh_node->if_incoming); 10408c2ecf20Sopenharmony_ci if (sum_orig >= sum_neigh) 10418c2ecf20Sopenharmony_ci goto out; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node); 10458c2ecf20Sopenharmony_ci goto out; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ciunlock: 10488c2ecf20Sopenharmony_ci rcu_read_unlock(); 10498c2ecf20Sopenharmony_ciout: 10508c2ecf20Sopenharmony_ci if (neigh_node) 10518c2ecf20Sopenharmony_ci batadv_neigh_node_put(neigh_node); 10528c2ecf20Sopenharmony_ci if (router) 10538c2ecf20Sopenharmony_ci batadv_neigh_node_put(router); 10548c2ecf20Sopenharmony_ci if (neigh_ifinfo) 10558c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(neigh_ifinfo); 10568c2ecf20Sopenharmony_ci if (router_ifinfo) 10578c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(router_ifinfo); 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci/** 10618c2ecf20Sopenharmony_ci * batadv_iv_ogm_calc_tq() - calculate tq for current received ogm packet 10628c2ecf20Sopenharmony_ci * @orig_node: the orig node who originally emitted the ogm packet 10638c2ecf20Sopenharmony_ci * @orig_neigh_node: the orig node struct of the neighbor who sent the packet 10648c2ecf20Sopenharmony_ci * @batadv_ogm_packet: the ogm packet 10658c2ecf20Sopenharmony_ci * @if_incoming: interface where the packet was received 10668c2ecf20Sopenharmony_ci * @if_outgoing: interface for which the retransmission should be considered 10678c2ecf20Sopenharmony_ci * 10688c2ecf20Sopenharmony_ci * Return: true if the link can be considered bidirectional, false otherwise 10698c2ecf20Sopenharmony_ci */ 10708c2ecf20Sopenharmony_cistatic bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, 10718c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_neigh_node, 10728c2ecf20Sopenharmony_ci struct batadv_ogm_packet *batadv_ogm_packet, 10738c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming, 10748c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 10778c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node; 10788c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *neigh_ifinfo; 10798c2ecf20Sopenharmony_ci u8 total_count; 10808c2ecf20Sopenharmony_ci u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; 10818c2ecf20Sopenharmony_ci unsigned int tq_iface_hop_penalty = BATADV_TQ_MAX_VALUE; 10828c2ecf20Sopenharmony_ci unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; 10838c2ecf20Sopenharmony_ci unsigned int tq_asym_penalty, inv_asym_penalty; 10848c2ecf20Sopenharmony_ci unsigned int combined_tq; 10858c2ecf20Sopenharmony_ci bool ret = false; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* find corresponding one hop neighbor */ 10888c2ecf20Sopenharmony_ci rcu_read_lock(); 10898c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(tmp_neigh_node, 10908c2ecf20Sopenharmony_ci &orig_neigh_node->neigh_list, list) { 10918c2ecf20Sopenharmony_ci if (!batadv_compare_eth(tmp_neigh_node->addr, 10928c2ecf20Sopenharmony_ci orig_neigh_node->orig)) 10938c2ecf20Sopenharmony_ci continue; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (tmp_neigh_node->if_incoming != if_incoming) 10968c2ecf20Sopenharmony_ci continue; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&tmp_neigh_node->refcount)) 10998c2ecf20Sopenharmony_ci continue; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci neigh_node = tmp_neigh_node; 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci rcu_read_unlock(); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (!neigh_node) 11078c2ecf20Sopenharmony_ci neigh_node = batadv_iv_ogm_neigh_new(if_incoming, 11088c2ecf20Sopenharmony_ci orig_neigh_node->orig, 11098c2ecf20Sopenharmony_ci orig_neigh_node, 11108c2ecf20Sopenharmony_ci orig_neigh_node); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (!neigh_node) 11138c2ecf20Sopenharmony_ci goto out; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* if orig_node is direct neighbor update neigh_node last_seen */ 11168c2ecf20Sopenharmony_ci if (orig_node == orig_neigh_node) 11178c2ecf20Sopenharmony_ci neigh_node->last_seen = jiffies; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci orig_node->last_seen = jiffies; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* find packet count of corresponding one hop neighbor */ 11228c2ecf20Sopenharmony_ci orig_eq_count = batadv_iv_orig_ifinfo_sum(orig_neigh_node, if_incoming); 11238c2ecf20Sopenharmony_ci neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); 11248c2ecf20Sopenharmony_ci if (neigh_ifinfo) { 11258c2ecf20Sopenharmony_ci neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count; 11268c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(neigh_ifinfo); 11278c2ecf20Sopenharmony_ci } else { 11288c2ecf20Sopenharmony_ci neigh_rq_count = 0; 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* pay attention to not get a value bigger than 100 % */ 11328c2ecf20Sopenharmony_ci if (orig_eq_count > neigh_rq_count) 11338c2ecf20Sopenharmony_ci total_count = neigh_rq_count; 11348c2ecf20Sopenharmony_ci else 11358c2ecf20Sopenharmony_ci total_count = orig_eq_count; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci /* if we have too few packets (too less data) we set tq_own to zero 11388c2ecf20Sopenharmony_ci * if we receive too few packets it is not considered bidirectional 11398c2ecf20Sopenharmony_ci */ 11408c2ecf20Sopenharmony_ci if (total_count < BATADV_TQ_LOCAL_BIDRECT_SEND_MINIMUM || 11418c2ecf20Sopenharmony_ci neigh_rq_count < BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM) 11428c2ecf20Sopenharmony_ci tq_own = 0; 11438c2ecf20Sopenharmony_ci else 11448c2ecf20Sopenharmony_ci /* neigh_node->real_packet_count is never zero as we 11458c2ecf20Sopenharmony_ci * only purge old information when getting new 11468c2ecf20Sopenharmony_ci * information 11478c2ecf20Sopenharmony_ci */ 11488c2ecf20Sopenharmony_ci tq_own = (BATADV_TQ_MAX_VALUE * total_count) / neigh_rq_count; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does 11518c2ecf20Sopenharmony_ci * affect the nearly-symmetric links only a little, but 11528c2ecf20Sopenharmony_ci * punishes asymmetric links more. This will give a value 11538c2ecf20Sopenharmony_ci * between 0 and TQ_MAX_VALUE 11548c2ecf20Sopenharmony_ci */ 11558c2ecf20Sopenharmony_ci neigh_rq_inv = BATADV_TQ_LOCAL_WINDOW_SIZE - neigh_rq_count; 11568c2ecf20Sopenharmony_ci neigh_rq_inv_cube = neigh_rq_inv * neigh_rq_inv * neigh_rq_inv; 11578c2ecf20Sopenharmony_ci neigh_rq_max_cube = BATADV_TQ_LOCAL_WINDOW_SIZE * 11588c2ecf20Sopenharmony_ci BATADV_TQ_LOCAL_WINDOW_SIZE * 11598c2ecf20Sopenharmony_ci BATADV_TQ_LOCAL_WINDOW_SIZE; 11608c2ecf20Sopenharmony_ci inv_asym_penalty = BATADV_TQ_MAX_VALUE * neigh_rq_inv_cube; 11618c2ecf20Sopenharmony_ci inv_asym_penalty /= neigh_rq_max_cube; 11628c2ecf20Sopenharmony_ci tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty; 11638c2ecf20Sopenharmony_ci tq_iface_hop_penalty -= atomic_read(&if_incoming->hop_penalty); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* penalize if the OGM is forwarded on the same interface. WiFi 11668c2ecf20Sopenharmony_ci * interfaces and other half duplex devices suffer from throughput 11678c2ecf20Sopenharmony_ci * drops as they can't send and receive at the same time. 11688c2ecf20Sopenharmony_ci */ 11698c2ecf20Sopenharmony_ci if (if_outgoing && if_incoming == if_outgoing && 11708c2ecf20Sopenharmony_ci batadv_is_wifi_hardif(if_outgoing)) 11718c2ecf20Sopenharmony_ci tq_iface_hop_penalty = batadv_hop_penalty(tq_iface_hop_penalty, 11728c2ecf20Sopenharmony_ci bat_priv); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci combined_tq = batadv_ogm_packet->tq * 11758c2ecf20Sopenharmony_ci tq_own * 11768c2ecf20Sopenharmony_ci tq_asym_penalty * 11778c2ecf20Sopenharmony_ci tq_iface_hop_penalty; 11788c2ecf20Sopenharmony_ci combined_tq /= BATADV_TQ_MAX_VALUE * 11798c2ecf20Sopenharmony_ci BATADV_TQ_MAX_VALUE * 11808c2ecf20Sopenharmony_ci BATADV_TQ_MAX_VALUE; 11818c2ecf20Sopenharmony_ci batadv_ogm_packet->tq = combined_tq; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 11848c2ecf20Sopenharmony_ci "bidirectional: orig = %pM neigh = %pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, iface_hop_penalty: %3i, total tq: %3i, if_incoming = %s, if_outgoing = %s\n", 11858c2ecf20Sopenharmony_ci orig_node->orig, orig_neigh_node->orig, total_count, 11868c2ecf20Sopenharmony_ci neigh_rq_count, tq_own, tq_asym_penalty, 11878c2ecf20Sopenharmony_ci tq_iface_hop_penalty, batadv_ogm_packet->tq, 11888c2ecf20Sopenharmony_ci if_incoming->net_dev->name, 11898c2ecf20Sopenharmony_ci if_outgoing ? if_outgoing->net_dev->name : "DEFAULT"); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* if link has the minimum required transmission quality 11928c2ecf20Sopenharmony_ci * consider it bidirectional 11938c2ecf20Sopenharmony_ci */ 11948c2ecf20Sopenharmony_ci if (batadv_ogm_packet->tq >= BATADV_TQ_TOTAL_BIDRECT_LIMIT) 11958c2ecf20Sopenharmony_ci ret = true; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ciout: 11988c2ecf20Sopenharmony_ci if (neigh_node) 11998c2ecf20Sopenharmony_ci batadv_neigh_node_put(neigh_node); 12008c2ecf20Sopenharmony_ci return ret; 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci/** 12048c2ecf20Sopenharmony_ci * batadv_iv_ogm_update_seqnos() - process a batman packet for all interfaces, 12058c2ecf20Sopenharmony_ci * adjust the sequence number and find out whether it is a duplicate 12068c2ecf20Sopenharmony_ci * @ethhdr: ethernet header of the packet 12078c2ecf20Sopenharmony_ci * @batadv_ogm_packet: OGM packet to be considered 12088c2ecf20Sopenharmony_ci * @if_incoming: interface on which the OGM packet was received 12098c2ecf20Sopenharmony_ci * @if_outgoing: interface for which the retransmission should be considered 12108c2ecf20Sopenharmony_ci * 12118c2ecf20Sopenharmony_ci * Return: duplicate status as enum batadv_dup_status 12128c2ecf20Sopenharmony_ci */ 12138c2ecf20Sopenharmony_cistatic enum batadv_dup_status 12148c2ecf20Sopenharmony_cibatadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, 12158c2ecf20Sopenharmony_ci const struct batadv_ogm_packet *batadv_ogm_packet, 12168c2ecf20Sopenharmony_ci const struct batadv_hard_iface *if_incoming, 12178c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 12208c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node; 12218c2ecf20Sopenharmony_ci struct batadv_orig_ifinfo *orig_ifinfo = NULL; 12228c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node; 12238c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *neigh_ifinfo; 12248c2ecf20Sopenharmony_ci bool is_dup; 12258c2ecf20Sopenharmony_ci s32 seq_diff; 12268c2ecf20Sopenharmony_ci bool need_update = false; 12278c2ecf20Sopenharmony_ci int set_mark; 12288c2ecf20Sopenharmony_ci enum batadv_dup_status ret = BATADV_NO_DUP; 12298c2ecf20Sopenharmony_ci u32 seqno = ntohl(batadv_ogm_packet->seqno); 12308c2ecf20Sopenharmony_ci u8 *neigh_addr; 12318c2ecf20Sopenharmony_ci u8 packet_count; 12328c2ecf20Sopenharmony_ci unsigned long *bitmap; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig); 12358c2ecf20Sopenharmony_ci if (!orig_node) 12368c2ecf20Sopenharmony_ci return BATADV_NO_DUP; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); 12398c2ecf20Sopenharmony_ci if (WARN_ON(!orig_ifinfo)) { 12408c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_node); 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); 12458c2ecf20Sopenharmony_ci seq_diff = seqno - orig_ifinfo->last_real_seqno; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* signalize caller that the packet is to be dropped. */ 12488c2ecf20Sopenharmony_ci if (!hlist_empty(&orig_node->neigh_list) && 12498c2ecf20Sopenharmony_ci batadv_window_protected(bat_priv, seq_diff, 12508c2ecf20Sopenharmony_ci BATADV_TQ_LOCAL_WINDOW_SIZE, 12518c2ecf20Sopenharmony_ci &orig_ifinfo->batman_seqno_reset, NULL)) { 12528c2ecf20Sopenharmony_ci ret = BATADV_PROTECTED; 12538c2ecf20Sopenharmony_ci goto out; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci rcu_read_lock(); 12578c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { 12588c2ecf20Sopenharmony_ci neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, 12598c2ecf20Sopenharmony_ci if_outgoing); 12608c2ecf20Sopenharmony_ci if (!neigh_ifinfo) 12618c2ecf20Sopenharmony_ci continue; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci neigh_addr = neigh_node->addr; 12648c2ecf20Sopenharmony_ci is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, 12658c2ecf20Sopenharmony_ci orig_ifinfo->last_real_seqno, 12668c2ecf20Sopenharmony_ci seqno); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && 12698c2ecf20Sopenharmony_ci neigh_node->if_incoming == if_incoming) { 12708c2ecf20Sopenharmony_ci set_mark = 1; 12718c2ecf20Sopenharmony_ci if (is_dup) 12728c2ecf20Sopenharmony_ci ret = BATADV_NEIGH_DUP; 12738c2ecf20Sopenharmony_ci } else { 12748c2ecf20Sopenharmony_ci set_mark = 0; 12758c2ecf20Sopenharmony_ci if (is_dup && ret != BATADV_NEIGH_DUP) 12768c2ecf20Sopenharmony_ci ret = BATADV_ORIG_DUP; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* if the window moved, set the update flag. */ 12808c2ecf20Sopenharmony_ci bitmap = neigh_ifinfo->bat_iv.real_bits; 12818c2ecf20Sopenharmony_ci need_update |= batadv_bit_get_packet(bat_priv, bitmap, 12828c2ecf20Sopenharmony_ci seq_diff, set_mark); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci packet_count = bitmap_weight(bitmap, 12858c2ecf20Sopenharmony_ci BATADV_TQ_LOCAL_WINDOW_SIZE); 12868c2ecf20Sopenharmony_ci neigh_ifinfo->bat_iv.real_packet_count = packet_count; 12878c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(neigh_ifinfo); 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci rcu_read_unlock(); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (need_update) { 12928c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 12938c2ecf20Sopenharmony_ci "%s updating last_seqno: old %u, new %u\n", 12948c2ecf20Sopenharmony_ci if_outgoing ? if_outgoing->net_dev->name : "DEFAULT", 12958c2ecf20Sopenharmony_ci orig_ifinfo->last_real_seqno, seqno); 12968c2ecf20Sopenharmony_ci orig_ifinfo->last_real_seqno = seqno; 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ciout: 13008c2ecf20Sopenharmony_ci spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); 13018c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_node); 13028c2ecf20Sopenharmony_ci batadv_orig_ifinfo_put(orig_ifinfo); 13038c2ecf20Sopenharmony_ci return ret; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci/** 13078c2ecf20Sopenharmony_ci * batadv_iv_ogm_process_per_outif() - process a batman iv OGM for an outgoing 13088c2ecf20Sopenharmony_ci * interface 13098c2ecf20Sopenharmony_ci * @skb: the skb containing the OGM 13108c2ecf20Sopenharmony_ci * @ogm_offset: offset from skb->data to start of ogm header 13118c2ecf20Sopenharmony_ci * @orig_node: the (cached) orig node for the originator of this OGM 13128c2ecf20Sopenharmony_ci * @if_incoming: the interface where this packet was received 13138c2ecf20Sopenharmony_ci * @if_outgoing: the interface for which the packet should be considered 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_cistatic void 13168c2ecf20Sopenharmony_cibatadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, 13178c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node, 13188c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming, 13198c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 13228c2ecf20Sopenharmony_ci struct batadv_hardif_neigh_node *hardif_neigh = NULL; 13238c2ecf20Sopenharmony_ci struct batadv_neigh_node *router = NULL; 13248c2ecf20Sopenharmony_ci struct batadv_neigh_node *router_router = NULL; 13258c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_neigh_node; 13268c2ecf20Sopenharmony_ci struct batadv_orig_ifinfo *orig_ifinfo; 13278c2ecf20Sopenharmony_ci struct batadv_neigh_node *orig_neigh_router = NULL; 13288c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *router_ifinfo = NULL; 13298c2ecf20Sopenharmony_ci struct batadv_ogm_packet *ogm_packet; 13308c2ecf20Sopenharmony_ci enum batadv_dup_status dup_status; 13318c2ecf20Sopenharmony_ci bool is_from_best_next_hop = false; 13328c2ecf20Sopenharmony_ci bool is_single_hop_neigh = false; 13338c2ecf20Sopenharmony_ci bool sameseq, similar_ttl; 13348c2ecf20Sopenharmony_ci struct sk_buff *skb_priv; 13358c2ecf20Sopenharmony_ci struct ethhdr *ethhdr; 13368c2ecf20Sopenharmony_ci u8 *prev_sender; 13378c2ecf20Sopenharmony_ci bool is_bidirect; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci /* create a private copy of the skb, as some functions change tq value 13408c2ecf20Sopenharmony_ci * and/or flags. 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_ci skb_priv = skb_copy(skb, GFP_ATOMIC); 13438c2ecf20Sopenharmony_ci if (!skb_priv) 13448c2ecf20Sopenharmony_ci return; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci ethhdr = eth_hdr(skb_priv); 13478c2ecf20Sopenharmony_ci ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet, 13508c2ecf20Sopenharmony_ci if_incoming, if_outgoing); 13518c2ecf20Sopenharmony_ci if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig)) 13528c2ecf20Sopenharmony_ci is_single_hop_neigh = true; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (dup_status == BATADV_PROTECTED) { 13558c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 13568c2ecf20Sopenharmony_ci "Drop packet: packet within seqno protection time (sender: %pM)\n", 13578c2ecf20Sopenharmony_ci ethhdr->h_source); 13588c2ecf20Sopenharmony_ci goto out; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (ogm_packet->tq == 0) { 13628c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 13638c2ecf20Sopenharmony_ci "Drop packet: originator packet with tq equal 0\n"); 13648c2ecf20Sopenharmony_ci goto out; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (is_single_hop_neigh) { 13688c2ecf20Sopenharmony_ci hardif_neigh = batadv_hardif_neigh_get(if_incoming, 13698c2ecf20Sopenharmony_ci ethhdr->h_source); 13708c2ecf20Sopenharmony_ci if (hardif_neigh) 13718c2ecf20Sopenharmony_ci hardif_neigh->last_seen = jiffies; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci router = batadv_orig_router_get(orig_node, if_outgoing); 13758c2ecf20Sopenharmony_ci if (router) { 13768c2ecf20Sopenharmony_ci router_router = batadv_orig_router_get(router->orig_node, 13778c2ecf20Sopenharmony_ci if_outgoing); 13788c2ecf20Sopenharmony_ci router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) && 13828c2ecf20Sopenharmony_ci (batadv_compare_eth(router->addr, ethhdr->h_source))) 13838c2ecf20Sopenharmony_ci is_from_best_next_hop = true; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci prev_sender = ogm_packet->prev_sender; 13868c2ecf20Sopenharmony_ci /* avoid temporary routing loops */ 13878c2ecf20Sopenharmony_ci if (router && router_router && 13888c2ecf20Sopenharmony_ci (batadv_compare_eth(router->addr, prev_sender)) && 13898c2ecf20Sopenharmony_ci !(batadv_compare_eth(ogm_packet->orig, prev_sender)) && 13908c2ecf20Sopenharmony_ci (batadv_compare_eth(router->addr, router_router->addr))) { 13918c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 13928c2ecf20Sopenharmony_ci "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", 13938c2ecf20Sopenharmony_ci ethhdr->h_source); 13948c2ecf20Sopenharmony_ci goto out; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (if_outgoing == BATADV_IF_DEFAULT) 13988c2ecf20Sopenharmony_ci batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci /* if sender is a direct neighbor the sender mac equals 14018c2ecf20Sopenharmony_ci * originator mac 14028c2ecf20Sopenharmony_ci */ 14038c2ecf20Sopenharmony_ci if (is_single_hop_neigh) 14048c2ecf20Sopenharmony_ci orig_neigh_node = orig_node; 14058c2ecf20Sopenharmony_ci else 14068c2ecf20Sopenharmony_ci orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, 14078c2ecf20Sopenharmony_ci ethhdr->h_source); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (!orig_neigh_node) 14108c2ecf20Sopenharmony_ci goto out; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci /* Update nc_nodes of the originator */ 14138c2ecf20Sopenharmony_ci batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node, 14148c2ecf20Sopenharmony_ci ogm_packet, is_single_hop_neigh); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci orig_neigh_router = batadv_orig_router_get(orig_neigh_node, 14178c2ecf20Sopenharmony_ci if_outgoing); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci /* drop packet if sender is not a direct neighbor and if we 14208c2ecf20Sopenharmony_ci * don't route towards it 14218c2ecf20Sopenharmony_ci */ 14228c2ecf20Sopenharmony_ci if (!is_single_hop_neigh && !orig_neigh_router) { 14238c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 14248c2ecf20Sopenharmony_ci "Drop packet: OGM via unknown neighbor!\n"); 14258c2ecf20Sopenharmony_ci goto out_neigh; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, 14298c2ecf20Sopenharmony_ci ogm_packet, if_incoming, 14308c2ecf20Sopenharmony_ci if_outgoing); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci /* update ranking if it is not a duplicate or has the same 14338c2ecf20Sopenharmony_ci * seqno and similar ttl as the non-duplicate 14348c2ecf20Sopenharmony_ci */ 14358c2ecf20Sopenharmony_ci orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); 14368c2ecf20Sopenharmony_ci if (!orig_ifinfo) 14378c2ecf20Sopenharmony_ci goto out_neigh; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno); 14408c2ecf20Sopenharmony_ci similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->ttl; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci if (is_bidirect && (dup_status == BATADV_NO_DUP || 14438c2ecf20Sopenharmony_ci (sameseq && similar_ttl))) { 14448c2ecf20Sopenharmony_ci batadv_iv_ogm_orig_update(bat_priv, orig_node, 14458c2ecf20Sopenharmony_ci orig_ifinfo, ethhdr, 14468c2ecf20Sopenharmony_ci ogm_packet, if_incoming, 14478c2ecf20Sopenharmony_ci if_outgoing, dup_status); 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci batadv_orig_ifinfo_put(orig_ifinfo); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci /* only forward for specific interface, not for the default one. */ 14528c2ecf20Sopenharmony_ci if (if_outgoing == BATADV_IF_DEFAULT) 14538c2ecf20Sopenharmony_ci goto out_neigh; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* is single hop (direct) neighbor */ 14568c2ecf20Sopenharmony_ci if (is_single_hop_neigh) { 14578c2ecf20Sopenharmony_ci /* OGMs from secondary interfaces should only scheduled once 14588c2ecf20Sopenharmony_ci * per interface where it has been received, not multiple times 14598c2ecf20Sopenharmony_ci */ 14608c2ecf20Sopenharmony_ci if (ogm_packet->ttl <= 2 && 14618c2ecf20Sopenharmony_ci if_incoming != if_outgoing) { 14628c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 14638c2ecf20Sopenharmony_ci "Drop packet: OGM from secondary interface and wrong outgoing interface\n"); 14648c2ecf20Sopenharmony_ci goto out_neigh; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci /* mark direct link on incoming interface */ 14678c2ecf20Sopenharmony_ci batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, 14688c2ecf20Sopenharmony_ci is_single_hop_neigh, 14698c2ecf20Sopenharmony_ci is_from_best_next_hop, if_incoming, 14708c2ecf20Sopenharmony_ci if_outgoing); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 14738c2ecf20Sopenharmony_ci "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); 14748c2ecf20Sopenharmony_ci goto out_neigh; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci /* multihop originator */ 14788c2ecf20Sopenharmony_ci if (!is_bidirect) { 14798c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 14808c2ecf20Sopenharmony_ci "Drop packet: not received via bidirectional link\n"); 14818c2ecf20Sopenharmony_ci goto out_neigh; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci if (dup_status == BATADV_NEIGH_DUP) { 14858c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 14868c2ecf20Sopenharmony_ci "Drop packet: duplicate packet received\n"); 14878c2ecf20Sopenharmony_ci goto out_neigh; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 14918c2ecf20Sopenharmony_ci "Forwarding packet: rebroadcast originator packet\n"); 14928c2ecf20Sopenharmony_ci batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, 14938c2ecf20Sopenharmony_ci is_single_hop_neigh, is_from_best_next_hop, 14948c2ecf20Sopenharmony_ci if_incoming, if_outgoing); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ciout_neigh: 14978c2ecf20Sopenharmony_ci if (orig_neigh_node && !is_single_hop_neigh) 14988c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_neigh_node); 14998c2ecf20Sopenharmony_ciout: 15008c2ecf20Sopenharmony_ci if (router_ifinfo) 15018c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(router_ifinfo); 15028c2ecf20Sopenharmony_ci if (router) 15038c2ecf20Sopenharmony_ci batadv_neigh_node_put(router); 15048c2ecf20Sopenharmony_ci if (router_router) 15058c2ecf20Sopenharmony_ci batadv_neigh_node_put(router_router); 15068c2ecf20Sopenharmony_ci if (orig_neigh_router) 15078c2ecf20Sopenharmony_ci batadv_neigh_node_put(orig_neigh_router); 15088c2ecf20Sopenharmony_ci if (hardif_neigh) 15098c2ecf20Sopenharmony_ci batadv_hardif_neigh_put(hardif_neigh); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci consume_skb(skb_priv); 15128c2ecf20Sopenharmony_ci} 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci/** 15158c2ecf20Sopenharmony_ci * batadv_iv_ogm_process_reply() - Check OGM for direct reply and process it 15168c2ecf20Sopenharmony_ci * @ogm_packet: rebroadcast OGM packet to process 15178c2ecf20Sopenharmony_ci * @if_incoming: the interface where this packet was received 15188c2ecf20Sopenharmony_ci * @orig_node: originator which reproadcasted the OGMs 15198c2ecf20Sopenharmony_ci * @if_incoming_seqno: OGM sequence number when rebroadcast was received 15208c2ecf20Sopenharmony_ci */ 15218c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_process_reply(struct batadv_ogm_packet *ogm_packet, 15228c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming, 15238c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node, 15248c2ecf20Sopenharmony_ci u32 if_incoming_seqno) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct batadv_orig_ifinfo *orig_ifinfo; 15278c2ecf20Sopenharmony_ci s32 bit_pos; 15288c2ecf20Sopenharmony_ci u8 *weight; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci /* neighbor has to indicate direct link and it has to 15318c2ecf20Sopenharmony_ci * come via the corresponding interface 15328c2ecf20Sopenharmony_ci */ 15338c2ecf20Sopenharmony_ci if (!(ogm_packet->flags & BATADV_DIRECTLINK)) 15348c2ecf20Sopenharmony_ci return; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (!batadv_compare_eth(if_incoming->net_dev->dev_addr, 15378c2ecf20Sopenharmony_ci ogm_packet->orig)) 15388c2ecf20Sopenharmony_ci return; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_incoming); 15418c2ecf20Sopenharmony_ci if (!orig_ifinfo) 15428c2ecf20Sopenharmony_ci return; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci /* save packet seqno for bidirectional check */ 15458c2ecf20Sopenharmony_ci spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); 15468c2ecf20Sopenharmony_ci bit_pos = if_incoming_seqno - 2; 15478c2ecf20Sopenharmony_ci bit_pos -= ntohl(ogm_packet->seqno); 15488c2ecf20Sopenharmony_ci batadv_set_bit(orig_ifinfo->bat_iv.bcast_own, bit_pos); 15498c2ecf20Sopenharmony_ci weight = &orig_ifinfo->bat_iv.bcast_own_sum; 15508c2ecf20Sopenharmony_ci *weight = bitmap_weight(orig_ifinfo->bat_iv.bcast_own, 15518c2ecf20Sopenharmony_ci BATADV_TQ_LOCAL_WINDOW_SIZE); 15528c2ecf20Sopenharmony_ci spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci batadv_orig_ifinfo_put(orig_ifinfo); 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci/** 15588c2ecf20Sopenharmony_ci * batadv_iv_ogm_process() - process an incoming batman iv OGM 15598c2ecf20Sopenharmony_ci * @skb: the skb containing the OGM 15608c2ecf20Sopenharmony_ci * @ogm_offset: offset to the OGM which should be processed (for aggregates) 15618c2ecf20Sopenharmony_ci * @if_incoming: the interface where this packet was received 15628c2ecf20Sopenharmony_ci */ 15638c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, 15648c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 15678c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_neigh_node, *orig_node; 15688c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 15698c2ecf20Sopenharmony_ci struct batadv_ogm_packet *ogm_packet; 15708c2ecf20Sopenharmony_ci u32 if_incoming_seqno; 15718c2ecf20Sopenharmony_ci bool has_directlink_flag; 15728c2ecf20Sopenharmony_ci struct ethhdr *ethhdr; 15738c2ecf20Sopenharmony_ci bool is_my_oldorig = false; 15748c2ecf20Sopenharmony_ci bool is_my_addr = false; 15758c2ecf20Sopenharmony_ci bool is_my_orig = false; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset); 15788c2ecf20Sopenharmony_ci ethhdr = eth_hdr(skb); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* Silently drop when the batman packet is actually not a 15818c2ecf20Sopenharmony_ci * correct packet. 15828c2ecf20Sopenharmony_ci * 15838c2ecf20Sopenharmony_ci * This might happen if a packet is padded (e.g. Ethernet has a 15848c2ecf20Sopenharmony_ci * minimum frame length of 64 byte) and the aggregation interprets 15858c2ecf20Sopenharmony_ci * it as an additional length. 15868c2ecf20Sopenharmony_ci * 15878c2ecf20Sopenharmony_ci * TODO: A more sane solution would be to have a bit in the 15888c2ecf20Sopenharmony_ci * batadv_ogm_packet to detect whether the packet is the last 15898c2ecf20Sopenharmony_ci * packet in an aggregation. Here we expect that the padding 15908c2ecf20Sopenharmony_ci * is always zero (or not 0x01) 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_ci if (ogm_packet->packet_type != BATADV_IV_OGM) 15938c2ecf20Sopenharmony_ci return; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci /* could be changed by schedule_own_packet() */ 15968c2ecf20Sopenharmony_ci if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (ogm_packet->flags & BATADV_DIRECTLINK) 15998c2ecf20Sopenharmony_ci has_directlink_flag = true; 16008c2ecf20Sopenharmony_ci else 16018c2ecf20Sopenharmony_ci has_directlink_flag = false; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 16048c2ecf20Sopenharmony_ci "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n", 16058c2ecf20Sopenharmony_ci ethhdr->h_source, if_incoming->net_dev->name, 16068c2ecf20Sopenharmony_ci if_incoming->net_dev->dev_addr, ogm_packet->orig, 16078c2ecf20Sopenharmony_ci ogm_packet->prev_sender, ntohl(ogm_packet->seqno), 16088c2ecf20Sopenharmony_ci ogm_packet->tq, ogm_packet->ttl, 16098c2ecf20Sopenharmony_ci ogm_packet->version, has_directlink_flag); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci rcu_read_lock(); 16128c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 16138c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_ACTIVE) 16148c2ecf20Sopenharmony_ci continue; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci if (hard_iface->soft_iface != if_incoming->soft_iface) 16178c2ecf20Sopenharmony_ci continue; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci if (batadv_compare_eth(ethhdr->h_source, 16208c2ecf20Sopenharmony_ci hard_iface->net_dev->dev_addr)) 16218c2ecf20Sopenharmony_ci is_my_addr = true; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (batadv_compare_eth(ogm_packet->orig, 16248c2ecf20Sopenharmony_ci hard_iface->net_dev->dev_addr)) 16258c2ecf20Sopenharmony_ci is_my_orig = true; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (batadv_compare_eth(ogm_packet->prev_sender, 16288c2ecf20Sopenharmony_ci hard_iface->net_dev->dev_addr)) 16298c2ecf20Sopenharmony_ci is_my_oldorig = true; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci rcu_read_unlock(); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (is_my_addr) { 16348c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 16358c2ecf20Sopenharmony_ci "Drop packet: received my own broadcast (sender: %pM)\n", 16368c2ecf20Sopenharmony_ci ethhdr->h_source); 16378c2ecf20Sopenharmony_ci return; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci if (is_my_orig) { 16418c2ecf20Sopenharmony_ci orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, 16428c2ecf20Sopenharmony_ci ethhdr->h_source); 16438c2ecf20Sopenharmony_ci if (!orig_neigh_node) 16448c2ecf20Sopenharmony_ci return; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci batadv_iv_ogm_process_reply(ogm_packet, if_incoming, 16478c2ecf20Sopenharmony_ci orig_neigh_node, if_incoming_seqno); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 16508c2ecf20Sopenharmony_ci "Drop packet: originator packet from myself (via neighbor)\n"); 16518c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_neigh_node); 16528c2ecf20Sopenharmony_ci return; 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci if (is_my_oldorig) { 16568c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 16578c2ecf20Sopenharmony_ci "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n", 16588c2ecf20Sopenharmony_ci ethhdr->h_source); 16598c2ecf20Sopenharmony_ci return; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { 16638c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 16648c2ecf20Sopenharmony_ci "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n", 16658c2ecf20Sopenharmony_ci ethhdr->h_source); 16668c2ecf20Sopenharmony_ci return; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig); 16708c2ecf20Sopenharmony_ci if (!orig_node) 16718c2ecf20Sopenharmony_ci return; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, 16748c2ecf20Sopenharmony_ci if_incoming, BATADV_IF_DEFAULT); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci rcu_read_lock(); 16778c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 16788c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_ACTIVE) 16798c2ecf20Sopenharmony_ci continue; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci if (hard_iface->soft_iface != bat_priv->soft_iface) 16828c2ecf20Sopenharmony_ci continue; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&hard_iface->refcount)) 16858c2ecf20Sopenharmony_ci continue; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, 16888c2ecf20Sopenharmony_ci if_incoming, hard_iface); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci rcu_read_unlock(); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_node); 16958c2ecf20Sopenharmony_ci} 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_cistatic void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci struct delayed_work *delayed_work; 17008c2ecf20Sopenharmony_ci struct batadv_forw_packet *forw_packet; 17018c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv; 17028c2ecf20Sopenharmony_ci bool dropped = false; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci delayed_work = to_delayed_work(work); 17058c2ecf20Sopenharmony_ci forw_packet = container_of(delayed_work, struct batadv_forw_packet, 17068c2ecf20Sopenharmony_ci delayed_work); 17078c2ecf20Sopenharmony_ci bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { 17108c2ecf20Sopenharmony_ci dropped = true; 17118c2ecf20Sopenharmony_ci goto out; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci batadv_iv_ogm_emit(forw_packet); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci /* we have to have at least one packet in the queue to determine the 17178c2ecf20Sopenharmony_ci * queues wake up time unless we are shutting down. 17188c2ecf20Sopenharmony_ci * 17198c2ecf20Sopenharmony_ci * only re-schedule if this is the "original" copy, e.g. the OGM of the 17208c2ecf20Sopenharmony_ci * primary interface should only be rescheduled once per period, but 17218c2ecf20Sopenharmony_ci * this function will be called for the forw_packet instances of the 17228c2ecf20Sopenharmony_ci * other secondary interfaces as well. 17238c2ecf20Sopenharmony_ci */ 17248c2ecf20Sopenharmony_ci if (forw_packet->own && 17258c2ecf20Sopenharmony_ci forw_packet->if_incoming == forw_packet->if_outgoing) 17268c2ecf20Sopenharmony_ci batadv_iv_ogm_schedule(forw_packet->if_incoming); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ciout: 17298c2ecf20Sopenharmony_ci /* do we get something for free()? */ 17308c2ecf20Sopenharmony_ci if (batadv_forw_packet_steal(forw_packet, 17318c2ecf20Sopenharmony_ci &bat_priv->forw_bat_list_lock)) 17328c2ecf20Sopenharmony_ci batadv_forw_packet_free(forw_packet, dropped); 17338c2ecf20Sopenharmony_ci} 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_cistatic int batadv_iv_ogm_receive(struct sk_buff *skb, 17368c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_incoming) 17378c2ecf20Sopenharmony_ci{ 17388c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 17398c2ecf20Sopenharmony_ci struct batadv_ogm_packet *ogm_packet; 17408c2ecf20Sopenharmony_ci u8 *packet_pos; 17418c2ecf20Sopenharmony_ci int ogm_offset; 17428c2ecf20Sopenharmony_ci bool res; 17438c2ecf20Sopenharmony_ci int ret = NET_RX_DROP; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci res = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); 17468c2ecf20Sopenharmony_ci if (!res) 17478c2ecf20Sopenharmony_ci goto free_skb; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci /* did we receive a B.A.T.M.A.N. IV OGM packet on an interface 17508c2ecf20Sopenharmony_ci * that does not have B.A.T.M.A.N. IV enabled ? 17518c2ecf20Sopenharmony_ci */ 17528c2ecf20Sopenharmony_ci if (bat_priv->algo_ops->iface.enable != batadv_iv_ogm_iface_enable) 17538c2ecf20Sopenharmony_ci goto free_skb; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX); 17568c2ecf20Sopenharmony_ci batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, 17578c2ecf20Sopenharmony_ci skb->len + ETH_HLEN); 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci ogm_offset = 0; 17608c2ecf20Sopenharmony_ci ogm_packet = (struct batadv_ogm_packet *)skb->data; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci /* unpack the aggregated packets and process them one by one */ 17638c2ecf20Sopenharmony_ci while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb), 17648c2ecf20Sopenharmony_ci ogm_packet)) { 17658c2ecf20Sopenharmony_ci batadv_iv_ogm_process(skb, ogm_offset, if_incoming); 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci ogm_offset += BATADV_OGM_HLEN; 17688c2ecf20Sopenharmony_ci ogm_offset += ntohs(ogm_packet->tvlv_len); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci packet_pos = skb->data + ogm_offset; 17718c2ecf20Sopenharmony_ci ogm_packet = (struct batadv_ogm_packet *)packet_pos; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci ret = NET_RX_SUCCESS; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_cifree_skb: 17778c2ecf20Sopenharmony_ci if (ret == NET_RX_SUCCESS) 17788c2ecf20Sopenharmony_ci consume_skb(skb); 17798c2ecf20Sopenharmony_ci else 17808c2ecf20Sopenharmony_ci kfree_skb(skb); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci return ret; 17838c2ecf20Sopenharmony_ci} 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS 17868c2ecf20Sopenharmony_ci/** 17878c2ecf20Sopenharmony_ci * batadv_iv_ogm_orig_print_neigh() - print neighbors for the originator table 17888c2ecf20Sopenharmony_ci * @orig_node: the orig_node for which the neighbors are printed 17898c2ecf20Sopenharmony_ci * @if_outgoing: outgoing interface for these entries 17908c2ecf20Sopenharmony_ci * @seq: debugfs table seq_file struct 17918c2ecf20Sopenharmony_ci * 17928c2ecf20Sopenharmony_ci * Must be called while holding an rcu lock. 17938c2ecf20Sopenharmony_ci */ 17948c2ecf20Sopenharmony_cistatic void 17958c2ecf20Sopenharmony_cibatadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node, 17968c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing, 17978c2ecf20Sopenharmony_ci struct seq_file *seq) 17988c2ecf20Sopenharmony_ci{ 17998c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node; 18008c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *n_ifinfo; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { 18038c2ecf20Sopenharmony_ci n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); 18048c2ecf20Sopenharmony_ci if (!n_ifinfo) 18058c2ecf20Sopenharmony_ci continue; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci seq_printf(seq, " %pM (%3i)", 18088c2ecf20Sopenharmony_ci neigh_node->addr, 18098c2ecf20Sopenharmony_ci n_ifinfo->bat_iv.tq_avg); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(n_ifinfo); 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci} 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci/** 18168c2ecf20Sopenharmony_ci * batadv_iv_ogm_orig_print() - print the originator table 18178c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 18188c2ecf20Sopenharmony_ci * @seq: debugfs table seq_file struct 18198c2ecf20Sopenharmony_ci * @if_outgoing: the outgoing interface for which this should be printed 18208c2ecf20Sopenharmony_ci */ 18218c2ecf20Sopenharmony_cistatic void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, 18228c2ecf20Sopenharmony_ci struct seq_file *seq, 18238c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node; 18268c2ecf20Sopenharmony_ci struct batadv_hashtable *hash = bat_priv->orig_hash; 18278c2ecf20Sopenharmony_ci int last_seen_msecs, last_seen_secs; 18288c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node; 18298c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *n_ifinfo; 18308c2ecf20Sopenharmony_ci unsigned long last_seen_jiffies; 18318c2ecf20Sopenharmony_ci struct hlist_head *head; 18328c2ecf20Sopenharmony_ci int batman_count = 0; 18338c2ecf20Sopenharmony_ci u32 i; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci seq_puts(seq, 18368c2ecf20Sopenharmony_ci " Originator last-seen (#/255) Nexthop [outgoingIF]: Potential nexthops ...\n"); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci for (i = 0; i < hash->size; i++) { 18398c2ecf20Sopenharmony_ci head = &hash->table[i]; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci rcu_read_lock(); 18428c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(orig_node, head, hash_entry) { 18438c2ecf20Sopenharmony_ci neigh_node = batadv_orig_router_get(orig_node, 18448c2ecf20Sopenharmony_ci if_outgoing); 18458c2ecf20Sopenharmony_ci if (!neigh_node) 18468c2ecf20Sopenharmony_ci continue; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, 18498c2ecf20Sopenharmony_ci if_outgoing); 18508c2ecf20Sopenharmony_ci if (!n_ifinfo) 18518c2ecf20Sopenharmony_ci goto next; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci if (n_ifinfo->bat_iv.tq_avg == 0) 18548c2ecf20Sopenharmony_ci goto next; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci last_seen_jiffies = jiffies - orig_node->last_seen; 18578c2ecf20Sopenharmony_ci last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 18588c2ecf20Sopenharmony_ci last_seen_secs = last_seen_msecs / 1000; 18598c2ecf20Sopenharmony_ci last_seen_msecs = last_seen_msecs % 1000; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", 18628c2ecf20Sopenharmony_ci orig_node->orig, last_seen_secs, 18638c2ecf20Sopenharmony_ci last_seen_msecs, n_ifinfo->bat_iv.tq_avg, 18648c2ecf20Sopenharmony_ci neigh_node->addr, 18658c2ecf20Sopenharmony_ci neigh_node->if_incoming->net_dev->name); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci batadv_iv_ogm_orig_print_neigh(orig_node, if_outgoing, 18688c2ecf20Sopenharmony_ci seq); 18698c2ecf20Sopenharmony_ci seq_putc(seq, '\n'); 18708c2ecf20Sopenharmony_ci batman_count++; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_cinext: 18738c2ecf20Sopenharmony_ci batadv_neigh_node_put(neigh_node); 18748c2ecf20Sopenharmony_ci if (n_ifinfo) 18758c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(n_ifinfo); 18768c2ecf20Sopenharmony_ci } 18778c2ecf20Sopenharmony_ci rcu_read_unlock(); 18788c2ecf20Sopenharmony_ci } 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci if (batman_count == 0) 18818c2ecf20Sopenharmony_ci seq_puts(seq, "No batman nodes in range ...\n"); 18828c2ecf20Sopenharmony_ci} 18838c2ecf20Sopenharmony_ci#endif 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci/** 18868c2ecf20Sopenharmony_ci * batadv_iv_ogm_neigh_get_tq_avg() - Get the TQ average for a neighbour on a 18878c2ecf20Sopenharmony_ci * given outgoing interface. 18888c2ecf20Sopenharmony_ci * @neigh_node: Neighbour of interest 18898c2ecf20Sopenharmony_ci * @if_outgoing: Outgoing interface of interest 18908c2ecf20Sopenharmony_ci * @tq_avg: Pointer of where to store the TQ average 18918c2ecf20Sopenharmony_ci * 18928c2ecf20Sopenharmony_ci * Return: False if no average TQ available, otherwise true. 18938c2ecf20Sopenharmony_ci */ 18948c2ecf20Sopenharmony_cistatic bool 18958c2ecf20Sopenharmony_cibatadv_iv_ogm_neigh_get_tq_avg(struct batadv_neigh_node *neigh_node, 18968c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing, 18978c2ecf20Sopenharmony_ci u8 *tq_avg) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *n_ifinfo; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); 19028c2ecf20Sopenharmony_ci if (!n_ifinfo) 19038c2ecf20Sopenharmony_ci return false; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci *tq_avg = n_ifinfo->bat_iv.tq_avg; 19068c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(n_ifinfo); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci return true; 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci/** 19128c2ecf20Sopenharmony_ci * batadv_iv_ogm_orig_dump_subentry() - Dump an originator subentry into a 19138c2ecf20Sopenharmony_ci * message 19148c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 19158c2ecf20Sopenharmony_ci * @portid: Port making netlink request 19168c2ecf20Sopenharmony_ci * @seq: Sequence number of netlink message 19178c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information 19188c2ecf20Sopenharmony_ci * @if_outgoing: Limit dump to entries with this outgoing interface 19198c2ecf20Sopenharmony_ci * @orig_node: Originator to dump 19208c2ecf20Sopenharmony_ci * @neigh_node: Single hops neighbour 19218c2ecf20Sopenharmony_ci * @best: Is the best originator 19228c2ecf20Sopenharmony_ci * 19238c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success 19248c2ecf20Sopenharmony_ci */ 19258c2ecf20Sopenharmony_cistatic int 19268c2ecf20Sopenharmony_cibatadv_iv_ogm_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, 19278c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv, 19288c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing, 19298c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node, 19308c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node, 19318c2ecf20Sopenharmony_ci bool best) 19328c2ecf20Sopenharmony_ci{ 19338c2ecf20Sopenharmony_ci void *hdr; 19348c2ecf20Sopenharmony_ci u8 tq_avg; 19358c2ecf20Sopenharmony_ci unsigned int last_seen_msecs; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node, if_outgoing, &tq_avg)) 19408c2ecf20Sopenharmony_ci return 0; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci if (if_outgoing != BATADV_IF_DEFAULT && 19438c2ecf20Sopenharmony_ci if_outgoing != neigh_node->if_incoming) 19448c2ecf20Sopenharmony_ci return 0; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, 19478c2ecf20Sopenharmony_ci NLM_F_MULTI, BATADV_CMD_GET_ORIGINATORS); 19488c2ecf20Sopenharmony_ci if (!hdr) 19498c2ecf20Sopenharmony_ci return -ENOBUFS; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, 19528c2ecf20Sopenharmony_ci orig_node->orig) || 19538c2ecf20Sopenharmony_ci nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN, 19548c2ecf20Sopenharmony_ci neigh_node->addr) || 19558c2ecf20Sopenharmony_ci nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, 19568c2ecf20Sopenharmony_ci neigh_node->if_incoming->net_dev->ifindex) || 19578c2ecf20Sopenharmony_ci nla_put_u8(msg, BATADV_ATTR_TQ, tq_avg) || 19588c2ecf20Sopenharmony_ci nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, 19598c2ecf20Sopenharmony_ci last_seen_msecs)) 19608c2ecf20Sopenharmony_ci goto nla_put_failure; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) 19638c2ecf20Sopenharmony_ci goto nla_put_failure; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 19668c2ecf20Sopenharmony_ci return 0; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci nla_put_failure: 19698c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 19708c2ecf20Sopenharmony_ci return -EMSGSIZE; 19718c2ecf20Sopenharmony_ci} 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci/** 19748c2ecf20Sopenharmony_ci * batadv_iv_ogm_orig_dump_entry() - Dump an originator entry into a message 19758c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 19768c2ecf20Sopenharmony_ci * @portid: Port making netlink request 19778c2ecf20Sopenharmony_ci * @seq: Sequence number of netlink message 19788c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information 19798c2ecf20Sopenharmony_ci * @if_outgoing: Limit dump to entries with this outgoing interface 19808c2ecf20Sopenharmony_ci * @orig_node: Originator to dump 19818c2ecf20Sopenharmony_ci * @sub_s: Number of sub entries to skip 19828c2ecf20Sopenharmony_ci * 19838c2ecf20Sopenharmony_ci * This function assumes the caller holds rcu_read_lock(). 19848c2ecf20Sopenharmony_ci * 19858c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success 19868c2ecf20Sopenharmony_ci */ 19878c2ecf20Sopenharmony_cistatic int 19888c2ecf20Sopenharmony_cibatadv_iv_ogm_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, 19898c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv, 19908c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing, 19918c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node, int *sub_s) 19928c2ecf20Sopenharmony_ci{ 19938c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node_best; 19948c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node; 19958c2ecf20Sopenharmony_ci int sub = 0; 19968c2ecf20Sopenharmony_ci bool best; 19978c2ecf20Sopenharmony_ci u8 tq_avg_best; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing); 20008c2ecf20Sopenharmony_ci if (!neigh_node_best) 20018c2ecf20Sopenharmony_ci goto out; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node_best, if_outgoing, 20048c2ecf20Sopenharmony_ci &tq_avg_best)) 20058c2ecf20Sopenharmony_ci goto out; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci if (tq_avg_best == 0) 20088c2ecf20Sopenharmony_ci goto out; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { 20118c2ecf20Sopenharmony_ci if (sub++ < *sub_s) 20128c2ecf20Sopenharmony_ci continue; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci best = (neigh_node == neigh_node_best); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci if (batadv_iv_ogm_orig_dump_subentry(msg, portid, seq, 20178c2ecf20Sopenharmony_ci bat_priv, if_outgoing, 20188c2ecf20Sopenharmony_ci orig_node, neigh_node, 20198c2ecf20Sopenharmony_ci best)) { 20208c2ecf20Sopenharmony_ci batadv_neigh_node_put(neigh_node_best); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci *sub_s = sub - 1; 20238c2ecf20Sopenharmony_ci return -EMSGSIZE; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci out: 20288c2ecf20Sopenharmony_ci if (neigh_node_best) 20298c2ecf20Sopenharmony_ci batadv_neigh_node_put(neigh_node_best); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci *sub_s = 0; 20328c2ecf20Sopenharmony_ci return 0; 20338c2ecf20Sopenharmony_ci} 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci/** 20368c2ecf20Sopenharmony_ci * batadv_iv_ogm_orig_dump_bucket() - Dump an originator bucket into a 20378c2ecf20Sopenharmony_ci * message 20388c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 20398c2ecf20Sopenharmony_ci * @portid: Port making netlink request 20408c2ecf20Sopenharmony_ci * @seq: Sequence number of netlink message 20418c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information 20428c2ecf20Sopenharmony_ci * @if_outgoing: Limit dump to entries with this outgoing interface 20438c2ecf20Sopenharmony_ci * @head: Bucket to be dumped 20448c2ecf20Sopenharmony_ci * @idx_s: Number of entries to be skipped 20458c2ecf20Sopenharmony_ci * @sub: Number of sub entries to be skipped 20468c2ecf20Sopenharmony_ci * 20478c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success 20488c2ecf20Sopenharmony_ci */ 20498c2ecf20Sopenharmony_cistatic int 20508c2ecf20Sopenharmony_cibatadv_iv_ogm_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, 20518c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv, 20528c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing, 20538c2ecf20Sopenharmony_ci struct hlist_head *head, int *idx_s, int *sub) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node; 20568c2ecf20Sopenharmony_ci int idx = 0; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci rcu_read_lock(); 20598c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(orig_node, head, hash_entry) { 20608c2ecf20Sopenharmony_ci if (idx++ < *idx_s) 20618c2ecf20Sopenharmony_ci continue; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci if (batadv_iv_ogm_orig_dump_entry(msg, portid, seq, bat_priv, 20648c2ecf20Sopenharmony_ci if_outgoing, orig_node, 20658c2ecf20Sopenharmony_ci sub)) { 20668c2ecf20Sopenharmony_ci rcu_read_unlock(); 20678c2ecf20Sopenharmony_ci *idx_s = idx - 1; 20688c2ecf20Sopenharmony_ci return -EMSGSIZE; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci rcu_read_unlock(); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci *idx_s = 0; 20748c2ecf20Sopenharmony_ci *sub = 0; 20758c2ecf20Sopenharmony_ci return 0; 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci/** 20798c2ecf20Sopenharmony_ci * batadv_iv_ogm_orig_dump() - Dump the originators into a message 20808c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 20818c2ecf20Sopenharmony_ci * @cb: Control block containing additional options 20828c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information 20838c2ecf20Sopenharmony_ci * @if_outgoing: Limit dump to entries with this outgoing interface 20848c2ecf20Sopenharmony_ci */ 20858c2ecf20Sopenharmony_cistatic void 20868c2ecf20Sopenharmony_cibatadv_iv_ogm_orig_dump(struct sk_buff *msg, struct netlink_callback *cb, 20878c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv, 20888c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing) 20898c2ecf20Sopenharmony_ci{ 20908c2ecf20Sopenharmony_ci struct batadv_hashtable *hash = bat_priv->orig_hash; 20918c2ecf20Sopenharmony_ci struct hlist_head *head; 20928c2ecf20Sopenharmony_ci int bucket = cb->args[0]; 20938c2ecf20Sopenharmony_ci int idx = cb->args[1]; 20948c2ecf20Sopenharmony_ci int sub = cb->args[2]; 20958c2ecf20Sopenharmony_ci int portid = NETLINK_CB(cb->skb).portid; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci while (bucket < hash->size) { 20988c2ecf20Sopenharmony_ci head = &hash->table[bucket]; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci if (batadv_iv_ogm_orig_dump_bucket(msg, portid, 21018c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 21028c2ecf20Sopenharmony_ci bat_priv, if_outgoing, head, 21038c2ecf20Sopenharmony_ci &idx, &sub)) 21048c2ecf20Sopenharmony_ci break; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci bucket++; 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci cb->args[0] = bucket; 21108c2ecf20Sopenharmony_ci cb->args[1] = idx; 21118c2ecf20Sopenharmony_ci cb->args[2] = sub; 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS 21158c2ecf20Sopenharmony_ci/** 21168c2ecf20Sopenharmony_ci * batadv_iv_hardif_neigh_print() - print a single hop neighbour node 21178c2ecf20Sopenharmony_ci * @seq: neighbour table seq_file struct 21188c2ecf20Sopenharmony_ci * @hardif_neigh: hardif neighbour information 21198c2ecf20Sopenharmony_ci */ 21208c2ecf20Sopenharmony_cistatic void 21218c2ecf20Sopenharmony_cibatadv_iv_hardif_neigh_print(struct seq_file *seq, 21228c2ecf20Sopenharmony_ci struct batadv_hardif_neigh_node *hardif_neigh) 21238c2ecf20Sopenharmony_ci{ 21248c2ecf20Sopenharmony_ci int last_secs, last_msecs; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000; 21278c2ecf20Sopenharmony_ci last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci seq_printf(seq, " %10s %pM %4i.%03is\n", 21308c2ecf20Sopenharmony_ci hardif_neigh->if_incoming->net_dev->name, 21318c2ecf20Sopenharmony_ci hardif_neigh->addr, last_secs, last_msecs); 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci/** 21358c2ecf20Sopenharmony_ci * batadv_iv_ogm_neigh_print() - print the single hop neighbour list 21368c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 21378c2ecf20Sopenharmony_ci * @seq: neighbour table seq_file struct 21388c2ecf20Sopenharmony_ci */ 21398c2ecf20Sopenharmony_cistatic void batadv_iv_neigh_print(struct batadv_priv *bat_priv, 21408c2ecf20Sopenharmony_ci struct seq_file *seq) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci struct net_device *net_dev = (struct net_device *)seq->private; 21438c2ecf20Sopenharmony_ci struct batadv_hardif_neigh_node *hardif_neigh; 21448c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 21458c2ecf20Sopenharmony_ci int batman_count = 0; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci seq_puts(seq, " IF Neighbor last-seen\n"); 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci rcu_read_lock(); 21508c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 21518c2ecf20Sopenharmony_ci if (hard_iface->soft_iface != net_dev) 21528c2ecf20Sopenharmony_ci continue; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(hardif_neigh, 21558c2ecf20Sopenharmony_ci &hard_iface->neigh_list, list) { 21568c2ecf20Sopenharmony_ci batadv_iv_hardif_neigh_print(seq, hardif_neigh); 21578c2ecf20Sopenharmony_ci batman_count++; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci rcu_read_unlock(); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci if (batman_count == 0) 21638c2ecf20Sopenharmony_ci seq_puts(seq, "No batman nodes in range ...\n"); 21648c2ecf20Sopenharmony_ci} 21658c2ecf20Sopenharmony_ci#endif 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci/** 21688c2ecf20Sopenharmony_ci * batadv_iv_ogm_neigh_diff() - calculate tq difference of two neighbors 21698c2ecf20Sopenharmony_ci * @neigh1: the first neighbor object of the comparison 21708c2ecf20Sopenharmony_ci * @if_outgoing1: outgoing interface for the first neighbor 21718c2ecf20Sopenharmony_ci * @neigh2: the second neighbor object of the comparison 21728c2ecf20Sopenharmony_ci * @if_outgoing2: outgoing interface for the second neighbor 21738c2ecf20Sopenharmony_ci * @diff: pointer to integer receiving the calculated difference 21748c2ecf20Sopenharmony_ci * 21758c2ecf20Sopenharmony_ci * The content of *@diff is only valid when this function returns true. 21768c2ecf20Sopenharmony_ci * It is less, equal to or greater than 0 if the metric via neigh1 is lower, 21778c2ecf20Sopenharmony_ci * the same as or higher than the metric via neigh2 21788c2ecf20Sopenharmony_ci * 21798c2ecf20Sopenharmony_ci * Return: true when the difference could be calculated, false otherwise 21808c2ecf20Sopenharmony_ci */ 21818c2ecf20Sopenharmony_cistatic bool batadv_iv_ogm_neigh_diff(struct batadv_neigh_node *neigh1, 21828c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing1, 21838c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh2, 21848c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing2, 21858c2ecf20Sopenharmony_ci int *diff) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; 21888c2ecf20Sopenharmony_ci u8 tq1, tq2; 21898c2ecf20Sopenharmony_ci bool ret = true; 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); 21928c2ecf20Sopenharmony_ci neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci if (!neigh1_ifinfo || !neigh2_ifinfo) { 21958c2ecf20Sopenharmony_ci ret = false; 21968c2ecf20Sopenharmony_ci goto out; 21978c2ecf20Sopenharmony_ci } 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci tq1 = neigh1_ifinfo->bat_iv.tq_avg; 22008c2ecf20Sopenharmony_ci tq2 = neigh2_ifinfo->bat_iv.tq_avg; 22018c2ecf20Sopenharmony_ci *diff = (int)tq1 - (int)tq2; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ciout: 22048c2ecf20Sopenharmony_ci if (neigh1_ifinfo) 22058c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(neigh1_ifinfo); 22068c2ecf20Sopenharmony_ci if (neigh2_ifinfo) 22078c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(neigh2_ifinfo); 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci return ret; 22108c2ecf20Sopenharmony_ci} 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci/** 22138c2ecf20Sopenharmony_ci * batadv_iv_ogm_neigh_dump_neigh() - Dump a neighbour into a netlink message 22148c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 22158c2ecf20Sopenharmony_ci * @portid: Port making netlink request 22168c2ecf20Sopenharmony_ci * @seq: Sequence number of netlink message 22178c2ecf20Sopenharmony_ci * @hardif_neigh: Neighbour to be dumped 22188c2ecf20Sopenharmony_ci * 22198c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success 22208c2ecf20Sopenharmony_ci */ 22218c2ecf20Sopenharmony_cistatic int 22228c2ecf20Sopenharmony_cibatadv_iv_ogm_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq, 22238c2ecf20Sopenharmony_ci struct batadv_hardif_neigh_node *hardif_neigh) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci void *hdr; 22268c2ecf20Sopenharmony_ci unsigned int last_seen_msecs; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen); 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, 22318c2ecf20Sopenharmony_ci NLM_F_MULTI, BATADV_CMD_GET_NEIGHBORS); 22328c2ecf20Sopenharmony_ci if (!hdr) 22338c2ecf20Sopenharmony_ci return -ENOBUFS; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN, 22368c2ecf20Sopenharmony_ci hardif_neigh->addr) || 22378c2ecf20Sopenharmony_ci nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, 22388c2ecf20Sopenharmony_ci hardif_neigh->if_incoming->net_dev->ifindex) || 22398c2ecf20Sopenharmony_ci nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, 22408c2ecf20Sopenharmony_ci last_seen_msecs)) 22418c2ecf20Sopenharmony_ci goto nla_put_failure; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 22448c2ecf20Sopenharmony_ci return 0; 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci nla_put_failure: 22478c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 22488c2ecf20Sopenharmony_ci return -EMSGSIZE; 22498c2ecf20Sopenharmony_ci} 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci/** 22528c2ecf20Sopenharmony_ci * batadv_iv_ogm_neigh_dump_hardif() - Dump the neighbours of a hard interface 22538c2ecf20Sopenharmony_ci * into a message 22548c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 22558c2ecf20Sopenharmony_ci * @portid: Port making netlink request 22568c2ecf20Sopenharmony_ci * @seq: Sequence number of netlink message 22578c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information 22588c2ecf20Sopenharmony_ci * @hard_iface: Hard interface to dump the neighbours for 22598c2ecf20Sopenharmony_ci * @idx_s: Number of entries to skip 22608c2ecf20Sopenharmony_ci * 22618c2ecf20Sopenharmony_ci * This function assumes the caller holds rcu_read_lock(). 22628c2ecf20Sopenharmony_ci * 22638c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success 22648c2ecf20Sopenharmony_ci */ 22658c2ecf20Sopenharmony_cistatic int 22668c2ecf20Sopenharmony_cibatadv_iv_ogm_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq, 22678c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv, 22688c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface, 22698c2ecf20Sopenharmony_ci int *idx_s) 22708c2ecf20Sopenharmony_ci{ 22718c2ecf20Sopenharmony_ci struct batadv_hardif_neigh_node *hardif_neigh; 22728c2ecf20Sopenharmony_ci int idx = 0; 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(hardif_neigh, 22758c2ecf20Sopenharmony_ci &hard_iface->neigh_list, list) { 22768c2ecf20Sopenharmony_ci if (idx++ < *idx_s) 22778c2ecf20Sopenharmony_ci continue; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci if (batadv_iv_ogm_neigh_dump_neigh(msg, portid, seq, 22808c2ecf20Sopenharmony_ci hardif_neigh)) { 22818c2ecf20Sopenharmony_ci *idx_s = idx - 1; 22828c2ecf20Sopenharmony_ci return -EMSGSIZE; 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci *idx_s = 0; 22878c2ecf20Sopenharmony_ci return 0; 22888c2ecf20Sopenharmony_ci} 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci/** 22918c2ecf20Sopenharmony_ci * batadv_iv_ogm_neigh_dump() - Dump the neighbours into a message 22928c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 22938c2ecf20Sopenharmony_ci * @cb: Control block containing additional options 22948c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information 22958c2ecf20Sopenharmony_ci * @single_hardif: Limit dump to this hard interface 22968c2ecf20Sopenharmony_ci */ 22978c2ecf20Sopenharmony_cistatic void 22988c2ecf20Sopenharmony_cibatadv_iv_ogm_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb, 22998c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv, 23008c2ecf20Sopenharmony_ci struct batadv_hard_iface *single_hardif) 23018c2ecf20Sopenharmony_ci{ 23028c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 23038c2ecf20Sopenharmony_ci int i_hardif = 0; 23048c2ecf20Sopenharmony_ci int i_hardif_s = cb->args[0]; 23058c2ecf20Sopenharmony_ci int idx = cb->args[1]; 23068c2ecf20Sopenharmony_ci int portid = NETLINK_CB(cb->skb).portid; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci rcu_read_lock(); 23098c2ecf20Sopenharmony_ci if (single_hardif) { 23108c2ecf20Sopenharmony_ci if (i_hardif_s == 0) { 23118c2ecf20Sopenharmony_ci if (batadv_iv_ogm_neigh_dump_hardif(msg, portid, 23128c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 23138c2ecf20Sopenharmony_ci bat_priv, 23148c2ecf20Sopenharmony_ci single_hardif, 23158c2ecf20Sopenharmony_ci &idx) == 0) 23168c2ecf20Sopenharmony_ci i_hardif++; 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci } else { 23198c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, 23208c2ecf20Sopenharmony_ci list) { 23218c2ecf20Sopenharmony_ci if (hard_iface->soft_iface != bat_priv->soft_iface) 23228c2ecf20Sopenharmony_ci continue; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci if (i_hardif++ < i_hardif_s) 23258c2ecf20Sopenharmony_ci continue; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci if (batadv_iv_ogm_neigh_dump_hardif(msg, portid, 23288c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 23298c2ecf20Sopenharmony_ci bat_priv, 23308c2ecf20Sopenharmony_ci hard_iface, &idx)) { 23318c2ecf20Sopenharmony_ci i_hardif--; 23328c2ecf20Sopenharmony_ci break; 23338c2ecf20Sopenharmony_ci } 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci rcu_read_unlock(); 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci cb->args[0] = i_hardif; 23398c2ecf20Sopenharmony_ci cb->args[1] = idx; 23408c2ecf20Sopenharmony_ci} 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci/** 23438c2ecf20Sopenharmony_ci * batadv_iv_ogm_neigh_cmp() - compare the metrics of two neighbors 23448c2ecf20Sopenharmony_ci * @neigh1: the first neighbor object of the comparison 23458c2ecf20Sopenharmony_ci * @if_outgoing1: outgoing interface for the first neighbor 23468c2ecf20Sopenharmony_ci * @neigh2: the second neighbor object of the comparison 23478c2ecf20Sopenharmony_ci * @if_outgoing2: outgoing interface for the second neighbor 23488c2ecf20Sopenharmony_ci * 23498c2ecf20Sopenharmony_ci * Return: a value less, equal to or greater than 0 if the metric via neigh1 is 23508c2ecf20Sopenharmony_ci * lower, the same as or higher than the metric via neigh2 23518c2ecf20Sopenharmony_ci */ 23528c2ecf20Sopenharmony_cistatic int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1, 23538c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing1, 23548c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh2, 23558c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing2) 23568c2ecf20Sopenharmony_ci{ 23578c2ecf20Sopenharmony_ci bool ret; 23588c2ecf20Sopenharmony_ci int diff; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci ret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2, 23618c2ecf20Sopenharmony_ci if_outgoing2, &diff); 23628c2ecf20Sopenharmony_ci if (!ret) 23638c2ecf20Sopenharmony_ci return 0; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci return diff; 23668c2ecf20Sopenharmony_ci} 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci/** 23698c2ecf20Sopenharmony_ci * batadv_iv_ogm_neigh_is_sob() - check if neigh1 is similarly good or better 23708c2ecf20Sopenharmony_ci * than neigh2 from the metric prospective 23718c2ecf20Sopenharmony_ci * @neigh1: the first neighbor object of the comparison 23728c2ecf20Sopenharmony_ci * @if_outgoing1: outgoing interface for the first neighbor 23738c2ecf20Sopenharmony_ci * @neigh2: the second neighbor object of the comparison 23748c2ecf20Sopenharmony_ci * @if_outgoing2: outgoing interface for the second neighbor 23758c2ecf20Sopenharmony_ci * 23768c2ecf20Sopenharmony_ci * Return: true if the metric via neigh1 is equally good or better than 23778c2ecf20Sopenharmony_ci * the metric via neigh2, false otherwise. 23788c2ecf20Sopenharmony_ci */ 23798c2ecf20Sopenharmony_cistatic bool 23808c2ecf20Sopenharmony_cibatadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1, 23818c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing1, 23828c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh2, 23838c2ecf20Sopenharmony_ci struct batadv_hard_iface *if_outgoing2) 23848c2ecf20Sopenharmony_ci{ 23858c2ecf20Sopenharmony_ci bool ret; 23868c2ecf20Sopenharmony_ci int diff; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci ret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2, 23898c2ecf20Sopenharmony_ci if_outgoing2, &diff); 23908c2ecf20Sopenharmony_ci if (!ret) 23918c2ecf20Sopenharmony_ci return false; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci ret = diff > -BATADV_TQ_SIMILARITY_THRESHOLD; 23948c2ecf20Sopenharmony_ci return ret; 23958c2ecf20Sopenharmony_ci} 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_cistatic void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface) 23988c2ecf20Sopenharmony_ci{ 23998c2ecf20Sopenharmony_ci /* begin scheduling originator messages on that interface */ 24008c2ecf20Sopenharmony_ci batadv_iv_ogm_schedule(hard_iface); 24018c2ecf20Sopenharmony_ci} 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci/** 24048c2ecf20Sopenharmony_ci * batadv_iv_init_sel_class() - initialize GW selection class 24058c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 24068c2ecf20Sopenharmony_ci */ 24078c2ecf20Sopenharmony_cistatic void batadv_iv_init_sel_class(struct batadv_priv *bat_priv) 24088c2ecf20Sopenharmony_ci{ 24098c2ecf20Sopenharmony_ci /* set default TQ difference threshold to 20 */ 24108c2ecf20Sopenharmony_ci atomic_set(&bat_priv->gw.sel_class, 20); 24118c2ecf20Sopenharmony_ci} 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_cistatic struct batadv_gw_node * 24148c2ecf20Sopenharmony_cibatadv_iv_gw_get_best_gw_node(struct batadv_priv *bat_priv) 24158c2ecf20Sopenharmony_ci{ 24168c2ecf20Sopenharmony_ci struct batadv_neigh_node *router; 24178c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *router_ifinfo; 24188c2ecf20Sopenharmony_ci struct batadv_gw_node *gw_node, *curr_gw = NULL; 24198c2ecf20Sopenharmony_ci u64 max_gw_factor = 0; 24208c2ecf20Sopenharmony_ci u64 tmp_gw_factor = 0; 24218c2ecf20Sopenharmony_ci u8 max_tq = 0; 24228c2ecf20Sopenharmony_ci u8 tq_avg; 24238c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node; 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci rcu_read_lock(); 24268c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) { 24278c2ecf20Sopenharmony_ci orig_node = gw_node->orig_node; 24288c2ecf20Sopenharmony_ci router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); 24298c2ecf20Sopenharmony_ci if (!router) 24308c2ecf20Sopenharmony_ci continue; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci router_ifinfo = batadv_neigh_ifinfo_get(router, 24338c2ecf20Sopenharmony_ci BATADV_IF_DEFAULT); 24348c2ecf20Sopenharmony_ci if (!router_ifinfo) 24358c2ecf20Sopenharmony_ci goto next; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&gw_node->refcount)) 24388c2ecf20Sopenharmony_ci goto next; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci tq_avg = router_ifinfo->bat_iv.tq_avg; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci switch (atomic_read(&bat_priv->gw.sel_class)) { 24438c2ecf20Sopenharmony_ci case 1: /* fast connection */ 24448c2ecf20Sopenharmony_ci tmp_gw_factor = tq_avg * tq_avg; 24458c2ecf20Sopenharmony_ci tmp_gw_factor *= gw_node->bandwidth_down; 24468c2ecf20Sopenharmony_ci tmp_gw_factor *= 100 * 100; 24478c2ecf20Sopenharmony_ci tmp_gw_factor >>= 18; 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci if (tmp_gw_factor > max_gw_factor || 24508c2ecf20Sopenharmony_ci (tmp_gw_factor == max_gw_factor && 24518c2ecf20Sopenharmony_ci tq_avg > max_tq)) { 24528c2ecf20Sopenharmony_ci if (curr_gw) 24538c2ecf20Sopenharmony_ci batadv_gw_node_put(curr_gw); 24548c2ecf20Sopenharmony_ci curr_gw = gw_node; 24558c2ecf20Sopenharmony_ci kref_get(&curr_gw->refcount); 24568c2ecf20Sopenharmony_ci } 24578c2ecf20Sopenharmony_ci break; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci default: /* 2: stable connection (use best statistic) 24608c2ecf20Sopenharmony_ci * 3: fast-switch (use best statistic but change as 24618c2ecf20Sopenharmony_ci * soon as a better gateway appears) 24628c2ecf20Sopenharmony_ci * XX: late-switch (use best statistic but change as 24638c2ecf20Sopenharmony_ci * soon as a better gateway appears which has 24648c2ecf20Sopenharmony_ci * $routing_class more tq points) 24658c2ecf20Sopenharmony_ci */ 24668c2ecf20Sopenharmony_ci if (tq_avg > max_tq) { 24678c2ecf20Sopenharmony_ci if (curr_gw) 24688c2ecf20Sopenharmony_ci batadv_gw_node_put(curr_gw); 24698c2ecf20Sopenharmony_ci curr_gw = gw_node; 24708c2ecf20Sopenharmony_ci kref_get(&curr_gw->refcount); 24718c2ecf20Sopenharmony_ci } 24728c2ecf20Sopenharmony_ci break; 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci if (tq_avg > max_tq) 24768c2ecf20Sopenharmony_ci max_tq = tq_avg; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci if (tmp_gw_factor > max_gw_factor) 24798c2ecf20Sopenharmony_ci max_gw_factor = tmp_gw_factor; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci batadv_gw_node_put(gw_node); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_cinext: 24848c2ecf20Sopenharmony_ci batadv_neigh_node_put(router); 24858c2ecf20Sopenharmony_ci if (router_ifinfo) 24868c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(router_ifinfo); 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci rcu_read_unlock(); 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci return curr_gw; 24918c2ecf20Sopenharmony_ci} 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_cistatic bool batadv_iv_gw_is_eligible(struct batadv_priv *bat_priv, 24948c2ecf20Sopenharmony_ci struct batadv_orig_node *curr_gw_orig, 24958c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node) 24968c2ecf20Sopenharmony_ci{ 24978c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *router_orig_ifinfo = NULL; 24988c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *router_gw_ifinfo = NULL; 24998c2ecf20Sopenharmony_ci struct batadv_neigh_node *router_gw = NULL; 25008c2ecf20Sopenharmony_ci struct batadv_neigh_node *router_orig = NULL; 25018c2ecf20Sopenharmony_ci u8 gw_tq_avg, orig_tq_avg; 25028c2ecf20Sopenharmony_ci bool ret = false; 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci /* dynamic re-election is performed only on fast or late switch */ 25058c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->gw.sel_class) <= 2) 25068c2ecf20Sopenharmony_ci return false; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT); 25098c2ecf20Sopenharmony_ci if (!router_gw) { 25108c2ecf20Sopenharmony_ci ret = true; 25118c2ecf20Sopenharmony_ci goto out; 25128c2ecf20Sopenharmony_ci } 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci router_gw_ifinfo = batadv_neigh_ifinfo_get(router_gw, 25158c2ecf20Sopenharmony_ci BATADV_IF_DEFAULT); 25168c2ecf20Sopenharmony_ci if (!router_gw_ifinfo) { 25178c2ecf20Sopenharmony_ci ret = true; 25188c2ecf20Sopenharmony_ci goto out; 25198c2ecf20Sopenharmony_ci } 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); 25228c2ecf20Sopenharmony_ci if (!router_orig) 25238c2ecf20Sopenharmony_ci goto out; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci router_orig_ifinfo = batadv_neigh_ifinfo_get(router_orig, 25268c2ecf20Sopenharmony_ci BATADV_IF_DEFAULT); 25278c2ecf20Sopenharmony_ci if (!router_orig_ifinfo) 25288c2ecf20Sopenharmony_ci goto out; 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci gw_tq_avg = router_gw_ifinfo->bat_iv.tq_avg; 25318c2ecf20Sopenharmony_ci orig_tq_avg = router_orig_ifinfo->bat_iv.tq_avg; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci /* the TQ value has to be better */ 25348c2ecf20Sopenharmony_ci if (orig_tq_avg < gw_tq_avg) 25358c2ecf20Sopenharmony_ci goto out; 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci /* if the routing class is greater than 3 the value tells us how much 25388c2ecf20Sopenharmony_ci * greater the TQ value of the new gateway must be 25398c2ecf20Sopenharmony_ci */ 25408c2ecf20Sopenharmony_ci if ((atomic_read(&bat_priv->gw.sel_class) > 3) && 25418c2ecf20Sopenharmony_ci (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw.sel_class))) 25428c2ecf20Sopenharmony_ci goto out; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 25458c2ecf20Sopenharmony_ci "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n", 25468c2ecf20Sopenharmony_ci gw_tq_avg, orig_tq_avg); 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci ret = true; 25498c2ecf20Sopenharmony_ciout: 25508c2ecf20Sopenharmony_ci if (router_gw_ifinfo) 25518c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(router_gw_ifinfo); 25528c2ecf20Sopenharmony_ci if (router_orig_ifinfo) 25538c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(router_orig_ifinfo); 25548c2ecf20Sopenharmony_ci if (router_gw) 25558c2ecf20Sopenharmony_ci batadv_neigh_node_put(router_gw); 25568c2ecf20Sopenharmony_ci if (router_orig) 25578c2ecf20Sopenharmony_ci batadv_neigh_node_put(router_orig); 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci return ret; 25608c2ecf20Sopenharmony_ci} 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS 25638c2ecf20Sopenharmony_ci/* fails if orig_node has no router */ 25648c2ecf20Sopenharmony_cistatic int batadv_iv_gw_write_buffer_text(struct batadv_priv *bat_priv, 25658c2ecf20Sopenharmony_ci struct seq_file *seq, 25668c2ecf20Sopenharmony_ci const struct batadv_gw_node *gw_node) 25678c2ecf20Sopenharmony_ci{ 25688c2ecf20Sopenharmony_ci struct batadv_gw_node *curr_gw; 25698c2ecf20Sopenharmony_ci struct batadv_neigh_node *router; 25708c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *router_ifinfo = NULL; 25718c2ecf20Sopenharmony_ci int ret = -1; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); 25748c2ecf20Sopenharmony_ci if (!router) 25758c2ecf20Sopenharmony_ci goto out; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); 25788c2ecf20Sopenharmony_ci if (!router_ifinfo) 25798c2ecf20Sopenharmony_ci goto out; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci curr_gw = batadv_gw_get_selected_gw_node(bat_priv); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n", 25848c2ecf20Sopenharmony_ci (curr_gw == gw_node ? "=>" : " "), 25858c2ecf20Sopenharmony_ci gw_node->orig_node->orig, 25868c2ecf20Sopenharmony_ci router_ifinfo->bat_iv.tq_avg, router->addr, 25878c2ecf20Sopenharmony_ci router->if_incoming->net_dev->name, 25888c2ecf20Sopenharmony_ci gw_node->bandwidth_down / 10, 25898c2ecf20Sopenharmony_ci gw_node->bandwidth_down % 10, 25908c2ecf20Sopenharmony_ci gw_node->bandwidth_up / 10, 25918c2ecf20Sopenharmony_ci gw_node->bandwidth_up % 10); 25928c2ecf20Sopenharmony_ci ret = seq_has_overflowed(seq) ? -1 : 0; 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci if (curr_gw) 25958c2ecf20Sopenharmony_ci batadv_gw_node_put(curr_gw); 25968c2ecf20Sopenharmony_ciout: 25978c2ecf20Sopenharmony_ci if (router_ifinfo) 25988c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(router_ifinfo); 25998c2ecf20Sopenharmony_ci if (router) 26008c2ecf20Sopenharmony_ci batadv_neigh_node_put(router); 26018c2ecf20Sopenharmony_ci return ret; 26028c2ecf20Sopenharmony_ci} 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_cistatic void batadv_iv_gw_print(struct batadv_priv *bat_priv, 26058c2ecf20Sopenharmony_ci struct seq_file *seq) 26068c2ecf20Sopenharmony_ci{ 26078c2ecf20Sopenharmony_ci struct batadv_gw_node *gw_node; 26088c2ecf20Sopenharmony_ci int gw_count = 0; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci seq_puts(seq, 26118c2ecf20Sopenharmony_ci " Gateway (#/255) Nexthop [outgoingIF]: advertised uplink bandwidth\n"); 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci rcu_read_lock(); 26148c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) { 26158c2ecf20Sopenharmony_ci /* fails if orig_node has no router */ 26168c2ecf20Sopenharmony_ci if (batadv_iv_gw_write_buffer_text(bat_priv, seq, gw_node) < 0) 26178c2ecf20Sopenharmony_ci continue; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci gw_count++; 26208c2ecf20Sopenharmony_ci } 26218c2ecf20Sopenharmony_ci rcu_read_unlock(); 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci if (gw_count == 0) 26248c2ecf20Sopenharmony_ci seq_puts(seq, "No gateways in range ...\n"); 26258c2ecf20Sopenharmony_ci} 26268c2ecf20Sopenharmony_ci#endif 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci/** 26298c2ecf20Sopenharmony_ci * batadv_iv_gw_dump_entry() - Dump a gateway into a message 26308c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 26318c2ecf20Sopenharmony_ci * @portid: Port making netlink request 26328c2ecf20Sopenharmony_ci * @cb: Control block containing additional options 26338c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information 26348c2ecf20Sopenharmony_ci * @gw_node: Gateway to be dumped 26358c2ecf20Sopenharmony_ci * 26368c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success 26378c2ecf20Sopenharmony_ci */ 26388c2ecf20Sopenharmony_cistatic int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, 26398c2ecf20Sopenharmony_ci struct netlink_callback *cb, 26408c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv, 26418c2ecf20Sopenharmony_ci struct batadv_gw_node *gw_node) 26428c2ecf20Sopenharmony_ci{ 26438c2ecf20Sopenharmony_ci struct batadv_neigh_ifinfo *router_ifinfo = NULL; 26448c2ecf20Sopenharmony_ci struct batadv_neigh_node *router; 26458c2ecf20Sopenharmony_ci struct batadv_gw_node *curr_gw = NULL; 26468c2ecf20Sopenharmony_ci int ret = 0; 26478c2ecf20Sopenharmony_ci void *hdr; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); 26508c2ecf20Sopenharmony_ci if (!router) 26518c2ecf20Sopenharmony_ci goto out; 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); 26548c2ecf20Sopenharmony_ci if (!router_ifinfo) 26558c2ecf20Sopenharmony_ci goto out; 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci curr_gw = batadv_gw_get_selected_gw_node(bat_priv); 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq, 26608c2ecf20Sopenharmony_ci &batadv_netlink_family, NLM_F_MULTI, 26618c2ecf20Sopenharmony_ci BATADV_CMD_GET_GATEWAYS); 26628c2ecf20Sopenharmony_ci if (!hdr) { 26638c2ecf20Sopenharmony_ci ret = -ENOBUFS; 26648c2ecf20Sopenharmony_ci goto out; 26658c2ecf20Sopenharmony_ci } 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci genl_dump_check_consistent(cb, hdr); 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci ret = -EMSGSIZE; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci if (curr_gw == gw_node) 26728c2ecf20Sopenharmony_ci if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) { 26738c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 26748c2ecf20Sopenharmony_ci goto out; 26758c2ecf20Sopenharmony_ci } 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, 26788c2ecf20Sopenharmony_ci gw_node->orig_node->orig) || 26798c2ecf20Sopenharmony_ci nla_put_u8(msg, BATADV_ATTR_TQ, router_ifinfo->bat_iv.tq_avg) || 26808c2ecf20Sopenharmony_ci nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN, 26818c2ecf20Sopenharmony_ci router->addr) || 26828c2ecf20Sopenharmony_ci nla_put_string(msg, BATADV_ATTR_HARD_IFNAME, 26838c2ecf20Sopenharmony_ci router->if_incoming->net_dev->name) || 26848c2ecf20Sopenharmony_ci nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN, 26858c2ecf20Sopenharmony_ci gw_node->bandwidth_down) || 26868c2ecf20Sopenharmony_ci nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP, 26878c2ecf20Sopenharmony_ci gw_node->bandwidth_up)) { 26888c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 26898c2ecf20Sopenharmony_ci goto out; 26908c2ecf20Sopenharmony_ci } 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 26938c2ecf20Sopenharmony_ci ret = 0; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ciout: 26968c2ecf20Sopenharmony_ci if (curr_gw) 26978c2ecf20Sopenharmony_ci batadv_gw_node_put(curr_gw); 26988c2ecf20Sopenharmony_ci if (router_ifinfo) 26998c2ecf20Sopenharmony_ci batadv_neigh_ifinfo_put(router_ifinfo); 27008c2ecf20Sopenharmony_ci if (router) 27018c2ecf20Sopenharmony_ci batadv_neigh_node_put(router); 27028c2ecf20Sopenharmony_ci return ret; 27038c2ecf20Sopenharmony_ci} 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci/** 27068c2ecf20Sopenharmony_ci * batadv_iv_gw_dump() - Dump gateways into a message 27078c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into 27088c2ecf20Sopenharmony_ci * @cb: Control block containing additional options 27098c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information 27108c2ecf20Sopenharmony_ci */ 27118c2ecf20Sopenharmony_cistatic void batadv_iv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb, 27128c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv) 27138c2ecf20Sopenharmony_ci{ 27148c2ecf20Sopenharmony_ci int portid = NETLINK_CB(cb->skb).portid; 27158c2ecf20Sopenharmony_ci struct batadv_gw_node *gw_node; 27168c2ecf20Sopenharmony_ci int idx_skip = cb->args[0]; 27178c2ecf20Sopenharmony_ci int idx = 0; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci spin_lock_bh(&bat_priv->gw.list_lock); 27208c2ecf20Sopenharmony_ci cb->seq = bat_priv->gw.generation << 1 | 1; 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci hlist_for_each_entry(gw_node, &bat_priv->gw.gateway_list, list) { 27238c2ecf20Sopenharmony_ci if (idx++ < idx_skip) 27248c2ecf20Sopenharmony_ci continue; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci if (batadv_iv_gw_dump_entry(msg, portid, cb, bat_priv, 27278c2ecf20Sopenharmony_ci gw_node)) { 27288c2ecf20Sopenharmony_ci idx_skip = idx - 1; 27298c2ecf20Sopenharmony_ci goto unlock; 27308c2ecf20Sopenharmony_ci } 27318c2ecf20Sopenharmony_ci } 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci idx_skip = idx; 27348c2ecf20Sopenharmony_ciunlock: 27358c2ecf20Sopenharmony_ci spin_unlock_bh(&bat_priv->gw.list_lock); 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci cb->args[0] = idx_skip; 27388c2ecf20Sopenharmony_ci} 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_cistatic struct batadv_algo_ops batadv_batman_iv __read_mostly = { 27418c2ecf20Sopenharmony_ci .name = "BATMAN_IV", 27428c2ecf20Sopenharmony_ci .iface = { 27438c2ecf20Sopenharmony_ci .enable = batadv_iv_ogm_iface_enable, 27448c2ecf20Sopenharmony_ci .enabled = batadv_iv_iface_enabled, 27458c2ecf20Sopenharmony_ci .disable = batadv_iv_ogm_iface_disable, 27468c2ecf20Sopenharmony_ci .update_mac = batadv_iv_ogm_iface_update_mac, 27478c2ecf20Sopenharmony_ci .primary_set = batadv_iv_ogm_primary_iface_set, 27488c2ecf20Sopenharmony_ci }, 27498c2ecf20Sopenharmony_ci .neigh = { 27508c2ecf20Sopenharmony_ci .cmp = batadv_iv_ogm_neigh_cmp, 27518c2ecf20Sopenharmony_ci .is_similar_or_better = batadv_iv_ogm_neigh_is_sob, 27528c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS 27538c2ecf20Sopenharmony_ci .print = batadv_iv_neigh_print, 27548c2ecf20Sopenharmony_ci#endif 27558c2ecf20Sopenharmony_ci .dump = batadv_iv_ogm_neigh_dump, 27568c2ecf20Sopenharmony_ci }, 27578c2ecf20Sopenharmony_ci .orig = { 27588c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS 27598c2ecf20Sopenharmony_ci .print = batadv_iv_ogm_orig_print, 27608c2ecf20Sopenharmony_ci#endif 27618c2ecf20Sopenharmony_ci .dump = batadv_iv_ogm_orig_dump, 27628c2ecf20Sopenharmony_ci }, 27638c2ecf20Sopenharmony_ci .gw = { 27648c2ecf20Sopenharmony_ci .init_sel_class = batadv_iv_init_sel_class, 27658c2ecf20Sopenharmony_ci .get_best_gw_node = batadv_iv_gw_get_best_gw_node, 27668c2ecf20Sopenharmony_ci .is_eligible = batadv_iv_gw_is_eligible, 27678c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS 27688c2ecf20Sopenharmony_ci .print = batadv_iv_gw_print, 27698c2ecf20Sopenharmony_ci#endif 27708c2ecf20Sopenharmony_ci .dump = batadv_iv_gw_dump, 27718c2ecf20Sopenharmony_ci }, 27728c2ecf20Sopenharmony_ci}; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci/** 27758c2ecf20Sopenharmony_ci * batadv_iv_init() - B.A.T.M.A.N. IV initialization function 27768c2ecf20Sopenharmony_ci * 27778c2ecf20Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 27788c2ecf20Sopenharmony_ci */ 27798c2ecf20Sopenharmony_ciint __init batadv_iv_init(void) 27808c2ecf20Sopenharmony_ci{ 27818c2ecf20Sopenharmony_ci int ret; 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci /* batman originator packet */ 27848c2ecf20Sopenharmony_ci ret = batadv_recv_handler_register(BATADV_IV_OGM, 27858c2ecf20Sopenharmony_ci batadv_iv_ogm_receive); 27868c2ecf20Sopenharmony_ci if (ret < 0) 27878c2ecf20Sopenharmony_ci goto out; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci ret = batadv_algo_register(&batadv_batman_iv); 27908c2ecf20Sopenharmony_ci if (ret < 0) 27918c2ecf20Sopenharmony_ci goto handler_unregister; 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci goto out; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_cihandler_unregister: 27968c2ecf20Sopenharmony_ci batadv_recv_handler_unregister(BATADV_IV_OGM); 27978c2ecf20Sopenharmony_ciout: 27988c2ecf20Sopenharmony_ci return ret; 27998c2ecf20Sopenharmony_ci} 2800