162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) B.A.T.M.A.N. contributors:
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Marek Lindner, Simon Wunderlich
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "send.h"
862306a36Sopenharmony_ci#include "main.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/atomic.h>
1162306a36Sopenharmony_ci#include <linux/bug.h>
1262306a36Sopenharmony_ci#include <linux/byteorder/generic.h>
1362306a36Sopenharmony_ci#include <linux/container_of.h>
1462306a36Sopenharmony_ci#include <linux/errno.h>
1562306a36Sopenharmony_ci#include <linux/etherdevice.h>
1662306a36Sopenharmony_ci#include <linux/gfp.h>
1762306a36Sopenharmony_ci#include <linux/if.h>
1862306a36Sopenharmony_ci#include <linux/if_ether.h>
1962306a36Sopenharmony_ci#include <linux/jiffies.h>
2062306a36Sopenharmony_ci#include <linux/kref.h>
2162306a36Sopenharmony_ci#include <linux/list.h>
2262306a36Sopenharmony_ci#include <linux/netdevice.h>
2362306a36Sopenharmony_ci#include <linux/printk.h>
2462306a36Sopenharmony_ci#include <linux/rculist.h>
2562306a36Sopenharmony_ci#include <linux/rcupdate.h>
2662306a36Sopenharmony_ci#include <linux/skbuff.h>
2762306a36Sopenharmony_ci#include <linux/slab.h>
2862306a36Sopenharmony_ci#include <linux/spinlock.h>
2962306a36Sopenharmony_ci#include <linux/stddef.h>
3062306a36Sopenharmony_ci#include <linux/workqueue.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "distributed-arp-table.h"
3362306a36Sopenharmony_ci#include "fragmentation.h"
3462306a36Sopenharmony_ci#include "gateway_client.h"
3562306a36Sopenharmony_ci#include "hard-interface.h"
3662306a36Sopenharmony_ci#include "log.h"
3762306a36Sopenharmony_ci#include "network-coding.h"
3862306a36Sopenharmony_ci#include "originator.h"
3962306a36Sopenharmony_ci#include "routing.h"
4062306a36Sopenharmony_ci#include "soft-interface.h"
4162306a36Sopenharmony_ci#include "translation-table.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void batadv_send_outstanding_bcast_packet(struct work_struct *work);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * batadv_send_skb_packet() - send an already prepared packet
4762306a36Sopenharmony_ci * @skb: the packet to send
4862306a36Sopenharmony_ci * @hard_iface: the interface to use to send the broadcast packet
4962306a36Sopenharmony_ci * @dst_addr: the payload destination
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Send out an already prepared packet to the given neighbor or broadcast it
5262306a36Sopenharmony_ci * using the specified interface. Either hard_iface or neigh_node must be not
5362306a36Sopenharmony_ci * NULL.
5462306a36Sopenharmony_ci * If neigh_node is NULL, then the packet is broadcasted using hard_iface,
5562306a36Sopenharmony_ci * otherwise it is sent as unicast to the given neighbor.
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * Regardless of the return value, the skb is consumed.
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Return: A negative errno code is returned on a failure. A success does not
6062306a36Sopenharmony_ci * guarantee the frame will be transmitted as it may be dropped due
6162306a36Sopenharmony_ci * to congestion or traffic shaping.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_ciint batadv_send_skb_packet(struct sk_buff *skb,
6462306a36Sopenharmony_ci			   struct batadv_hard_iface *hard_iface,
6562306a36Sopenharmony_ci			   const u8 *dst_addr)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	struct batadv_priv *bat_priv;
6862306a36Sopenharmony_ci	struct ethhdr *ethhdr;
6962306a36Sopenharmony_ci	int ret;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	bat_priv = netdev_priv(hard_iface->soft_iface);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (hard_iface->if_status != BATADV_IF_ACTIVE)
7462306a36Sopenharmony_ci		goto send_skb_err;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (unlikely(!hard_iface->net_dev))
7762306a36Sopenharmony_ci		goto send_skb_err;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (!(hard_iface->net_dev->flags & IFF_UP)) {
8062306a36Sopenharmony_ci		pr_warn("Interface %s is not up - can't send packet via that interface!\n",
8162306a36Sopenharmony_ci			hard_iface->net_dev->name);
8262306a36Sopenharmony_ci		goto send_skb_err;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/* push to the ethernet header. */
8662306a36Sopenharmony_ci	if (batadv_skb_head_push(skb, ETH_HLEN) < 0)
8762306a36Sopenharmony_ci		goto send_skb_err;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	skb_reset_mac_header(skb);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	ethhdr = eth_hdr(skb);
9262306a36Sopenharmony_ci	ether_addr_copy(ethhdr->h_source, hard_iface->net_dev->dev_addr);
9362306a36Sopenharmony_ci	ether_addr_copy(ethhdr->h_dest, dst_addr);
9462306a36Sopenharmony_ci	ethhdr->h_proto = htons(ETH_P_BATMAN);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	skb_set_network_header(skb, ETH_HLEN);
9762306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_BATMAN);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	skb->dev = hard_iface->net_dev;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* Save a clone of the skb to use when decoding coded packets */
10262306a36Sopenharmony_ci	batadv_nc_skb_store_for_decoding(bat_priv, skb);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* dev_queue_xmit() returns a negative result on error.	 However on
10562306a36Sopenharmony_ci	 * congestion and traffic shaping, it drops and returns NET_XMIT_DROP
10662306a36Sopenharmony_ci	 * (which is > 0). This will not be treated as an error.
10762306a36Sopenharmony_ci	 */
10862306a36Sopenharmony_ci	ret = dev_queue_xmit(skb);
10962306a36Sopenharmony_ci	return net_xmit_eval(ret);
11062306a36Sopenharmony_cisend_skb_err:
11162306a36Sopenharmony_ci	kfree_skb(skb);
11262306a36Sopenharmony_ci	return NET_XMIT_DROP;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/**
11662306a36Sopenharmony_ci * batadv_send_broadcast_skb() - Send broadcast packet via hard interface
11762306a36Sopenharmony_ci * @skb: packet to be transmitted (with batadv header and no outer eth header)
11862306a36Sopenharmony_ci * @hard_iface: outgoing interface
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * Return: A negative errno code is returned on a failure. A success does not
12162306a36Sopenharmony_ci * guarantee the frame will be transmitted as it may be dropped due
12262306a36Sopenharmony_ci * to congestion or traffic shaping.
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_ciint batadv_send_broadcast_skb(struct sk_buff *skb,
12562306a36Sopenharmony_ci			      struct batadv_hard_iface *hard_iface)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	return batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/**
13162306a36Sopenharmony_ci * batadv_send_unicast_skb() - Send unicast packet to neighbor
13262306a36Sopenharmony_ci * @skb: packet to be transmitted (with batadv header and no outer eth header)
13362306a36Sopenharmony_ci * @neigh: neighbor which is used as next hop to destination
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * Return: A negative errno code is returned on a failure. A success does not
13662306a36Sopenharmony_ci * guarantee the frame will be transmitted as it may be dropped due
13762306a36Sopenharmony_ci * to congestion or traffic shaping.
13862306a36Sopenharmony_ci */
13962306a36Sopenharmony_ciint batadv_send_unicast_skb(struct sk_buff *skb,
14062306a36Sopenharmony_ci			    struct batadv_neigh_node *neigh)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BATMAN_V
14362306a36Sopenharmony_ci	struct batadv_hardif_neigh_node *hardif_neigh;
14462306a36Sopenharmony_ci#endif
14562306a36Sopenharmony_ci	int ret;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	ret = batadv_send_skb_packet(skb, neigh->if_incoming, neigh->addr);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BATMAN_V
15062306a36Sopenharmony_ci	hardif_neigh = batadv_hardif_neigh_get(neigh->if_incoming, neigh->addr);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (hardif_neigh && ret != NET_XMIT_DROP)
15362306a36Sopenharmony_ci		hardif_neigh->bat_v.last_unicast_tx = jiffies;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	batadv_hardif_neigh_put(hardif_neigh);
15662306a36Sopenharmony_ci#endif
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return ret;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/**
16262306a36Sopenharmony_ci * batadv_send_skb_to_orig() - Lookup next-hop and transmit skb.
16362306a36Sopenharmony_ci * @skb: Packet to be transmitted.
16462306a36Sopenharmony_ci * @orig_node: Final destination of the packet.
16562306a36Sopenharmony_ci * @recv_if: Interface used when receiving the packet (can be NULL).
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci * Looks up the best next-hop towards the passed originator and passes the
16862306a36Sopenharmony_ci * skb on for preparation of MAC header. If the packet originated from this
16962306a36Sopenharmony_ci * host, NULL can be passed as recv_if and no interface alternating is
17062306a36Sopenharmony_ci * attempted.
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci * Return: negative errno code on a failure, -EINPROGRESS if the skb is
17362306a36Sopenharmony_ci * buffered for later transmit or the NET_XMIT status returned by the
17462306a36Sopenharmony_ci * lower routine if the packet has been passed down.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_ciint batadv_send_skb_to_orig(struct sk_buff *skb,
17762306a36Sopenharmony_ci			    struct batadv_orig_node *orig_node,
17862306a36Sopenharmony_ci			    struct batadv_hard_iface *recv_if)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct batadv_priv *bat_priv = orig_node->bat_priv;
18162306a36Sopenharmony_ci	struct batadv_neigh_node *neigh_node;
18262306a36Sopenharmony_ci	int ret;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* batadv_find_router() increases neigh_nodes refcount if found. */
18562306a36Sopenharmony_ci	neigh_node = batadv_find_router(bat_priv, orig_node, recv_if);
18662306a36Sopenharmony_ci	if (!neigh_node) {
18762306a36Sopenharmony_ci		ret = -EINVAL;
18862306a36Sopenharmony_ci		goto free_skb;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* Check if the skb is too large to send in one piece and fragment
19262306a36Sopenharmony_ci	 * it if needed.
19362306a36Sopenharmony_ci	 */
19462306a36Sopenharmony_ci	if (atomic_read(&bat_priv->fragmentation) &&
19562306a36Sopenharmony_ci	    skb->len > neigh_node->if_incoming->net_dev->mtu) {
19662306a36Sopenharmony_ci		/* Fragment and send packet. */
19762306a36Sopenharmony_ci		ret = batadv_frag_send_packet(skb, orig_node, neigh_node);
19862306a36Sopenharmony_ci		/* skb was consumed */
19962306a36Sopenharmony_ci		skb = NULL;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		goto put_neigh_node;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* try to network code the packet, if it is received on an interface
20562306a36Sopenharmony_ci	 * (i.e. being forwarded). If the packet originates from this node or if
20662306a36Sopenharmony_ci	 * network coding fails, then send the packet as usual.
20762306a36Sopenharmony_ci	 */
20862306a36Sopenharmony_ci	if (recv_if && batadv_nc_skb_forward(skb, neigh_node))
20962306a36Sopenharmony_ci		ret = -EINPROGRESS;
21062306a36Sopenharmony_ci	else
21162306a36Sopenharmony_ci		ret = batadv_send_unicast_skb(skb, neigh_node);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* skb was consumed */
21462306a36Sopenharmony_ci	skb = NULL;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ciput_neigh_node:
21762306a36Sopenharmony_ci	batadv_neigh_node_put(neigh_node);
21862306a36Sopenharmony_cifree_skb:
21962306a36Sopenharmony_ci	kfree_skb(skb);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	return ret;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/**
22562306a36Sopenharmony_ci * batadv_send_skb_push_fill_unicast() - extend the buffer and initialize the
22662306a36Sopenharmony_ci *  common fields for unicast packets
22762306a36Sopenharmony_ci * @skb: the skb carrying the unicast header to initialize
22862306a36Sopenharmony_ci * @hdr_size: amount of bytes to push at the beginning of the skb
22962306a36Sopenharmony_ci * @orig_node: the destination node
23062306a36Sopenharmony_ci *
23162306a36Sopenharmony_ci * Return: false if the buffer extension was not possible or true otherwise.
23262306a36Sopenharmony_ci */
23362306a36Sopenharmony_cistatic bool
23462306a36Sopenharmony_cibatadv_send_skb_push_fill_unicast(struct sk_buff *skb, int hdr_size,
23562306a36Sopenharmony_ci				  struct batadv_orig_node *orig_node)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct batadv_unicast_packet *unicast_packet;
23862306a36Sopenharmony_ci	u8 ttvn = (u8)atomic_read(&orig_node->last_ttvn);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (batadv_skb_head_push(skb, hdr_size) < 0)
24162306a36Sopenharmony_ci		return false;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	unicast_packet = (struct batadv_unicast_packet *)skb->data;
24462306a36Sopenharmony_ci	unicast_packet->version = BATADV_COMPAT_VERSION;
24562306a36Sopenharmony_ci	/* batman packet type: unicast */
24662306a36Sopenharmony_ci	unicast_packet->packet_type = BATADV_UNICAST;
24762306a36Sopenharmony_ci	/* set unicast ttl */
24862306a36Sopenharmony_ci	unicast_packet->ttl = BATADV_TTL;
24962306a36Sopenharmony_ci	/* copy the destination for faster routing */
25062306a36Sopenharmony_ci	ether_addr_copy(unicast_packet->dest, orig_node->orig);
25162306a36Sopenharmony_ci	/* set the destination tt version number */
25262306a36Sopenharmony_ci	unicast_packet->ttvn = ttvn;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return true;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci/**
25862306a36Sopenharmony_ci * batadv_send_skb_prepare_unicast() - encapsulate an skb with a unicast header
25962306a36Sopenharmony_ci * @skb: the skb containing the payload to encapsulate
26062306a36Sopenharmony_ci * @orig_node: the destination node
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * Return: false if the payload could not be encapsulated or true otherwise.
26362306a36Sopenharmony_ci */
26462306a36Sopenharmony_cistatic bool batadv_send_skb_prepare_unicast(struct sk_buff *skb,
26562306a36Sopenharmony_ci					    struct batadv_orig_node *orig_node)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	size_t uni_size = sizeof(struct batadv_unicast_packet);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return batadv_send_skb_push_fill_unicast(skb, uni_size, orig_node);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/**
27362306a36Sopenharmony_ci * batadv_send_skb_prepare_unicast_4addr() - encapsulate an skb with a
27462306a36Sopenharmony_ci *  unicast 4addr header
27562306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
27662306a36Sopenharmony_ci * @skb: the skb containing the payload to encapsulate
27762306a36Sopenharmony_ci * @orig: the destination node
27862306a36Sopenharmony_ci * @packet_subtype: the unicast 4addr packet subtype to use
27962306a36Sopenharmony_ci *
28062306a36Sopenharmony_ci * Return: false if the payload could not be encapsulated or true otherwise.
28162306a36Sopenharmony_ci */
28262306a36Sopenharmony_cibool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
28362306a36Sopenharmony_ci					   struct sk_buff *skb,
28462306a36Sopenharmony_ci					   struct batadv_orig_node *orig,
28562306a36Sopenharmony_ci					   int packet_subtype)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
28862306a36Sopenharmony_ci	struct batadv_unicast_4addr_packet *uc_4addr_packet;
28962306a36Sopenharmony_ci	bool ret = false;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
29262306a36Sopenharmony_ci	if (!primary_if)
29362306a36Sopenharmony_ci		goto out;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* Pull the header space and fill the unicast_packet substructure.
29662306a36Sopenharmony_ci	 * We can do that because the first member of the uc_4addr_packet
29762306a36Sopenharmony_ci	 * is of type struct unicast_packet
29862306a36Sopenharmony_ci	 */
29962306a36Sopenharmony_ci	if (!batadv_send_skb_push_fill_unicast(skb, sizeof(*uc_4addr_packet),
30062306a36Sopenharmony_ci					       orig))
30162306a36Sopenharmony_ci		goto out;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	uc_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;
30462306a36Sopenharmony_ci	uc_4addr_packet->u.packet_type = BATADV_UNICAST_4ADDR;
30562306a36Sopenharmony_ci	ether_addr_copy(uc_4addr_packet->src, primary_if->net_dev->dev_addr);
30662306a36Sopenharmony_ci	uc_4addr_packet->subtype = packet_subtype;
30762306a36Sopenharmony_ci	uc_4addr_packet->reserved = 0;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	ret = true;
31062306a36Sopenharmony_ciout:
31162306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
31262306a36Sopenharmony_ci	return ret;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/**
31662306a36Sopenharmony_ci * batadv_send_skb_unicast() - encapsulate and send an skb via unicast
31762306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
31862306a36Sopenharmony_ci * @skb: payload to send
31962306a36Sopenharmony_ci * @packet_type: the batman unicast packet type to use
32062306a36Sopenharmony_ci * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast
32162306a36Sopenharmony_ci *  4addr packets)
32262306a36Sopenharmony_ci * @orig_node: the originator to send the packet to
32362306a36Sopenharmony_ci * @vid: the vid to be used to search the translation table
32462306a36Sopenharmony_ci *
32562306a36Sopenharmony_ci * Wrap the given skb into a batman-adv unicast or unicast-4addr header
32662306a36Sopenharmony_ci * depending on whether BATADV_UNICAST or BATADV_UNICAST_4ADDR was supplied
32762306a36Sopenharmony_ci * as packet_type. Then send this frame to the given orig_node.
32862306a36Sopenharmony_ci *
32962306a36Sopenharmony_ci * Return: NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
33062306a36Sopenharmony_ci */
33162306a36Sopenharmony_ciint batadv_send_skb_unicast(struct batadv_priv *bat_priv,
33262306a36Sopenharmony_ci			    struct sk_buff *skb, int packet_type,
33362306a36Sopenharmony_ci			    int packet_subtype,
33462306a36Sopenharmony_ci			    struct batadv_orig_node *orig_node,
33562306a36Sopenharmony_ci			    unsigned short vid)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct batadv_unicast_packet *unicast_packet;
33862306a36Sopenharmony_ci	struct ethhdr *ethhdr;
33962306a36Sopenharmony_ci	int ret = NET_XMIT_DROP;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (!orig_node)
34262306a36Sopenharmony_ci		goto out;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	switch (packet_type) {
34562306a36Sopenharmony_ci	case BATADV_UNICAST:
34662306a36Sopenharmony_ci		if (!batadv_send_skb_prepare_unicast(skb, orig_node))
34762306a36Sopenharmony_ci			goto out;
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	case BATADV_UNICAST_4ADDR:
35062306a36Sopenharmony_ci		if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb,
35162306a36Sopenharmony_ci							   orig_node,
35262306a36Sopenharmony_ci							   packet_subtype))
35362306a36Sopenharmony_ci			goto out;
35462306a36Sopenharmony_ci		break;
35562306a36Sopenharmony_ci	default:
35662306a36Sopenharmony_ci		/* this function supports UNICAST and UNICAST_4ADDR only. It
35762306a36Sopenharmony_ci		 * should never be invoked with any other packet type
35862306a36Sopenharmony_ci		 */
35962306a36Sopenharmony_ci		goto out;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* skb->data might have been reallocated by
36362306a36Sopenharmony_ci	 * batadv_send_skb_prepare_unicast{,_4addr}()
36462306a36Sopenharmony_ci	 */
36562306a36Sopenharmony_ci	ethhdr = eth_hdr(skb);
36662306a36Sopenharmony_ci	unicast_packet = (struct batadv_unicast_packet *)skb->data;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	/* inform the destination node that we are still missing a correct route
36962306a36Sopenharmony_ci	 * for this client. The destination will receive this packet and will
37062306a36Sopenharmony_ci	 * try to reroute it because the ttvn contained in the header is less
37162306a36Sopenharmony_ci	 * than the current one
37262306a36Sopenharmony_ci	 */
37362306a36Sopenharmony_ci	if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest, vid))
37462306a36Sopenharmony_ci		unicast_packet->ttvn = unicast_packet->ttvn - 1;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	ret = batadv_send_skb_to_orig(skb, orig_node, NULL);
37762306a36Sopenharmony_ci	 /* skb was consumed */
37862306a36Sopenharmony_ci	skb = NULL;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ciout:
38162306a36Sopenharmony_ci	kfree_skb(skb);
38262306a36Sopenharmony_ci	return ret;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci/**
38662306a36Sopenharmony_ci * batadv_send_skb_via_tt_generic() - send an skb via TT lookup
38762306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
38862306a36Sopenharmony_ci * @skb: payload to send
38962306a36Sopenharmony_ci * @packet_type: the batman unicast packet type to use
39062306a36Sopenharmony_ci * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast
39162306a36Sopenharmony_ci *  4addr packets)
39262306a36Sopenharmony_ci * @dst_hint: can be used to override the destination contained in the skb
39362306a36Sopenharmony_ci * @vid: the vid to be used to search the translation table
39462306a36Sopenharmony_ci *
39562306a36Sopenharmony_ci * Look up the recipient node for the destination address in the ethernet
39662306a36Sopenharmony_ci * header via the translation table. Wrap the given skb into a batman-adv
39762306a36Sopenharmony_ci * unicast or unicast-4addr header depending on whether BATADV_UNICAST or
39862306a36Sopenharmony_ci * BATADV_UNICAST_4ADDR was supplied as packet_type. Then send this frame
39962306a36Sopenharmony_ci * to the according destination node.
40062306a36Sopenharmony_ci *
40162306a36Sopenharmony_ci * Return: NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
40262306a36Sopenharmony_ci */
40362306a36Sopenharmony_ciint batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
40462306a36Sopenharmony_ci				   struct sk_buff *skb, int packet_type,
40562306a36Sopenharmony_ci				   int packet_subtype, u8 *dst_hint,
40662306a36Sopenharmony_ci				   unsigned short vid)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
40962306a36Sopenharmony_ci	struct batadv_orig_node *orig_node;
41062306a36Sopenharmony_ci	u8 *src, *dst;
41162306a36Sopenharmony_ci	int ret;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	src = ethhdr->h_source;
41462306a36Sopenharmony_ci	dst = ethhdr->h_dest;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	/* if we got an hint! let's send the packet to this client (if any) */
41762306a36Sopenharmony_ci	if (dst_hint) {
41862306a36Sopenharmony_ci		src = NULL;
41962306a36Sopenharmony_ci		dst = dst_hint;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci	orig_node = batadv_transtable_search(bat_priv, src, dst, vid);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	ret = batadv_send_skb_unicast(bat_priv, skb, packet_type,
42462306a36Sopenharmony_ci				      packet_subtype, orig_node, vid);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	batadv_orig_node_put(orig_node);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return ret;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci/**
43262306a36Sopenharmony_ci * batadv_send_skb_via_gw() - send an skb via gateway lookup
43362306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
43462306a36Sopenharmony_ci * @skb: payload to send
43562306a36Sopenharmony_ci * @vid: the vid to be used to search the translation table
43662306a36Sopenharmony_ci *
43762306a36Sopenharmony_ci * Look up the currently selected gateway. Wrap the given skb into a batman-adv
43862306a36Sopenharmony_ci * unicast header and send this frame to this gateway node.
43962306a36Sopenharmony_ci *
44062306a36Sopenharmony_ci * Return: NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_ciint batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
44362306a36Sopenharmony_ci			   unsigned short vid)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct batadv_orig_node *orig_node;
44662306a36Sopenharmony_ci	int ret;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	orig_node = batadv_gw_get_selected_orig(bat_priv);
44962306a36Sopenharmony_ci	ret = batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST_4ADDR,
45062306a36Sopenharmony_ci				      BATADV_P_DATA, orig_node, vid);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	batadv_orig_node_put(orig_node);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return ret;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci/**
45862306a36Sopenharmony_ci * batadv_forw_packet_free() - free a forwarding packet
45962306a36Sopenharmony_ci * @forw_packet: The packet to free
46062306a36Sopenharmony_ci * @dropped: whether the packet is freed because is dropped
46162306a36Sopenharmony_ci *
46262306a36Sopenharmony_ci * This frees a forwarding packet and releases any resources it might
46362306a36Sopenharmony_ci * have claimed.
46462306a36Sopenharmony_ci */
46562306a36Sopenharmony_civoid batadv_forw_packet_free(struct batadv_forw_packet *forw_packet,
46662306a36Sopenharmony_ci			     bool dropped)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	if (dropped)
46962306a36Sopenharmony_ci		kfree_skb(forw_packet->skb);
47062306a36Sopenharmony_ci	else
47162306a36Sopenharmony_ci		consume_skb(forw_packet->skb);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	batadv_hardif_put(forw_packet->if_incoming);
47462306a36Sopenharmony_ci	batadv_hardif_put(forw_packet->if_outgoing);
47562306a36Sopenharmony_ci	if (forw_packet->queue_left)
47662306a36Sopenharmony_ci		atomic_inc(forw_packet->queue_left);
47762306a36Sopenharmony_ci	kfree(forw_packet);
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/**
48162306a36Sopenharmony_ci * batadv_forw_packet_alloc() - allocate a forwarding packet
48262306a36Sopenharmony_ci * @if_incoming: The (optional) if_incoming to be grabbed
48362306a36Sopenharmony_ci * @if_outgoing: The (optional) if_outgoing to be grabbed
48462306a36Sopenharmony_ci * @queue_left: The (optional) queue counter to decrease
48562306a36Sopenharmony_ci * @bat_priv: The bat_priv for the mesh of this forw_packet
48662306a36Sopenharmony_ci * @skb: The raw packet this forwarding packet shall contain
48762306a36Sopenharmony_ci *
48862306a36Sopenharmony_ci * Allocates a forwarding packet and tries to get a reference to the
48962306a36Sopenharmony_ci * (optional) if_incoming, if_outgoing and queue_left. If queue_left
49062306a36Sopenharmony_ci * is NULL then bat_priv is optional, too.
49162306a36Sopenharmony_ci *
49262306a36Sopenharmony_ci * Return: An allocated forwarding packet on success, NULL otherwise.
49362306a36Sopenharmony_ci */
49462306a36Sopenharmony_cistruct batadv_forw_packet *
49562306a36Sopenharmony_cibatadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
49662306a36Sopenharmony_ci			 struct batadv_hard_iface *if_outgoing,
49762306a36Sopenharmony_ci			 atomic_t *queue_left,
49862306a36Sopenharmony_ci			 struct batadv_priv *bat_priv,
49962306a36Sopenharmony_ci			 struct sk_buff *skb)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct batadv_forw_packet *forw_packet;
50262306a36Sopenharmony_ci	const char *qname;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (queue_left && !batadv_atomic_dec_not_zero(queue_left)) {
50562306a36Sopenharmony_ci		qname = "unknown";
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		if (queue_left == &bat_priv->bcast_queue_left)
50862306a36Sopenharmony_ci			qname = "bcast";
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		if (queue_left == &bat_priv->batman_queue_left)
51162306a36Sopenharmony_ci			qname = "batman";
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
51462306a36Sopenharmony_ci			   "%s queue is full\n", qname);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		return NULL;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	forw_packet = kmalloc(sizeof(*forw_packet), GFP_ATOMIC);
52062306a36Sopenharmony_ci	if (!forw_packet)
52162306a36Sopenharmony_ci		goto err;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (if_incoming)
52462306a36Sopenharmony_ci		kref_get(&if_incoming->refcount);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (if_outgoing)
52762306a36Sopenharmony_ci		kref_get(&if_outgoing->refcount);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	INIT_HLIST_NODE(&forw_packet->list);
53062306a36Sopenharmony_ci	INIT_HLIST_NODE(&forw_packet->cleanup_list);
53162306a36Sopenharmony_ci	forw_packet->skb = skb;
53262306a36Sopenharmony_ci	forw_packet->queue_left = queue_left;
53362306a36Sopenharmony_ci	forw_packet->if_incoming = if_incoming;
53462306a36Sopenharmony_ci	forw_packet->if_outgoing = if_outgoing;
53562306a36Sopenharmony_ci	forw_packet->num_packets = 0;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return forw_packet;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cierr:
54062306a36Sopenharmony_ci	if (queue_left)
54162306a36Sopenharmony_ci		atomic_inc(queue_left);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	return NULL;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci/**
54762306a36Sopenharmony_ci * batadv_forw_packet_was_stolen() - check whether someone stole this packet
54862306a36Sopenharmony_ci * @forw_packet: the forwarding packet to check
54962306a36Sopenharmony_ci *
55062306a36Sopenharmony_ci * This function checks whether the given forwarding packet was claimed by
55162306a36Sopenharmony_ci * someone else for free().
55262306a36Sopenharmony_ci *
55362306a36Sopenharmony_ci * Return: True if someone stole it, false otherwise.
55462306a36Sopenharmony_ci */
55562306a36Sopenharmony_cistatic bool
55662306a36Sopenharmony_cibatadv_forw_packet_was_stolen(struct batadv_forw_packet *forw_packet)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	return !hlist_unhashed(&forw_packet->cleanup_list);
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/**
56262306a36Sopenharmony_ci * batadv_forw_packet_steal() - claim a forw_packet for free()
56362306a36Sopenharmony_ci * @forw_packet: the forwarding packet to steal
56462306a36Sopenharmony_ci * @lock: a key to the store to steal from (e.g. forw_{bat,bcast}_list_lock)
56562306a36Sopenharmony_ci *
56662306a36Sopenharmony_ci * This function tries to steal a specific forw_packet from global
56762306a36Sopenharmony_ci * visibility for the purpose of getting it for free(). That means
56862306a36Sopenharmony_ci * the caller is *not* allowed to requeue it afterwards.
56962306a36Sopenharmony_ci *
57062306a36Sopenharmony_ci * Return: True if stealing was successful. False if someone else stole it
57162306a36Sopenharmony_ci * before us.
57262306a36Sopenharmony_ci */
57362306a36Sopenharmony_cibool batadv_forw_packet_steal(struct batadv_forw_packet *forw_packet,
57462306a36Sopenharmony_ci			      spinlock_t *lock)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	/* did purging routine steal it earlier? */
57762306a36Sopenharmony_ci	spin_lock_bh(lock);
57862306a36Sopenharmony_ci	if (batadv_forw_packet_was_stolen(forw_packet)) {
57962306a36Sopenharmony_ci		spin_unlock_bh(lock);
58062306a36Sopenharmony_ci		return false;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	hlist_del_init(&forw_packet->list);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* Just to spot misuse of this function */
58662306a36Sopenharmony_ci	hlist_add_fake(&forw_packet->cleanup_list);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	spin_unlock_bh(lock);
58962306a36Sopenharmony_ci	return true;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/**
59362306a36Sopenharmony_ci * batadv_forw_packet_list_steal() - claim a list of forward packets for free()
59462306a36Sopenharmony_ci * @forw_list: the to be stolen forward packets
59562306a36Sopenharmony_ci * @cleanup_list: a backup pointer, to be able to dispose the packet later
59662306a36Sopenharmony_ci * @hard_iface: the interface to steal forward packets from
59762306a36Sopenharmony_ci *
59862306a36Sopenharmony_ci * This function claims responsibility to free any forw_packet queued on the
59962306a36Sopenharmony_ci * given hard_iface. If hard_iface is NULL forwarding packets on all hard
60062306a36Sopenharmony_ci * interfaces will be claimed.
60162306a36Sopenharmony_ci *
60262306a36Sopenharmony_ci * The packets are being moved from the forw_list to the cleanup_list. This
60362306a36Sopenharmony_ci * makes it possible for already running threads to notice the claim.
60462306a36Sopenharmony_ci */
60562306a36Sopenharmony_cistatic void
60662306a36Sopenharmony_cibatadv_forw_packet_list_steal(struct hlist_head *forw_list,
60762306a36Sopenharmony_ci			      struct hlist_head *cleanup_list,
60862306a36Sopenharmony_ci			      const struct batadv_hard_iface *hard_iface)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct batadv_forw_packet *forw_packet;
61162306a36Sopenharmony_ci	struct hlist_node *safe_tmp_node;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	hlist_for_each_entry_safe(forw_packet, safe_tmp_node,
61462306a36Sopenharmony_ci				  forw_list, list) {
61562306a36Sopenharmony_ci		/* if purge_outstanding_packets() was called with an argument
61662306a36Sopenharmony_ci		 * we delete only packets belonging to the given interface
61762306a36Sopenharmony_ci		 */
61862306a36Sopenharmony_ci		if (hard_iface &&
61962306a36Sopenharmony_ci		    forw_packet->if_incoming != hard_iface &&
62062306a36Sopenharmony_ci		    forw_packet->if_outgoing != hard_iface)
62162306a36Sopenharmony_ci			continue;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		hlist_del(&forw_packet->list);
62462306a36Sopenharmony_ci		hlist_add_head(&forw_packet->cleanup_list, cleanup_list);
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci/**
62962306a36Sopenharmony_ci * batadv_forw_packet_list_free() - free a list of forward packets
63062306a36Sopenharmony_ci * @head: a list of to be freed forw_packets
63162306a36Sopenharmony_ci *
63262306a36Sopenharmony_ci * This function cancels the scheduling of any packet in the provided list,
63362306a36Sopenharmony_ci * waits for any possibly running packet forwarding thread to finish and
63462306a36Sopenharmony_ci * finally, safely frees this forward packet.
63562306a36Sopenharmony_ci *
63662306a36Sopenharmony_ci * This function might sleep.
63762306a36Sopenharmony_ci */
63862306a36Sopenharmony_cistatic void batadv_forw_packet_list_free(struct hlist_head *head)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct batadv_forw_packet *forw_packet;
64162306a36Sopenharmony_ci	struct hlist_node *safe_tmp_node;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	hlist_for_each_entry_safe(forw_packet, safe_tmp_node, head,
64462306a36Sopenharmony_ci				  cleanup_list) {
64562306a36Sopenharmony_ci		cancel_delayed_work_sync(&forw_packet->delayed_work);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		hlist_del(&forw_packet->cleanup_list);
64862306a36Sopenharmony_ci		batadv_forw_packet_free(forw_packet, true);
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci/**
65362306a36Sopenharmony_ci * batadv_forw_packet_queue() - try to queue a forwarding packet
65462306a36Sopenharmony_ci * @forw_packet: the forwarding packet to queue
65562306a36Sopenharmony_ci * @lock: a key to the store (e.g. forw_{bat,bcast}_list_lock)
65662306a36Sopenharmony_ci * @head: the shelve to queue it on (e.g. forw_{bat,bcast}_list)
65762306a36Sopenharmony_ci * @send_time: timestamp (jiffies) when the packet is to be sent
65862306a36Sopenharmony_ci *
65962306a36Sopenharmony_ci * This function tries to (re)queue a forwarding packet. Requeuing
66062306a36Sopenharmony_ci * is prevented if the according interface is shutting down
66162306a36Sopenharmony_ci * (e.g. if batadv_forw_packet_list_steal() was called for this
66262306a36Sopenharmony_ci * packet earlier).
66362306a36Sopenharmony_ci *
66462306a36Sopenharmony_ci * Calling batadv_forw_packet_queue() after a call to
66562306a36Sopenharmony_ci * batadv_forw_packet_steal() is forbidden!
66662306a36Sopenharmony_ci *
66762306a36Sopenharmony_ci * Caller needs to ensure that forw_packet->delayed_work was initialized.
66862306a36Sopenharmony_ci */
66962306a36Sopenharmony_cistatic void batadv_forw_packet_queue(struct batadv_forw_packet *forw_packet,
67062306a36Sopenharmony_ci				     spinlock_t *lock, struct hlist_head *head,
67162306a36Sopenharmony_ci				     unsigned long send_time)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	spin_lock_bh(lock);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* did purging routine steal it from us? */
67662306a36Sopenharmony_ci	if (batadv_forw_packet_was_stolen(forw_packet)) {
67762306a36Sopenharmony_ci		/* If you got it for free() without trouble, then
67862306a36Sopenharmony_ci		 * don't get back into the queue after stealing...
67962306a36Sopenharmony_ci		 */
68062306a36Sopenharmony_ci		WARN_ONCE(hlist_fake(&forw_packet->cleanup_list),
68162306a36Sopenharmony_ci			  "Requeuing after batadv_forw_packet_steal() not allowed!\n");
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		spin_unlock_bh(lock);
68462306a36Sopenharmony_ci		return;
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	hlist_del_init(&forw_packet->list);
68862306a36Sopenharmony_ci	hlist_add_head(&forw_packet->list, head);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	queue_delayed_work(batadv_event_workqueue,
69162306a36Sopenharmony_ci			   &forw_packet->delayed_work,
69262306a36Sopenharmony_ci			   send_time - jiffies);
69362306a36Sopenharmony_ci	spin_unlock_bh(lock);
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/**
69762306a36Sopenharmony_ci * batadv_forw_packet_bcast_queue() - try to queue a broadcast packet
69862306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
69962306a36Sopenharmony_ci * @forw_packet: the forwarding packet to queue
70062306a36Sopenharmony_ci * @send_time: timestamp (jiffies) when the packet is to be sent
70162306a36Sopenharmony_ci *
70262306a36Sopenharmony_ci * This function tries to (re)queue a broadcast packet.
70362306a36Sopenharmony_ci *
70462306a36Sopenharmony_ci * Caller needs to ensure that forw_packet->delayed_work was initialized.
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_cistatic void
70762306a36Sopenharmony_cibatadv_forw_packet_bcast_queue(struct batadv_priv *bat_priv,
70862306a36Sopenharmony_ci			       struct batadv_forw_packet *forw_packet,
70962306a36Sopenharmony_ci			       unsigned long send_time)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	batadv_forw_packet_queue(forw_packet, &bat_priv->forw_bcast_list_lock,
71262306a36Sopenharmony_ci				 &bat_priv->forw_bcast_list, send_time);
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/**
71662306a36Sopenharmony_ci * batadv_forw_packet_ogmv1_queue() - try to queue an OGMv1 packet
71762306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
71862306a36Sopenharmony_ci * @forw_packet: the forwarding packet to queue
71962306a36Sopenharmony_ci * @send_time: timestamp (jiffies) when the packet is to be sent
72062306a36Sopenharmony_ci *
72162306a36Sopenharmony_ci * This function tries to (re)queue an OGMv1 packet.
72262306a36Sopenharmony_ci *
72362306a36Sopenharmony_ci * Caller needs to ensure that forw_packet->delayed_work was initialized.
72462306a36Sopenharmony_ci */
72562306a36Sopenharmony_civoid batadv_forw_packet_ogmv1_queue(struct batadv_priv *bat_priv,
72662306a36Sopenharmony_ci				    struct batadv_forw_packet *forw_packet,
72762306a36Sopenharmony_ci				    unsigned long send_time)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	batadv_forw_packet_queue(forw_packet, &bat_priv->forw_bat_list_lock,
73062306a36Sopenharmony_ci				 &bat_priv->forw_bat_list, send_time);
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci/**
73462306a36Sopenharmony_ci * batadv_forw_bcast_packet_to_list() - queue broadcast packet for transmissions
73562306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
73662306a36Sopenharmony_ci * @skb: broadcast packet to add
73762306a36Sopenharmony_ci * @delay: number of jiffies to wait before sending
73862306a36Sopenharmony_ci * @own_packet: true if it is a self-generated broadcast packet
73962306a36Sopenharmony_ci * @if_in: the interface where the packet was received on
74062306a36Sopenharmony_ci * @if_out: the outgoing interface to queue on
74162306a36Sopenharmony_ci *
74262306a36Sopenharmony_ci * Adds a broadcast packet to the queue and sets up timers. Broadcast packets
74362306a36Sopenharmony_ci * are sent multiple times to increase probability for being received.
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci * This call clones the given skb, hence the caller needs to take into
74662306a36Sopenharmony_ci * account that the data segment of the original skb might not be
74762306a36Sopenharmony_ci * modifiable anymore.
74862306a36Sopenharmony_ci *
74962306a36Sopenharmony_ci * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY on errors.
75062306a36Sopenharmony_ci */
75162306a36Sopenharmony_cistatic int batadv_forw_bcast_packet_to_list(struct batadv_priv *bat_priv,
75262306a36Sopenharmony_ci					    struct sk_buff *skb,
75362306a36Sopenharmony_ci					    unsigned long delay,
75462306a36Sopenharmony_ci					    bool own_packet,
75562306a36Sopenharmony_ci					    struct batadv_hard_iface *if_in,
75662306a36Sopenharmony_ci					    struct batadv_hard_iface *if_out)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	struct batadv_forw_packet *forw_packet;
75962306a36Sopenharmony_ci	unsigned long send_time = jiffies;
76062306a36Sopenharmony_ci	struct sk_buff *newskb;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	newskb = skb_clone(skb, GFP_ATOMIC);
76362306a36Sopenharmony_ci	if (!newskb)
76462306a36Sopenharmony_ci		goto err;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	forw_packet = batadv_forw_packet_alloc(if_in, if_out,
76762306a36Sopenharmony_ci					       &bat_priv->bcast_queue_left,
76862306a36Sopenharmony_ci					       bat_priv, newskb);
76962306a36Sopenharmony_ci	if (!forw_packet)
77062306a36Sopenharmony_ci		goto err_packet_free;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	forw_packet->own = own_packet;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	INIT_DELAYED_WORK(&forw_packet->delayed_work,
77562306a36Sopenharmony_ci			  batadv_send_outstanding_bcast_packet);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	send_time += delay ? delay : msecs_to_jiffies(5);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	batadv_forw_packet_bcast_queue(bat_priv, forw_packet, send_time);
78062306a36Sopenharmony_ci	return NETDEV_TX_OK;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cierr_packet_free:
78362306a36Sopenharmony_ci	kfree_skb(newskb);
78462306a36Sopenharmony_cierr:
78562306a36Sopenharmony_ci	return NETDEV_TX_BUSY;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci/**
78962306a36Sopenharmony_ci * batadv_forw_bcast_packet_if() - forward and queue a broadcast packet
79062306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
79162306a36Sopenharmony_ci * @skb: broadcast packet to add
79262306a36Sopenharmony_ci * @delay: number of jiffies to wait before sending
79362306a36Sopenharmony_ci * @own_packet: true if it is a self-generated broadcast packet
79462306a36Sopenharmony_ci * @if_in: the interface where the packet was received on
79562306a36Sopenharmony_ci * @if_out: the outgoing interface to forward to
79662306a36Sopenharmony_ci *
79762306a36Sopenharmony_ci * Transmits a broadcast packet on the specified interface either immediately
79862306a36Sopenharmony_ci * or if a delay is given after that. Furthermore, queues additional
79962306a36Sopenharmony_ci * retransmissions if this interface is a wireless one.
80062306a36Sopenharmony_ci *
80162306a36Sopenharmony_ci * This call clones the given skb, hence the caller needs to take into
80262306a36Sopenharmony_ci * account that the data segment of the original skb might not be
80362306a36Sopenharmony_ci * modifiable anymore.
80462306a36Sopenharmony_ci *
80562306a36Sopenharmony_ci * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY on errors.
80662306a36Sopenharmony_ci */
80762306a36Sopenharmony_cistatic int batadv_forw_bcast_packet_if(struct batadv_priv *bat_priv,
80862306a36Sopenharmony_ci				       struct sk_buff *skb,
80962306a36Sopenharmony_ci				       unsigned long delay,
81062306a36Sopenharmony_ci				       bool own_packet,
81162306a36Sopenharmony_ci				       struct batadv_hard_iface *if_in,
81262306a36Sopenharmony_ci				       struct batadv_hard_iface *if_out)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	unsigned int num_bcasts = if_out->num_bcasts;
81562306a36Sopenharmony_ci	struct sk_buff *newskb;
81662306a36Sopenharmony_ci	int ret = NETDEV_TX_OK;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	if (!delay) {
81962306a36Sopenharmony_ci		newskb = skb_clone(skb, GFP_ATOMIC);
82062306a36Sopenharmony_ci		if (!newskb)
82162306a36Sopenharmony_ci			return NETDEV_TX_BUSY;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		batadv_send_broadcast_skb(newskb, if_out);
82462306a36Sopenharmony_ci		num_bcasts--;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* delayed broadcast or rebroadcasts? */
82862306a36Sopenharmony_ci	if (num_bcasts >= 1) {
82962306a36Sopenharmony_ci		BATADV_SKB_CB(skb)->num_bcasts = num_bcasts;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		ret = batadv_forw_bcast_packet_to_list(bat_priv, skb, delay,
83262306a36Sopenharmony_ci						       own_packet, if_in,
83362306a36Sopenharmony_ci						       if_out);
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return ret;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci/**
84062306a36Sopenharmony_ci * batadv_send_no_broadcast() - check whether (re)broadcast is necessary
84162306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
84262306a36Sopenharmony_ci * @skb: broadcast packet to check
84362306a36Sopenharmony_ci * @own_packet: true if it is a self-generated broadcast packet
84462306a36Sopenharmony_ci * @if_out: the outgoing interface checked and considered for (re)broadcast
84562306a36Sopenharmony_ci *
84662306a36Sopenharmony_ci * Return: False if a packet needs to be (re)broadcasted on the given interface,
84762306a36Sopenharmony_ci * true otherwise.
84862306a36Sopenharmony_ci */
84962306a36Sopenharmony_cistatic bool batadv_send_no_broadcast(struct batadv_priv *bat_priv,
85062306a36Sopenharmony_ci				     struct sk_buff *skb, bool own_packet,
85162306a36Sopenharmony_ci				     struct batadv_hard_iface *if_out)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct batadv_hardif_neigh_node *neigh_node = NULL;
85462306a36Sopenharmony_ci	struct batadv_bcast_packet *bcast_packet;
85562306a36Sopenharmony_ci	u8 *orig_neigh;
85662306a36Sopenharmony_ci	u8 *neigh_addr;
85762306a36Sopenharmony_ci	char *type;
85862306a36Sopenharmony_ci	int ret;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if (!own_packet) {
86162306a36Sopenharmony_ci		neigh_addr = eth_hdr(skb)->h_source;
86262306a36Sopenharmony_ci		neigh_node = batadv_hardif_neigh_get(if_out,
86362306a36Sopenharmony_ci						     neigh_addr);
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	bcast_packet = (struct batadv_bcast_packet *)skb->data;
86762306a36Sopenharmony_ci	orig_neigh = neigh_node ? neigh_node->orig : NULL;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	ret = batadv_hardif_no_broadcast(if_out, bcast_packet->orig,
87062306a36Sopenharmony_ci					 orig_neigh);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	batadv_hardif_neigh_put(neigh_node);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	/* ok, may broadcast */
87562306a36Sopenharmony_ci	if (!ret)
87662306a36Sopenharmony_ci		return false;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* no broadcast */
87962306a36Sopenharmony_ci	switch (ret) {
88062306a36Sopenharmony_ci	case BATADV_HARDIF_BCAST_NORECIPIENT:
88162306a36Sopenharmony_ci		type = "no neighbor";
88262306a36Sopenharmony_ci		break;
88362306a36Sopenharmony_ci	case BATADV_HARDIF_BCAST_DUPFWD:
88462306a36Sopenharmony_ci		type = "single neighbor is source";
88562306a36Sopenharmony_ci		break;
88662306a36Sopenharmony_ci	case BATADV_HARDIF_BCAST_DUPORIG:
88762306a36Sopenharmony_ci		type = "single neighbor is originator";
88862306a36Sopenharmony_ci		break;
88962306a36Sopenharmony_ci	default:
89062306a36Sopenharmony_ci		type = "unknown";
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
89462306a36Sopenharmony_ci		   "BCAST packet from orig %pM on %s suppressed: %s\n",
89562306a36Sopenharmony_ci		   bcast_packet->orig,
89662306a36Sopenharmony_ci		   if_out->net_dev->name, type);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	return true;
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci/**
90262306a36Sopenharmony_ci * __batadv_forw_bcast_packet() - forward and queue a broadcast packet
90362306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
90462306a36Sopenharmony_ci * @skb: broadcast packet to add
90562306a36Sopenharmony_ci * @delay: number of jiffies to wait before sending
90662306a36Sopenharmony_ci * @own_packet: true if it is a self-generated broadcast packet
90762306a36Sopenharmony_ci *
90862306a36Sopenharmony_ci * Transmits a broadcast packet either immediately or if a delay is given
90962306a36Sopenharmony_ci * after that. Furthermore, queues additional retransmissions on wireless
91062306a36Sopenharmony_ci * interfaces.
91162306a36Sopenharmony_ci *
91262306a36Sopenharmony_ci * This call clones the given skb, hence the caller needs to take into
91362306a36Sopenharmony_ci * account that the data segment of the given skb might not be
91462306a36Sopenharmony_ci * modifiable anymore.
91562306a36Sopenharmony_ci *
91662306a36Sopenharmony_ci * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY on errors.
91762306a36Sopenharmony_ci */
91862306a36Sopenharmony_cistatic int __batadv_forw_bcast_packet(struct batadv_priv *bat_priv,
91962306a36Sopenharmony_ci				      struct sk_buff *skb,
92062306a36Sopenharmony_ci				      unsigned long delay,
92162306a36Sopenharmony_ci				      bool own_packet)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	struct batadv_hard_iface *hard_iface;
92462306a36Sopenharmony_ci	struct batadv_hard_iface *primary_if;
92562306a36Sopenharmony_ci	int ret = NETDEV_TX_OK;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
92862306a36Sopenharmony_ci	if (!primary_if)
92962306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	rcu_read_lock();
93262306a36Sopenharmony_ci	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
93362306a36Sopenharmony_ci		if (hard_iface->soft_iface != bat_priv->soft_iface)
93462306a36Sopenharmony_ci			continue;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		if (!kref_get_unless_zero(&hard_iface->refcount))
93762306a36Sopenharmony_ci			continue;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		if (batadv_send_no_broadcast(bat_priv, skb, own_packet,
94062306a36Sopenharmony_ci					     hard_iface)) {
94162306a36Sopenharmony_ci			batadv_hardif_put(hard_iface);
94262306a36Sopenharmony_ci			continue;
94362306a36Sopenharmony_ci		}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci		ret = batadv_forw_bcast_packet_if(bat_priv, skb, delay,
94662306a36Sopenharmony_ci						  own_packet, primary_if,
94762306a36Sopenharmony_ci						  hard_iface);
94862306a36Sopenharmony_ci		batadv_hardif_put(hard_iface);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		if (ret == NETDEV_TX_BUSY)
95162306a36Sopenharmony_ci			break;
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci	rcu_read_unlock();
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	batadv_hardif_put(primary_if);
95662306a36Sopenharmony_ci	return ret;
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci/**
96062306a36Sopenharmony_ci * batadv_forw_bcast_packet() - forward and queue a broadcast packet
96162306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
96262306a36Sopenharmony_ci * @skb: broadcast packet to add
96362306a36Sopenharmony_ci * @delay: number of jiffies to wait before sending
96462306a36Sopenharmony_ci * @own_packet: true if it is a self-generated broadcast packet
96562306a36Sopenharmony_ci *
96662306a36Sopenharmony_ci * Transmits a broadcast packet either immediately or if a delay is given
96762306a36Sopenharmony_ci * after that. Furthermore, queues additional retransmissions on wireless
96862306a36Sopenharmony_ci * interfaces.
96962306a36Sopenharmony_ci *
97062306a36Sopenharmony_ci * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY on errors.
97162306a36Sopenharmony_ci */
97262306a36Sopenharmony_ciint batadv_forw_bcast_packet(struct batadv_priv *bat_priv,
97362306a36Sopenharmony_ci			     struct sk_buff *skb,
97462306a36Sopenharmony_ci			     unsigned long delay,
97562306a36Sopenharmony_ci			     bool own_packet)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	return __batadv_forw_bcast_packet(bat_priv, skb, delay, own_packet);
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci/**
98162306a36Sopenharmony_ci * batadv_send_bcast_packet() - send and queue a broadcast packet
98262306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
98362306a36Sopenharmony_ci * @skb: broadcast packet to add
98462306a36Sopenharmony_ci * @delay: number of jiffies to wait before sending
98562306a36Sopenharmony_ci * @own_packet: true if it is a self-generated broadcast packet
98662306a36Sopenharmony_ci *
98762306a36Sopenharmony_ci * Transmits a broadcast packet either immediately or if a delay is given
98862306a36Sopenharmony_ci * after that. Furthermore, queues additional retransmissions on wireless
98962306a36Sopenharmony_ci * interfaces.
99062306a36Sopenharmony_ci *
99162306a36Sopenharmony_ci * Consumes the provided skb.
99262306a36Sopenharmony_ci */
99362306a36Sopenharmony_civoid batadv_send_bcast_packet(struct batadv_priv *bat_priv,
99462306a36Sopenharmony_ci			      struct sk_buff *skb,
99562306a36Sopenharmony_ci			      unsigned long delay,
99662306a36Sopenharmony_ci			      bool own_packet)
99762306a36Sopenharmony_ci{
99862306a36Sopenharmony_ci	__batadv_forw_bcast_packet(bat_priv, skb, delay, own_packet);
99962306a36Sopenharmony_ci	consume_skb(skb);
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci/**
100362306a36Sopenharmony_ci * batadv_forw_packet_bcasts_left() - check if a retransmission is necessary
100462306a36Sopenharmony_ci * @forw_packet: the forwarding packet to check
100562306a36Sopenharmony_ci *
100662306a36Sopenharmony_ci * Checks whether a given packet has any (re)transmissions left on the provided
100762306a36Sopenharmony_ci * interface.
100862306a36Sopenharmony_ci *
100962306a36Sopenharmony_ci * hard_iface may be NULL: In that case the number of transmissions this skb had
101062306a36Sopenharmony_ci * so far is compared with the maximum amount of retransmissions independent of
101162306a36Sopenharmony_ci * any interface instead.
101262306a36Sopenharmony_ci *
101362306a36Sopenharmony_ci * Return: True if (re)transmissions are left, false otherwise.
101462306a36Sopenharmony_ci */
101562306a36Sopenharmony_cistatic bool
101662306a36Sopenharmony_cibatadv_forw_packet_bcasts_left(struct batadv_forw_packet *forw_packet)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	return BATADV_SKB_CB(forw_packet->skb)->num_bcasts;
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci/**
102262306a36Sopenharmony_ci * batadv_forw_packet_bcasts_dec() - decrement retransmission counter of a
102362306a36Sopenharmony_ci *  packet
102462306a36Sopenharmony_ci * @forw_packet: the packet to decrease the counter for
102562306a36Sopenharmony_ci */
102662306a36Sopenharmony_cistatic void
102762306a36Sopenharmony_cibatadv_forw_packet_bcasts_dec(struct batadv_forw_packet *forw_packet)
102862306a36Sopenharmony_ci{
102962306a36Sopenharmony_ci	BATADV_SKB_CB(forw_packet->skb)->num_bcasts--;
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci/**
103362306a36Sopenharmony_ci * batadv_forw_packet_is_rebroadcast() - check packet for previous transmissions
103462306a36Sopenharmony_ci * @forw_packet: the packet to check
103562306a36Sopenharmony_ci *
103662306a36Sopenharmony_ci * Return: True if this packet was transmitted before, false otherwise.
103762306a36Sopenharmony_ci */
103862306a36Sopenharmony_cibool batadv_forw_packet_is_rebroadcast(struct batadv_forw_packet *forw_packet)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	unsigned char num_bcasts = BATADV_SKB_CB(forw_packet->skb)->num_bcasts;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	return num_bcasts != forw_packet->if_outgoing->num_bcasts;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci/**
104662306a36Sopenharmony_ci * batadv_send_outstanding_bcast_packet() - transmit a queued broadcast packet
104762306a36Sopenharmony_ci * @work: work queue item
104862306a36Sopenharmony_ci *
104962306a36Sopenharmony_ci * Transmits a queued broadcast packet and if necessary reschedules it.
105062306a36Sopenharmony_ci */
105162306a36Sopenharmony_cistatic void batadv_send_outstanding_bcast_packet(struct work_struct *work)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	unsigned long send_time = jiffies + msecs_to_jiffies(5);
105462306a36Sopenharmony_ci	struct batadv_forw_packet *forw_packet;
105562306a36Sopenharmony_ci	struct delayed_work *delayed_work;
105662306a36Sopenharmony_ci	struct batadv_priv *bat_priv;
105762306a36Sopenharmony_ci	struct sk_buff *skb1;
105862306a36Sopenharmony_ci	bool dropped = false;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	delayed_work = to_delayed_work(work);
106162306a36Sopenharmony_ci	forw_packet = container_of(delayed_work, struct batadv_forw_packet,
106262306a36Sopenharmony_ci				   delayed_work);
106362306a36Sopenharmony_ci	bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
106662306a36Sopenharmony_ci		dropped = true;
106762306a36Sopenharmony_ci		goto out;
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (batadv_dat_drop_broadcast_packet(bat_priv, forw_packet)) {
107162306a36Sopenharmony_ci		dropped = true;
107262306a36Sopenharmony_ci		goto out;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/* send a copy of the saved skb */
107662306a36Sopenharmony_ci	skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
107762306a36Sopenharmony_ci	if (!skb1)
107862306a36Sopenharmony_ci		goto out;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	batadv_send_broadcast_skb(skb1, forw_packet->if_outgoing);
108162306a36Sopenharmony_ci	batadv_forw_packet_bcasts_dec(forw_packet);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (batadv_forw_packet_bcasts_left(forw_packet)) {
108462306a36Sopenharmony_ci		batadv_forw_packet_bcast_queue(bat_priv, forw_packet,
108562306a36Sopenharmony_ci					       send_time);
108662306a36Sopenharmony_ci		return;
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ciout:
109062306a36Sopenharmony_ci	/* do we get something for free()? */
109162306a36Sopenharmony_ci	if (batadv_forw_packet_steal(forw_packet,
109262306a36Sopenharmony_ci				     &bat_priv->forw_bcast_list_lock))
109362306a36Sopenharmony_ci		batadv_forw_packet_free(forw_packet, dropped);
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci/**
109762306a36Sopenharmony_ci * batadv_purge_outstanding_packets() - stop/purge scheduled bcast/OGMv1 packets
109862306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
109962306a36Sopenharmony_ci * @hard_iface: the hard interface to cancel and purge bcast/ogm packets on
110062306a36Sopenharmony_ci *
110162306a36Sopenharmony_ci * This method cancels and purges any broadcast and OGMv1 packet on the given
110262306a36Sopenharmony_ci * hard_iface. If hard_iface is NULL, broadcast and OGMv1 packets on all hard
110362306a36Sopenharmony_ci * interfaces will be canceled and purged.
110462306a36Sopenharmony_ci *
110562306a36Sopenharmony_ci * This function might sleep.
110662306a36Sopenharmony_ci */
110762306a36Sopenharmony_civoid
110862306a36Sopenharmony_cibatadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
110962306a36Sopenharmony_ci				 const struct batadv_hard_iface *hard_iface)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	struct hlist_head head = HLIST_HEAD_INIT;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (hard_iface)
111462306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
111562306a36Sopenharmony_ci			   "%s(): %s\n",
111662306a36Sopenharmony_ci			   __func__, hard_iface->net_dev->name);
111762306a36Sopenharmony_ci	else
111862306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
111962306a36Sopenharmony_ci			   "%s()\n", __func__);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	/* claim bcast list for free() */
112262306a36Sopenharmony_ci	spin_lock_bh(&bat_priv->forw_bcast_list_lock);
112362306a36Sopenharmony_ci	batadv_forw_packet_list_steal(&bat_priv->forw_bcast_list, &head,
112462306a36Sopenharmony_ci				      hard_iface);
112562306a36Sopenharmony_ci	spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	/* claim batman packet list for free() */
112862306a36Sopenharmony_ci	spin_lock_bh(&bat_priv->forw_bat_list_lock);
112962306a36Sopenharmony_ci	batadv_forw_packet_list_steal(&bat_priv->forw_bat_list, &head,
113062306a36Sopenharmony_ci				      hard_iface);
113162306a36Sopenharmony_ci	spin_unlock_bh(&bat_priv->forw_bat_list_lock);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/* then cancel or wait for packet workers to finish and free */
113462306a36Sopenharmony_ci	batadv_forw_packet_list_free(&head);
113562306a36Sopenharmony_ci}
1136