File Index
Files and directories
Sign in
FILE

bat_v_ogm.c

File preview with syntax highlighting.

linux-6.19.14/net/batman-adv/bat_v_ogm.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (C) B.A.T.M.A.N. contributors:
   3 *
   4 * Antonio Quartulli
   5 */
   6
   7#include "bat_v_ogm.h"
   8#include "main.h"
   9
  10#include <linux/atomic.h>
  11#include <linux/byteorder/generic.h>
  12#include <linux/container_of.h>
  13#include <linux/errno.h>
  14#include <linux/etherdevice.h>
  15#include <linux/gfp.h>
  16#include <linux/if_ether.h>
  17#include <linux/jiffies.h>
  18#include <linux/kref.h>
  19#include <linux/list.h>
  20#include <linux/lockdep.h>
  21#include <linux/minmax.h>
  22#include <linux/mutex.h>
  23#include <linux/netdevice.h>
  24#include <linux/random.h>
  25#include <linux/rcupdate.h>
  26#include <linux/skbuff.h>
  27#include <linux/slab.h>
  28#include <linux/spinlock.h>
  29#include <linux/stddef.h>
  30#include <linux/string.h>
  31#include <linux/types.h>
  32#include <linux/workqueue.h>
  33#include <uapi/linux/batadv_packet.h>
  34
  35#include "hard-interface.h"
  36#include "hash.h"
  37#include "log.h"
  38#include "originator.h"
  39#include "routing.h"
  40#include "send.h"
  41#include "translation-table.h"
  42#include "tvlv.h"
  43
  44/**
  45 * batadv_v_ogm_orig_get() - retrieve and possibly create an originator node
  46 * @bat_priv: the bat priv with all the mesh interface information
  47 * @addr: the address of the originator
  48 *
  49 * Return: the orig_node corresponding to the specified address. If such an
  50 * object does not exist, it is allocated here. In case of allocation failure
  51 * returns NULL.
  52 */
  53struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
  54					       const u8 *addr)
  55{
  56	struct batadv_orig_node *orig_node;
  57	int hash_added;
  58
  59	orig_node = batadv_orig_hash_find(bat_priv, addr);
  60	if (orig_node)
  61		return orig_node;
  62
  63	orig_node = batadv_orig_node_new(bat_priv, addr);
  64	if (!orig_node)
  65		return NULL;
  66
  67	kref_get(&orig_node->refcount);
  68	hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
  69				     batadv_choose_orig, orig_node,
  70				     &orig_node->hash_entry);
  71	if (hash_added != 0) {
  72		/* remove refcnt for newly created orig_node and hash entry */
  73		batadv_orig_node_put(orig_node);
  74		batadv_orig_node_put(orig_node);
  75		orig_node = NULL;
  76	}
  77
  78	return orig_node;
  79}
  80
  81/**
  82 * batadv_v_ogm_start_queue_timer() - restart the OGM aggregation timer
  83 * @hard_iface: the interface to use to send the OGM
  84 */
  85static void batadv_v_ogm_start_queue_timer(struct batadv_hard_iface *hard_iface)
  86{
  87	unsigned int msecs = BATADV_MAX_AGGREGATION_MS * 1000;
  88
  89	/* msecs * [0.9, 1.1] */
  90	msecs += get_random_u32_below(msecs / 5) - (msecs / 10);
  91	queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.aggr_wq,
  92			   msecs_to_jiffies(msecs / 1000));
  93}
  94
  95/**
  96 * batadv_v_ogm_start_timer() - restart the OGM sending timer
  97 * @bat_priv: the bat priv with all the mesh interface information
  98 */
  99static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
 100{
 101	unsigned long msecs;
 102	/* this function may be invoked in different contexts (ogm rescheduling
 103	 * or hard_iface activation), but the work timer should not be reset
 104	 */
 105	if (delayed_work_pending(&bat_priv->bat_v.ogm_wq))
 106		return;
 107
 108	msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
 109	msecs += get_random_u32_below(2 * BATADV_JITTER);
 110	queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq,
 111			   msecs_to_jiffies(msecs));
 112}
 113
 114/**
 115 * batadv_v_ogm_send_to_if() - send a batman ogm using a given interface
 116 * @skb: the OGM to send
 117 * @hard_iface: the interface to use to send the OGM
 118 */
 119static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
 120				    struct batadv_hard_iface *hard_iface)
 121{
 122	struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
 123
 124	if (hard_iface->if_status != BATADV_IF_ACTIVE) {
 125		kfree_skb(skb);
 126		return;
 127	}
 128
 129	batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
 130	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
 131			   skb->len + ETH_HLEN);
 132
 133	batadv_send_broadcast_skb(skb, hard_iface);
 134}
 135
 136/**
 137 * batadv_v_ogm_len() - OGMv2 packet length
 138 * @skb: the OGM to check
 139 *
 140 * Return: Length of the given OGMv2 packet, including tvlv length, excluding
 141 * ethernet header length.
 142 */
 143static unsigned int batadv_v_ogm_len(struct sk_buff *skb)
 144{
 145	struct batadv_ogm2_packet *ogm_packet;
 146
 147	ogm_packet = (struct batadv_ogm2_packet *)skb->data;
 148	return BATADV_OGM2_HLEN + ntohs(ogm_packet->tvlv_len);
 149}
 150
 151/**
 152 * batadv_v_ogm_queue_left() - check if given OGM still fits aggregation queue
 153 * @skb: the OGM to check
 154 * @hard_iface: the interface to use to send the OGM
 155 *
 156 * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
 157 *
 158 * Return: True, if the given OGMv2 packet still fits, false otherwise.
 159 */
 160static bool batadv_v_ogm_queue_left(struct sk_buff *skb,
 161				    struct batadv_hard_iface *hard_iface)
 162{
 163	unsigned int max = min_t(unsigned int, hard_iface->net_dev->mtu,
 164				 BATADV_MAX_AGGREGATION_BYTES);
 165	unsigned int ogm_len = batadv_v_ogm_len(skb);
 166
 167	lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
 168
 169	return hard_iface->bat_v.aggr_len + ogm_len <= max;
 170}
 171
 172/**
 173 * batadv_v_ogm_aggr_list_free - free all elements in an aggregation queue
 174 * @hard_iface: the interface holding the aggregation queue
 175 *
 176 * Empties the OGMv2 aggregation queue and frees all the skbs it contains.
 177 *
 178 * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
 179 */
 180static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
 181{
 182	lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
 183
 184	__skb_queue_purge(&hard_iface->bat_v.aggr_list);
 185	hard_iface->bat_v.aggr_len = 0;
 186}
 187
 188/**
 189 * batadv_v_ogm_aggr_send() - flush & send aggregation queue
 190 * @hard_iface: the interface with the aggregation queue to flush
 191 *
 192 * Aggregates all OGMv2 packets currently in the aggregation queue into a
 193 * single OGMv2 packet and transmits this aggregate.
 194 *
 195 * The aggregation queue is empty after this call.
 196 *
 197 * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
 198 */
 199static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
 200{
 201	unsigned int aggr_len = hard_iface->bat_v.aggr_len;
 202	struct sk_buff *skb_aggr;
 203	unsigned int ogm_len;
 204	struct sk_buff *skb;
 205
 206	lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
 207
 208	if (!aggr_len)
 209		return;
 210
 211	skb_aggr = dev_alloc_skb(aggr_len + ETH_HLEN + NET_IP_ALIGN);
 212	if (!skb_aggr) {
 213		batadv_v_ogm_aggr_list_free(hard_iface);
 214		return;
 215	}
 216
 217	skb_reserve(skb_aggr, ETH_HLEN + NET_IP_ALIGN);
 218	skb_reset_network_header(skb_aggr);
 219
 220	while ((skb = __skb_dequeue(&hard_iface->bat_v.aggr_list))) {
 221		hard_iface->bat_v.aggr_len -= batadv_v_ogm_len(skb);
 222
 223		ogm_len = batadv_v_ogm_len(skb);
 224		skb_put_data(skb_aggr, skb->data, ogm_len);
 225
 226		consume_skb(skb);
 227	}
 228
 229	batadv_v_ogm_send_to_if(skb_aggr, hard_iface);
 230}
 231
 232/**
 233 * batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface
 234 * @skb: the OGM to queue
 235 * @hard_iface: the interface to queue the OGM on
 236 */
 237static void batadv_v_ogm_queue_on_if(struct sk_buff *skb,
 238				     struct batadv_hard_iface *hard_iface)
 239{
 240	struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
 241
 242	if (!atomic_read(&bat_priv->aggregated_ogms)) {
 243		batadv_v_ogm_send_to_if(skb, hard_iface);
 244		return;
 245	}
 246
 247	spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
 248	if (!batadv_v_ogm_queue_left(skb, hard_iface))
 249		batadv_v_ogm_aggr_send(hard_iface);
 250
 251	hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb);
 252	__skb_queue_tail(&hard_iface->bat_v.aggr_list, skb);
 253	spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
 254}
 255
 256/**
 257 * batadv_v_ogm_send_meshif() - periodic worker broadcasting the own OGM
 258 * @bat_priv: the bat priv with all the mesh interface information
 259 */
 260static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
 261{
 262	struct batadv_hard_iface *hard_iface;
 263	struct batadv_ogm2_packet *ogm_packet;
 264	struct sk_buff *skb, *skb_tmp;
 265	unsigned char *ogm_buff;
 266	struct list_head *iter;
 267	int ogm_buff_len;
 268	u16 tvlv_len = 0;
 269	int ret;
 270
 271	lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex);
 272
 273	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
 274		goto out;
 275
 276	ogm_buff = bat_priv->bat_v.ogm_buff;
 277	ogm_buff_len = bat_priv->bat_v.ogm_buff_len;
 278	/* tt changes have to be committed before the tvlv data is
 279	 * appended as it may alter the tt tvlv container
 280	 */
 281	batadv_tt_local_commit_changes(bat_priv);
 282	tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
 283						    &ogm_buff_len,
 284						    BATADV_OGM2_HLEN);
 285
 286	bat_priv->bat_v.ogm_buff = ogm_buff;
 287	bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
 288
 289	skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
 290	if (!skb)
 291		goto reschedule;
 292
 293	skb_reserve(skb, ETH_HLEN);
 294	skb_put_data(skb, ogm_buff, ogm_buff_len);
 295
 296	ogm_packet = (struct batadv_ogm2_packet *)skb->data;
 297	ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
 298	atomic_inc(&bat_priv->bat_v.ogm_seqno);
 299	ogm_packet->tvlv_len = htons(tvlv_len);
 300
 301	/* broadcast on every interface */
 302	rcu_read_lock();
 303	netdev_for_each_lower_private_rcu(bat_priv->mesh_iface, hard_iface, iter) {
 304		if (!kref_get_unless_zero(&hard_iface->refcount))
 305			continue;
 306
 307		ret = batadv_hardif_no_broadcast(hard_iface, NULL, NULL);
 308		if (ret) {
 309			char *type;
 310
 311			switch (ret) {
 312			case BATADV_HARDIF_BCAST_NORECIPIENT:
 313				type = "no neighbor";
 314				break;
 315			case BATADV_HARDIF_BCAST_DUPFWD:
 316				type = "single neighbor is source";
 317				break;
 318			case BATADV_HARDIF_BCAST_DUPORIG:
 319				type = "single neighbor is originator";
 320				break;
 321			default:
 322				type = "unknown";
 323			}
 324
 325			batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 from ourselves on %s suppressed: %s\n",
 326				   hard_iface->net_dev->name, type);
 327
 328			batadv_hardif_put(hard_iface);
 329			continue;
 330		}
 331
 332		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 333			   "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
 334			   ogm_packet->orig, ntohl(ogm_packet->seqno),
 335			   ntohl(ogm_packet->throughput), ogm_packet->ttl,
 336			   hard_iface->net_dev->name,
 337			   hard_iface->net_dev->dev_addr);
 338
 339		/* this skb gets consumed by batadv_v_ogm_send_to_if() */
 340		skb_tmp = skb_clone(skb, GFP_ATOMIC);
 341		if (!skb_tmp) {
 342			batadv_hardif_put(hard_iface);
 343			break;
 344		}
 345
 346		batadv_v_ogm_queue_on_if(skb_tmp, hard_iface);
 347		batadv_hardif_put(hard_iface);
 348	}
 349	rcu_read_unlock();
 350
 351	consume_skb(skb);
 352
 353reschedule:
 354	batadv_v_ogm_start_timer(bat_priv);
 355out:
 356	return;
 357}
 358
 359/**
 360 * batadv_v_ogm_send() - periodic worker broadcasting the own OGM
 361 * @work: work queue item
 362 */
 363static void batadv_v_ogm_send(struct work_struct *work)
 364{
 365	struct batadv_priv_bat_v *bat_v;
 366	struct batadv_priv *bat_priv;
 367
 368	bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
 369	bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
 370
 371	mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
 372	batadv_v_ogm_send_meshif(bat_priv);
 373	mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
 374}
 375
 376/**
 377 * batadv_v_ogm_aggr_work() - OGM queue periodic task per interface
 378 * @work: work queue item
 379 *
 380 * Emits aggregated OGM messages in regular intervals.
 381 */
 382void batadv_v_ogm_aggr_work(struct work_struct *work)
 383{
 384	struct batadv_hard_iface_bat_v *batv;
 385	struct batadv_hard_iface *hard_iface;
 386
 387	batv = container_of(work, struct batadv_hard_iface_bat_v, aggr_wq.work);
 388	hard_iface = container_of(batv, struct batadv_hard_iface, bat_v);
 389
 390	spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
 391	batadv_v_ogm_aggr_send(hard_iface);
 392	spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
 393
 394	batadv_v_ogm_start_queue_timer(hard_iface);
 395}
 396
 397/**
 398 * batadv_v_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. V
 399 * @hard_iface: the interface to prepare
 400 *
 401 * Takes care of scheduling its own OGM sending routine for this interface.
 402 *
 403 * Return: 0 on success or a negative error code otherwise
 404 */
 405int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
 406{
 407	struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
 408
 409	batadv_v_ogm_start_queue_timer(hard_iface);
 410	batadv_v_ogm_start_timer(bat_priv);
 411
 412	return 0;
 413}
 414
 415/**
 416 * batadv_v_ogm_iface_disable() - release OGM interface private resources
 417 * @hard_iface: interface for which the resources have to be released
 418 */
 419void batadv_v_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
 420{
 421	cancel_delayed_work_sync(&hard_iface->bat_v.aggr_wq);
 422
 423	spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
 424	batadv_v_ogm_aggr_list_free(hard_iface);
 425	spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
 426}
 427
 428/**
 429 * batadv_v_ogm_primary_iface_set() - set a new primary interface
 430 * @primary_iface: the new primary interface
 431 */
 432void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface)
 433{
 434	struct batadv_priv *bat_priv = netdev_priv(primary_iface->mesh_iface);
 435	struct batadv_ogm2_packet *ogm_packet;
 436
 437	mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
 438	if (!bat_priv->bat_v.ogm_buff)
 439		goto unlock;
 440
 441	ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
 442	ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
 443
 444unlock:
 445	mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
 446}
 447
 448/**
 449 * batadv_v_forward_penalty() - apply a penalty to the throughput metric
 450 *  forwarded with B.A.T.M.A.N. V OGMs
 451 * @bat_priv: the bat priv with all the mesh interface information
 452 * @if_incoming: the interface where the OGM has been received
 453 * @if_outgoing: the interface where the OGM has to be forwarded to
 454 * @throughput: the current throughput
 455 *
 456 * Apply a penalty on the current throughput metric value based on the
 457 * characteristic of the interface where the OGM has been received.
 458 *
 459 * Initially the per hardif hop penalty is applied to the throughput. After
 460 * that the return value is then computed as follows:
 461 * - throughput * 50%          if the incoming and outgoing interface are the
 462 *                             same WiFi interface and the throughput is above
 463 *                             1MBit/s
 464 * - throughput                if the outgoing interface is the default
 465 *                             interface (i.e. this OGM is processed for the
 466 *                             internal table and not forwarded)
 467 * - throughput * node hop penalty  otherwise
 468 *
 469 * Return: the penalised throughput metric.
 470 */
 471static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv,
 472				    struct batadv_hard_iface *if_incoming,
 473				    struct batadv_hard_iface *if_outgoing,
 474				    u32 throughput)
 475{
 476	int if_hop_penalty = atomic_read(&if_incoming->hop_penalty);
 477	int hop_penalty = atomic_read(&bat_priv->hop_penalty);
 478	int hop_penalty_max = BATADV_TQ_MAX_VALUE;
 479
 480	/* Apply per hardif hop penalty */
 481	throughput = throughput * (hop_penalty_max - if_hop_penalty) /
 482		     hop_penalty_max;
 483
 484	/* Don't apply hop penalty in default originator table. */
 485	if (if_outgoing == BATADV_IF_DEFAULT)
 486		return throughput;
 487
 488	/* Forwarding on the same WiFi interface cuts the throughput in half
 489	 * due to the store & forward characteristics of WIFI.
 490	 * Very low throughput values are the exception.
 491	 */
 492	if (throughput > 10 &&
 493	    if_incoming == if_outgoing &&
 494	    !(if_incoming->bat_v.flags & BATADV_FULL_DUPLEX))
 495		return throughput / 2;
 496
 497	/* hop penalty of 255 equals 100% */
 498	return throughput * (hop_penalty_max - hop_penalty) / hop_penalty_max;
 499}
 500
 501/**
 502 * batadv_v_ogm_forward() - check conditions and forward an OGM to the given
 503 *  outgoing interface
 504 * @bat_priv: the bat priv with all the mesh interface information
 505 * @ogm_received: previously received OGM to be forwarded
 506 * @orig_node: the originator which has been updated
 507 * @neigh_node: the neigh_node through with the OGM has been received
 508 * @if_incoming: the interface on which this OGM was received on
 509 * @if_outgoing: the interface to which the OGM has to be forwarded to
 510 *
 511 * Forward an OGM to an interface after having altered the throughput metric and
 512 * the TTL value contained in it. The original OGM isn't modified.
 513 */
 514static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
 515				 const struct batadv_ogm2_packet *ogm_received,
 516				 struct batadv_orig_node *orig_node,
 517				 struct batadv_neigh_node *neigh_node,
 518				 struct batadv_hard_iface *if_incoming,
 519				 struct batadv_hard_iface *if_outgoing)
 520{
 521	struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
 522	struct batadv_orig_ifinfo *orig_ifinfo = NULL;
 523	struct batadv_neigh_node *router = NULL;
 524	struct batadv_ogm2_packet *ogm_forward;
 525	unsigned char *skb_buff;
 526	struct sk_buff *skb;
 527	size_t packet_len;
 528	u16 tvlv_len;
 529
 530	/* only forward for specific interfaces, not for the default one. */
 531	if (if_outgoing == BATADV_IF_DEFAULT)
 532		goto out;
 533
 534	orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
 535	if (!orig_ifinfo)
 536		goto out;
 537
 538	/* acquire possibly updated router */
 539	router = batadv_orig_router_get(orig_node, if_outgoing);
 540
 541	/* strict rule: forward packets coming from the best next hop only */
 542	if (neigh_node != router)
 543		goto out;
 544
 545	/* don't forward the same seqno twice on one interface */
 546	if (orig_ifinfo->last_seqno_forwarded == ntohl(ogm_received->seqno))
 547		goto out;
 548
 549	orig_ifinfo->last_seqno_forwarded = ntohl(ogm_received->seqno);
 550
 551	if (ogm_received->ttl <= 1) {
 552		batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n");
 553		goto out;
 554	}
 555
 556	neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
 557	if (!neigh_ifinfo)
 558		goto out;
 559
 560	tvlv_len = ntohs(ogm_received->tvlv_len);
 561
 562	packet_len = BATADV_OGM2_HLEN + tvlv_len;
 563	skb = netdev_alloc_skb_ip_align(if_outgoing->net_dev,
 564					ETH_HLEN + packet_len);
 565	if (!skb)
 566		goto out;
 567
 568	skb_reserve(skb, ETH_HLEN);
 569	skb_buff = skb_put_data(skb, ogm_received, packet_len);
 570
 571	/* apply forward penalty */
 572	ogm_forward = (struct batadv_ogm2_packet *)skb_buff;
 573	ogm_forward->throughput = htonl(neigh_ifinfo->bat_v.throughput);
 574	ogm_forward->ttl--;
 575
 576	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 577		   "Forwarding OGM2 packet on %s: throughput %u, ttl %u, received via %s\n",
 578		   if_outgoing->net_dev->name, ntohl(ogm_forward->throughput),
 579		   ogm_forward->ttl, if_incoming->net_dev->name);
 580
 581	batadv_v_ogm_queue_on_if(skb, if_outgoing);
 582
 583out:
 584	batadv_orig_ifinfo_put(orig_ifinfo);
 585	batadv_neigh_node_put(router);
 586	batadv_neigh_ifinfo_put(neigh_ifinfo);
 587}
 588
 589/**
 590 * batadv_v_ogm_metric_update() - update route metric based on OGM
 591 * @bat_priv: the bat priv with all the mesh interface information
 592 * @ogm2: OGM2 structure
 593 * @orig_node: Originator structure for which the OGM has been received
 594 * @neigh_node: the neigh_node through with the OGM has been received
 595 * @if_incoming: the interface where this packet was received
 596 * @if_outgoing: the interface for which the packet should be considered
 597 *
 598 * Return:
 599 *  1  if the OGM is new,
 600 *  0  if it is not new but valid,
 601 *  <0 on error (e.g. old OGM)
 602 */
 603static int batadv_v_ogm_metric_update(struct batadv_priv *bat_priv,
 604				      const struct batadv_ogm2_packet *ogm2,
 605				      struct batadv_orig_node *orig_node,
 606				      struct batadv_neigh_node *neigh_node,
 607				      struct batadv_hard_iface *if_incoming,
 608				      struct batadv_hard_iface *if_outgoing)
 609{
 610	struct batadv_orig_ifinfo *orig_ifinfo;
 611	struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
 612	bool protection_started = false;
 613	int ret = -EINVAL;
 614	u32 path_throughput;
 615	s32 seq_diff;
 616
 617	orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
 618	if (!orig_ifinfo)
 619		goto out;
 620
 621	seq_diff = ntohl(ogm2->seqno) - orig_ifinfo->last_real_seqno;
 622
 623	if (!hlist_empty(&orig_node->neigh_list) &&
 624	    batadv_window_protected(bat_priv, seq_diff,
 625				    BATADV_OGM_MAX_AGE,
 626				    &orig_ifinfo->batman_seqno_reset,
 627				    &protection_started)) {
 628		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 629			   "Drop packet: packet within window protection time from %pM\n",
 630			   ogm2->orig);
 631		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 632			   "Last reset: %ld, %ld\n",
 633			   orig_ifinfo->batman_seqno_reset, jiffies);
 634		goto out;
 635	}
 636
 637	/* drop packets with old seqnos, however accept the first packet after
 638	 * a host has been rebooted.
 639	 */
 640	if (seq_diff < 0 && !protection_started)
 641		goto out;
 642
 643	neigh_node->last_seen = jiffies;
 644
 645	orig_node->last_seen = jiffies;
 646
 647	orig_ifinfo->last_real_seqno = ntohl(ogm2->seqno);
 648	orig_ifinfo->last_ttl = ogm2->ttl;
 649
 650	neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
 651	if (!neigh_ifinfo)
 652		goto out;
 653
 654	path_throughput = batadv_v_forward_penalty(bat_priv, if_incoming,
 655						   if_outgoing,
 656						   ntohl(ogm2->throughput));
 657	neigh_ifinfo->bat_v.throughput = path_throughput;
 658	neigh_ifinfo->bat_v.last_seqno = ntohl(ogm2->seqno);
 659	neigh_ifinfo->last_ttl = ogm2->ttl;
 660
 661	if (seq_diff > 0 || protection_started)
 662		ret = 1;
 663	else
 664		ret = 0;
 665out:
 666	batadv_orig_ifinfo_put(orig_ifinfo);
 667	batadv_neigh_ifinfo_put(neigh_ifinfo);
 668
 669	return ret;
 670}
 671
 672/**
 673 * batadv_v_ogm_route_update() - update routes based on OGM
 674 * @bat_priv: the bat priv with all the mesh interface information
 675 * @ethhdr: the Ethernet header of the OGM2
 676 * @ogm2: OGM2 structure
 677 * @orig_node: Originator structure for which the OGM has been received
 678 * @neigh_node: the neigh_node through with the OGM has been received
 679 * @if_incoming: the interface where this packet was received
 680 * @if_outgoing: the interface for which the packet should be considered
 681 *
 682 * Return: true if the packet should be forwarded, false otherwise
 683 */
 684static bool batadv_v_ogm_route_update(struct batadv_priv *bat_priv,
 685				      const struct ethhdr *ethhdr,
 686				      const struct batadv_ogm2_packet *ogm2,
 687				      struct batadv_orig_node *orig_node,
 688				      struct batadv_neigh_node *neigh_node,
 689				      struct batadv_hard_iface *if_incoming,
 690				      struct batadv_hard_iface *if_outgoing)
 691{
 692	struct batadv_neigh_node *router = NULL;
 693	struct batadv_orig_node *orig_neigh_node;
 694	struct batadv_neigh_node *orig_neigh_router = NULL;
 695	struct batadv_neigh_ifinfo *router_ifinfo = NULL, *neigh_ifinfo = NULL;
 696	u32 router_throughput, neigh_throughput;
 697	u32 router_last_seqno;
 698	u32 neigh_last_seqno;
 699	s32 neigh_seq_diff;
 700	bool forward = false;
 701
 702	orig_neigh_node = batadv_v_ogm_orig_get(bat_priv, ethhdr->h_source);
 703	if (!orig_neigh_node)
 704		goto out;
 705
 706	orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
 707						   if_outgoing);
 708
 709	/* drop packet if sender is not a direct neighbor and if we
 710	 * don't route towards it
 711	 */
 712	router = batadv_orig_router_get(orig_node, if_outgoing);
 713	if (router && router->orig_node != orig_node && !orig_neigh_router) {
 714		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 715			   "Drop packet: OGM via unknown neighbor!\n");
 716		goto out;
 717	}
 718
 719	/* Mark the OGM to be considered for forwarding, and update routes
 720	 * if needed.
 721	 */
 722	forward = true;
 723
 724	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 725		   "Searching and updating originator entry of received packet\n");
 726
 727	/* if this neighbor already is our next hop there is nothing
 728	 * to change
 729	 */
 730	if (router == neigh_node)
 731		goto out;
 732
 733	/* don't consider neighbours with worse throughput.
 734	 * also switch route if this seqno is BATADV_V_MAX_ORIGDIFF newer than
 735	 * the last received seqno from our best next hop.
 736	 */
 737	if (router) {
 738		router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
 739		neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
 740
 741		/* if these are not allocated, something is wrong. */
 742		if (!router_ifinfo || !neigh_ifinfo)
 743			goto out;
 744
 745		neigh_last_seqno = neigh_ifinfo->bat_v.last_seqno;
 746		router_last_seqno = router_ifinfo->bat_v.last_seqno;
 747		neigh_seq_diff = neigh_last_seqno - router_last_seqno;
 748		router_throughput = router_ifinfo->bat_v.throughput;
 749		neigh_throughput = neigh_ifinfo->bat_v.throughput;
 750
 751		if (neigh_seq_diff < BATADV_OGM_MAX_ORIGDIFF &&
 752		    router_throughput >= neigh_throughput)
 753			goto out;
 754	}
 755
 756	batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
 757out:
 758	batadv_neigh_node_put(router);
 759	batadv_neigh_node_put(orig_neigh_router);
 760	batadv_orig_node_put(orig_neigh_node);
 761	batadv_neigh_ifinfo_put(router_ifinfo);
 762	batadv_neigh_ifinfo_put(neigh_ifinfo);
 763
 764	return forward;
 765}
 766
 767/**
 768 * batadv_v_ogm_process_per_outif() - process a batman v OGM for an outgoing if
 769 * @bat_priv: the bat priv with all the mesh interface information
 770 * @ethhdr: the Ethernet header of the OGM2
 771 * @ogm2: OGM2 structure
 772 * @orig_node: Originator structure for which the OGM has been received
 773 * @neigh_node: the neigh_node through with the OGM has been received
 774 * @if_incoming: the interface where this packet was received
 775 * @if_outgoing: the interface for which the packet should be considered
 776 */
 777static void
 778batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
 779			       const struct ethhdr *ethhdr,
 780			       const struct batadv_ogm2_packet *ogm2,
 781			       struct batadv_orig_node *orig_node,
 782			       struct batadv_neigh_node *neigh_node,
 783			       struct batadv_hard_iface *if_incoming,
 784			       struct batadv_hard_iface *if_outgoing)
 785{
 786	int seqno_age;
 787	bool forward;
 788
 789	/* first, update the metric with according sanity checks */
 790	seqno_age = batadv_v_ogm_metric_update(bat_priv, ogm2, orig_node,
 791					       neigh_node, if_incoming,
 792					       if_outgoing);
 793
 794	/* outdated sequence numbers are to be discarded */
 795	if (seqno_age < 0)
 796		return;
 797
 798	/* only unknown & newer OGMs contain TVLVs we are interested in */
 799	if (seqno_age > 0 && if_outgoing == BATADV_IF_DEFAULT)
 800		batadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
 801					       NULL,
 802					       (unsigned char *)(ogm2 + 1),
 803					       ntohs(ogm2->tvlv_len));
 804
 805	/* if the metric update went through, update routes if needed */
 806	forward = batadv_v_ogm_route_update(bat_priv, ethhdr, ogm2, orig_node,
 807					    neigh_node, if_incoming,
 808					    if_outgoing);
 809
 810	/* if the routes have been processed correctly, check and forward */
 811	if (forward)
 812		batadv_v_ogm_forward(bat_priv, ogm2, orig_node, neigh_node,
 813				     if_incoming, if_outgoing);
 814}
 815
 816/**
 817 * batadv_v_ogm_aggr_packet() - checks if there is another OGM aggregated
 818 * @buff_pos: current position in the skb
 819 * @packet_len: total length of the skb
 820 * @ogm2_packet: potential OGM2 in buffer
 821 *
 822 * Return: true if there is enough space for another OGM, false otherwise.
 823 */
 824static bool
 825batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
 826			 const struct batadv_ogm2_packet *ogm2_packet)
 827{
 828	int next_buff_pos = 0;
 829
 830	/* check if there is enough space for the header */
 831	next_buff_pos += buff_pos + sizeof(*ogm2_packet);
 832	if (next_buff_pos > packet_len)
 833		return false;
 834
 835	/* check if there is enough space for the optional TVLV */
 836	next_buff_pos += ntohs(ogm2_packet->tvlv_len);
 837
 838	return next_buff_pos <= packet_len;
 839}
 840
 841/**
 842 * batadv_v_ogm_process() - process an incoming batman v OGM
 843 * @skb: the skb containing the OGM
 844 * @ogm_offset: offset to the OGM which should be processed (for aggregates)
 845 * @if_incoming: the interface where this packet was received
 846 */
 847static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
 848				 struct batadv_hard_iface *if_incoming)
 849{
 850	struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
 851	struct ethhdr *ethhdr;
 852	struct batadv_orig_node *orig_node = NULL;
 853	struct batadv_hardif_neigh_node *hardif_neigh = NULL;
 854	struct batadv_neigh_node *neigh_node = NULL;
 855	struct batadv_hard_iface *hard_iface;
 856	struct batadv_ogm2_packet *ogm_packet;
 857	u32 ogm_throughput, link_throughput, path_throughput;
 858	struct list_head *iter;
 859	int ret;
 860
 861	ethhdr = eth_hdr(skb);
 862	ogm_packet = (struct batadv_ogm2_packet *)(skb->data + ogm_offset);
 863
 864	ogm_throughput = ntohl(ogm_packet->throughput);
 865
 866	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 867		   "Received OGM2 packet via NB: %pM, IF: %s [%pM] (from OG: %pM, seqno %u, throughput %u, TTL %u, V %u, tvlv_len %u)\n",
 868		   ethhdr->h_source, if_incoming->net_dev->name,
 869		   if_incoming->net_dev->dev_addr, ogm_packet->orig,
 870		   ntohl(ogm_packet->seqno), ogm_throughput, ogm_packet->ttl,
 871		   ogm_packet->version, ntohs(ogm_packet->tvlv_len));
 872
 873	if (batadv_is_my_mac(bat_priv, ogm_packet->orig)) {
 874		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 875			   "Drop packet: originator packet from ourself\n");
 876		return;
 877	}
 878
 879	/* If the throughput metric is 0, immediately drop the packet. No need
 880	 * to create orig_node / neigh_node for an unusable route.
 881	 */
 882	if (ogm_throughput == 0) {
 883		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 884			   "Drop packet: originator packet with throughput metric of 0\n");
 885		return;
 886	}
 887
 888	/* require ELP packets be to received from this neighbor first */
 889	hardif_neigh = batadv_hardif_neigh_get(if_incoming, ethhdr->h_source);
 890	if (!hardif_neigh) {
 891		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 892			   "Drop packet: OGM via unknown neighbor!\n");
 893		goto out;
 894	}
 895
 896	orig_node = batadv_v_ogm_orig_get(bat_priv, ogm_packet->orig);
 897	if (!orig_node)
 898		goto out;
 899
 900	neigh_node = batadv_neigh_node_get_or_create(orig_node, if_incoming,
 901						     ethhdr->h_source);
 902	if (!neigh_node)
 903		goto out;
 904
 905	/* Update the received throughput metric to match the link
 906	 * characteristic:
 907	 *  - If this OGM traveled one hop so far (emitted by single hop
 908	 *    neighbor) the path throughput metric equals the link throughput.
 909	 *  - For OGMs traversing more than hop the path throughput metric is
 910	 *    the smaller of the path throughput and the link throughput.
 911	 */
 912	link_throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
 913	path_throughput = min_t(u32, link_throughput, ogm_throughput);
 914	ogm_packet->throughput = htonl(path_throughput);
 915
 916	batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, orig_node,
 917				       neigh_node, if_incoming,
 918				       BATADV_IF_DEFAULT);
 919
 920	rcu_read_lock();
 921	netdev_for_each_lower_private_rcu(bat_priv->mesh_iface, hard_iface, iter) {
 922		if (hard_iface->if_status != BATADV_IF_ACTIVE)
 923			continue;
 924
 925		if (!kref_get_unless_zero(&hard_iface->refcount))
 926			continue;
 927
 928		ret = batadv_hardif_no_broadcast(hard_iface,
 929						 ogm_packet->orig,
 930						 hardif_neigh->orig);
 931
 932		if (ret) {
 933			char *type;
 934
 935			switch (ret) {
 936			case BATADV_HARDIF_BCAST_NORECIPIENT:
 937				type = "no neighbor";
 938				break;
 939			case BATADV_HARDIF_BCAST_DUPFWD:
 940				type = "single neighbor is source";
 941				break;
 942			case BATADV_HARDIF_BCAST_DUPORIG:
 943				type = "single neighbor is originator";
 944				break;
 945			default:
 946				type = "unknown";
 947			}
 948
 949			batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 packet from %pM on %s suppressed: %s\n",
 950				   ogm_packet->orig, hard_iface->net_dev->name,
 951				   type);
 952
 953			batadv_hardif_put(hard_iface);
 954			continue;
 955		}
 956
 957		batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet,
 958					       orig_node, neigh_node,
 959					       if_incoming, hard_iface);
 960
 961		batadv_hardif_put(hard_iface);
 962	}
 963	rcu_read_unlock();
 964out:
 965	batadv_orig_node_put(orig_node);
 966	batadv_neigh_node_put(neigh_node);
 967	batadv_hardif_neigh_put(hardif_neigh);
 968}
 969
 970/**
 971 * batadv_v_ogm_packet_recv() - OGM2 receiving handler
 972 * @skb: the received OGM
 973 * @if_incoming: the interface where this OGM has been received
 974 *
 975 * Return: NET_RX_SUCCESS and consume the skb on success or returns NET_RX_DROP
 976 * (without freeing the skb) on failure
 977 */
 978int batadv_v_ogm_packet_recv(struct sk_buff *skb,
 979			     struct batadv_hard_iface *if_incoming)
 980{
 981	struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
 982	struct batadv_ogm2_packet *ogm_packet;
 983	struct ethhdr *ethhdr;
 984	int ogm_offset;
 985	u8 *packet_pos;
 986	int ret = NET_RX_DROP;
 987
 988	/* did we receive a OGM2 packet on an interface that does not have
 989	 * B.A.T.M.A.N. V enabled ?
 990	 */
 991	if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0)
 992		goto free_skb;
 993
 994	if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
 995		goto free_skb;
 996
 997	ethhdr = eth_hdr(skb);
 998	if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
 999		goto free_skb;
1000
1001	batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
1002	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
1003			   skb->len + ETH_HLEN);
1004
1005	ogm_offset = 0;
1006	ogm_packet = (struct batadv_ogm2_packet *)skb->data;
1007
1008	while (batadv_v_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
1009					ogm_packet)) {
1010		batadv_v_ogm_process(skb, ogm_offset, if_incoming);
1011
1012		ogm_offset += BATADV_OGM2_HLEN;
1013		ogm_offset += ntohs(ogm_packet->tvlv_len);
1014
1015		packet_pos = skb->data + ogm_offset;
1016		ogm_packet = (struct batadv_ogm2_packet *)packet_pos;
1017	}
1018
1019	ret = NET_RX_SUCCESS;
1020
1021free_skb:
1022	if (ret == NET_RX_SUCCESS)
1023		consume_skb(skb);
1024	else
1025		kfree_skb(skb);
1026
1027	return ret;
1028}
1029
1030/**
1031 * batadv_v_ogm_init() - initialise the OGM2 engine
1032 * @bat_priv: the bat priv with all the mesh interface information
1033 *
1034 * Return: 0 on success or a negative error code in case of failure
1035 */
1036int batadv_v_ogm_init(struct batadv_priv *bat_priv)
1037{
1038	struct batadv_ogm2_packet *ogm_packet;
1039	unsigned char *ogm_buff;
1040	u32 random_seqno;
1041
1042	bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
1043	ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
1044	if (!ogm_buff)
1045		return -ENOMEM;
1046
1047	bat_priv->bat_v.ogm_buff = ogm_buff;
1048	ogm_packet = (struct batadv_ogm2_packet *)ogm_buff;
1049	ogm_packet->packet_type = BATADV_OGM2;
1050	ogm_packet->version = BATADV_COMPAT_VERSION;
1051	ogm_packet->ttl = BATADV_TTL;
1052	ogm_packet->flags = BATADV_NO_FLAGS;
1053	ogm_packet->throughput = htonl(BATADV_THROUGHPUT_MAX_VALUE);
1054
1055	/* randomize initial seqno to avoid collision */
1056	get_random_bytes(&random_seqno, sizeof(random_seqno));
1057	atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
1058	INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
1059
1060	mutex_init(&bat_priv->bat_v.ogm_buff_mutex);
1061
1062	return 0;
1063}
1064
1065/**
1066 * batadv_v_ogm_free() - free OGM private resources
1067 * @bat_priv: the bat priv with all the mesh interface information
1068 */
1069void batadv_v_ogm_free(struct batadv_priv *bat_priv)
1070{
1071	cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
1072
1073	mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
1074
1075	kfree(bat_priv->bat_v.ogm_buff);
1076	bat_priv->bat_v.ogm_buff = NULL;
1077	bat_priv->bat_v.ogm_buff_len = 0;
1078
1079	mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
1080}
~/ Read-only file preview.