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