xref: /linux/net/batman-adv/bat_v_ogm.c (revision f89255a02f1d75d8e1b9d1c31435fcb64840cb2a)
17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
27a79d717SSven Eckelmann /* Copyright (C) 2013-2019  B.A.T.M.A.N. contributors:
30da00359SAntonio Quartulli  *
40da00359SAntonio Quartulli  * Antonio Quartulli
50da00359SAntonio Quartulli  */
60da00359SAntonio Quartulli 
70da00359SAntonio Quartulli #include "bat_v_ogm.h"
80da00359SAntonio Quartulli #include "main.h"
90da00359SAntonio Quartulli 
100da00359SAntonio Quartulli #include <linux/atomic.h>
110da00359SAntonio Quartulli #include <linux/byteorder/generic.h>
120da00359SAntonio Quartulli #include <linux/errno.h>
130da00359SAntonio Quartulli #include <linux/etherdevice.h>
14b92b94acSSven Eckelmann #include <linux/gfp.h>
150da00359SAntonio Quartulli #include <linux/if_ether.h>
160da00359SAntonio Quartulli #include <linux/jiffies.h>
170da00359SAntonio Quartulli #include <linux/kernel.h>
1827353446SSven Eckelmann #include <linux/kref.h>
199323158eSAntonio Quartulli #include <linux/list.h>
20*f89255a0SLinus Lüssing #include <linux/lockdep.h>
210da00359SAntonio Quartulli #include <linux/netdevice.h>
220da00359SAntonio Quartulli #include <linux/random.h>
230da00359SAntonio Quartulli #include <linux/rculist.h>
240da00359SAntonio Quartulli #include <linux/rcupdate.h>
250da00359SAntonio Quartulli #include <linux/skbuff.h>
260da00359SAntonio Quartulli #include <linux/slab.h>
27*f89255a0SLinus Lüssing #include <linux/spinlock.h>
280da00359SAntonio Quartulli #include <linux/stddef.h>
290da00359SAntonio Quartulli #include <linux/string.h>
300da00359SAntonio Quartulli #include <linux/types.h>
310da00359SAntonio Quartulli #include <linux/workqueue.h>
32fec149f5SSven Eckelmann #include <uapi/linux/batadv_packet.h>
330da00359SAntonio Quartulli 
3401d350d1SSven Eckelmann #include "bat_algo.h"
350da00359SAntonio Quartulli #include "hard-interface.h"
369323158eSAntonio Quartulli #include "hash.h"
37ba412080SSven Eckelmann #include "log.h"
389323158eSAntonio Quartulli #include "originator.h"
390da00359SAntonio Quartulli #include "routing.h"
400da00359SAntonio Quartulli #include "send.h"
410da00359SAntonio Quartulli #include "translation-table.h"
421f8dce49SMarkus Pargmann #include "tvlv.h"
430da00359SAntonio Quartulli 
440da00359SAntonio Quartulli /**
457e9a8c2cSSven Eckelmann  * batadv_v_ogm_orig_get() - retrieve and possibly create an originator node
469323158eSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
479323158eSAntonio Quartulli  * @addr: the address of the originator
489323158eSAntonio Quartulli  *
499323158eSAntonio Quartulli  * Return: the orig_node corresponding to the specified address. If such object
509323158eSAntonio Quartulli  * does not exist it is allocated here. In case of allocation failure returns
519323158eSAntonio Quartulli  * NULL.
529323158eSAntonio Quartulli  */
539323158eSAntonio Quartulli struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
549323158eSAntonio Quartulli 					       const u8 *addr)
559323158eSAntonio Quartulli {
569323158eSAntonio Quartulli 	struct batadv_orig_node *orig_node;
579323158eSAntonio Quartulli 	int hash_added;
589323158eSAntonio Quartulli 
599323158eSAntonio Quartulli 	orig_node = batadv_orig_hash_find(bat_priv, addr);
609323158eSAntonio Quartulli 	if (orig_node)
619323158eSAntonio Quartulli 		return orig_node;
629323158eSAntonio Quartulli 
639323158eSAntonio Quartulli 	orig_node = batadv_orig_node_new(bat_priv, addr);
649323158eSAntonio Quartulli 	if (!orig_node)
659323158eSAntonio Quartulli 		return NULL;
669323158eSAntonio Quartulli 
6755db2d59SSven Eckelmann 	kref_get(&orig_node->refcount);
689323158eSAntonio Quartulli 	hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
699323158eSAntonio Quartulli 				     batadv_choose_orig, orig_node,
709323158eSAntonio Quartulli 				     &orig_node->hash_entry);
719323158eSAntonio Quartulli 	if (hash_added != 0) {
7255db2d59SSven Eckelmann 		/* remove refcnt for newly created orig_node and hash entry */
739323158eSAntonio Quartulli 		batadv_orig_node_put(orig_node);
749323158eSAntonio Quartulli 		batadv_orig_node_put(orig_node);
759323158eSAntonio Quartulli 		orig_node = NULL;
769323158eSAntonio Quartulli 	}
779323158eSAntonio Quartulli 
789323158eSAntonio Quartulli 	return orig_node;
799323158eSAntonio Quartulli }
809323158eSAntonio Quartulli 
819323158eSAntonio Quartulli /**
82*f89255a0SLinus Lüssing  * batadv_v_ogm_start_queue_timer() - restart the OGM aggregation timer
83*f89255a0SLinus Lüssing  * @hard_iface: the interface to use to send the OGM
84*f89255a0SLinus Lüssing  */
85*f89255a0SLinus Lüssing static void batadv_v_ogm_start_queue_timer(struct batadv_hard_iface *hard_iface)
86*f89255a0SLinus Lüssing {
87*f89255a0SLinus Lüssing 	unsigned int msecs = BATADV_MAX_AGGREGATION_MS * 1000;
88*f89255a0SLinus Lüssing 
89*f89255a0SLinus Lüssing 	/* msecs * [0.9, 1.1] */
90*f89255a0SLinus Lüssing 	msecs += prandom_u32() % (msecs / 5) - (msecs / 10);
91*f89255a0SLinus Lüssing 	queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.aggr_wq,
92*f89255a0SLinus Lüssing 			   msecs_to_jiffies(msecs / 1000));
93*f89255a0SLinus Lüssing }
94*f89255a0SLinus Lüssing 
95*f89255a0SLinus Lüssing /**
967e9a8c2cSSven Eckelmann  * batadv_v_ogm_start_timer() - restart the OGM sending timer
970da00359SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
980da00359SAntonio Quartulli  */
990da00359SAntonio Quartulli static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
1000da00359SAntonio Quartulli {
1010da00359SAntonio Quartulli 	unsigned long msecs;
1020da00359SAntonio Quartulli 	/* this function may be invoked in different contexts (ogm rescheduling
1030da00359SAntonio Quartulli 	 * or hard_iface activation), but the work timer should not be reset
1040da00359SAntonio Quartulli 	 */
1050da00359SAntonio Quartulli 	if (delayed_work_pending(&bat_priv->bat_v.ogm_wq))
1060da00359SAntonio Quartulli 		return;
1070da00359SAntonio Quartulli 
1080da00359SAntonio Quartulli 	msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
1090da00359SAntonio Quartulli 	msecs += prandom_u32() % (2 * BATADV_JITTER);
1100da00359SAntonio Quartulli 	queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq,
1110da00359SAntonio Quartulli 			   msecs_to_jiffies(msecs));
1120da00359SAntonio Quartulli }
1130da00359SAntonio Quartulli 
1140da00359SAntonio Quartulli /**
1157e9a8c2cSSven Eckelmann  * batadv_v_ogm_send_to_if() - send a batman ogm using a given interface
1160da00359SAntonio Quartulli  * @skb: the OGM to send
1170da00359SAntonio Quartulli  * @hard_iface: the interface to use to send the OGM
1180da00359SAntonio Quartulli  */
1190da00359SAntonio Quartulli static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
1200da00359SAntonio Quartulli 				    struct batadv_hard_iface *hard_iface)
1210da00359SAntonio Quartulli {
1220da00359SAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
1230da00359SAntonio Quartulli 
1240da00359SAntonio Quartulli 	if (hard_iface->if_status != BATADV_IF_ACTIVE)
1250da00359SAntonio Quartulli 		return;
1260da00359SAntonio Quartulli 
1270da00359SAntonio Quartulli 	batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
1280da00359SAntonio Quartulli 	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
1290da00359SAntonio Quartulli 			   skb->len + ETH_HLEN);
1300da00359SAntonio Quartulli 
13195d39278SAntonio Quartulli 	batadv_send_broadcast_skb(skb, hard_iface);
1320da00359SAntonio Quartulli }
1330da00359SAntonio Quartulli 
1340da00359SAntonio Quartulli /**
135*f89255a0SLinus Lüssing  * batadv_v_ogm_len() - OGMv2 packet length
136*f89255a0SLinus Lüssing  * @skb: the OGM to check
137*f89255a0SLinus Lüssing  *
138*f89255a0SLinus Lüssing  * Return: Length of the given OGMv2 packet, including tvlv length, excluding
139*f89255a0SLinus Lüssing  * ethernet header length.
140*f89255a0SLinus Lüssing  */
141*f89255a0SLinus Lüssing static unsigned int batadv_v_ogm_len(struct sk_buff *skb)
142*f89255a0SLinus Lüssing {
143*f89255a0SLinus Lüssing 	struct batadv_ogm2_packet *ogm_packet;
144*f89255a0SLinus Lüssing 
145*f89255a0SLinus Lüssing 	ogm_packet = (struct batadv_ogm2_packet *)skb->data;
146*f89255a0SLinus Lüssing 	return BATADV_OGM2_HLEN + ntohs(ogm_packet->tvlv_len);
147*f89255a0SLinus Lüssing }
148*f89255a0SLinus Lüssing 
149*f89255a0SLinus Lüssing /**
150*f89255a0SLinus Lüssing  * batadv_v_ogm_queue_left() - check if given OGM still fits aggregation queue
151*f89255a0SLinus Lüssing  * @skb: the OGM to check
152*f89255a0SLinus Lüssing  * @hard_iface: the interface to use to send the OGM
153*f89255a0SLinus Lüssing  *
154*f89255a0SLinus Lüssing  * Caller needs to hold the hard_iface->bat_v.aggr_list_lock.
155*f89255a0SLinus Lüssing  *
156*f89255a0SLinus Lüssing  * Return: True, if the given OGMv2 packet still fits, false otherwise.
157*f89255a0SLinus Lüssing  */
158*f89255a0SLinus Lüssing static bool batadv_v_ogm_queue_left(struct sk_buff *skb,
159*f89255a0SLinus Lüssing 				    struct batadv_hard_iface *hard_iface)
160*f89255a0SLinus Lüssing {
161*f89255a0SLinus Lüssing 	unsigned int max = min_t(unsigned int, hard_iface->net_dev->mtu,
162*f89255a0SLinus Lüssing 				 BATADV_MAX_AGGREGATION_BYTES);
163*f89255a0SLinus Lüssing 	unsigned int ogm_len = batadv_v_ogm_len(skb);
164*f89255a0SLinus Lüssing 
165*f89255a0SLinus Lüssing 	lockdep_assert_held(&hard_iface->bat_v.aggr_list_lock);
166*f89255a0SLinus Lüssing 
167*f89255a0SLinus Lüssing 	return hard_iface->bat_v.aggr_len + ogm_len <= max;
168*f89255a0SLinus Lüssing }
169*f89255a0SLinus Lüssing 
170*f89255a0SLinus Lüssing /**
171*f89255a0SLinus Lüssing  * batadv_v_ogm_aggr_list_free - free all elements in an aggregation queue
172*f89255a0SLinus Lüssing  * @hard_iface: the interface holding the aggregation queue
173*f89255a0SLinus Lüssing  *
174*f89255a0SLinus Lüssing  * Empties the OGMv2 aggregation queue and frees all the skbs it contained.
175*f89255a0SLinus Lüssing  *
176*f89255a0SLinus Lüssing  * Caller needs to hold the hard_iface->bat_v.aggr_list_lock.
177*f89255a0SLinus Lüssing  */
178*f89255a0SLinus Lüssing static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
179*f89255a0SLinus Lüssing {
180*f89255a0SLinus Lüssing 	struct sk_buff *skb;
181*f89255a0SLinus Lüssing 
182*f89255a0SLinus Lüssing 	lockdep_assert_held(&hard_iface->bat_v.aggr_list_lock);
183*f89255a0SLinus Lüssing 
184*f89255a0SLinus Lüssing 	while ((skb = skb_dequeue(&hard_iface->bat_v.aggr_list)))
185*f89255a0SLinus Lüssing 		kfree_skb(skb);
186*f89255a0SLinus Lüssing 
187*f89255a0SLinus Lüssing 	hard_iface->bat_v.aggr_len = 0;
188*f89255a0SLinus Lüssing }
189*f89255a0SLinus Lüssing 
190*f89255a0SLinus Lüssing /**
191*f89255a0SLinus Lüssing  * batadv_v_ogm_aggr_send() - flush & send aggregation queue
192*f89255a0SLinus Lüssing  * @hard_iface: the interface with the aggregation queue to flush
193*f89255a0SLinus Lüssing  *
194*f89255a0SLinus Lüssing  * Caller needs to hold the hard_iface->bat_v.aggr_list_lock.
195*f89255a0SLinus Lüssing  */
196*f89255a0SLinus Lüssing static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
197*f89255a0SLinus Lüssing {
198*f89255a0SLinus Lüssing 	struct sk_buff *skb;
199*f89255a0SLinus Lüssing 
200*f89255a0SLinus Lüssing 	lockdep_assert_held(&hard_iface->bat_v.aggr_list_lock);
201*f89255a0SLinus Lüssing 
202*f89255a0SLinus Lüssing 	while ((skb = skb_dequeue(&hard_iface->bat_v.aggr_list))) {
203*f89255a0SLinus Lüssing 		hard_iface->bat_v.aggr_len -= batadv_v_ogm_len(skb);
204*f89255a0SLinus Lüssing 		batadv_v_ogm_send_to_if(skb, hard_iface);
205*f89255a0SLinus Lüssing 	}
206*f89255a0SLinus Lüssing }
207*f89255a0SLinus Lüssing 
208*f89255a0SLinus Lüssing /**
209*f89255a0SLinus Lüssing  * batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface
210*f89255a0SLinus Lüssing  * @skb: the OGM to queue
211*f89255a0SLinus Lüssing  * @hard_iface: the interface to queue the OGM on
212*f89255a0SLinus Lüssing  */
213*f89255a0SLinus Lüssing static void batadv_v_ogm_queue_on_if(struct sk_buff *skb,
214*f89255a0SLinus Lüssing 				     struct batadv_hard_iface *hard_iface)
215*f89255a0SLinus Lüssing {
216*f89255a0SLinus Lüssing 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
217*f89255a0SLinus Lüssing 
218*f89255a0SLinus Lüssing 	if (!atomic_read(&bat_priv->aggregated_ogms)) {
219*f89255a0SLinus Lüssing 		batadv_v_ogm_send_to_if(skb, hard_iface);
220*f89255a0SLinus Lüssing 		return;
221*f89255a0SLinus Lüssing 	}
222*f89255a0SLinus Lüssing 
223*f89255a0SLinus Lüssing 	spin_lock_bh(&hard_iface->bat_v.aggr_list_lock);
224*f89255a0SLinus Lüssing 	if (!batadv_v_ogm_queue_left(skb, hard_iface))
225*f89255a0SLinus Lüssing 		batadv_v_ogm_aggr_send(hard_iface);
226*f89255a0SLinus Lüssing 
227*f89255a0SLinus Lüssing 	hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb);
228*f89255a0SLinus Lüssing 	skb_queue_tail(&hard_iface->bat_v.aggr_list, skb);
229*f89255a0SLinus Lüssing 	spin_unlock_bh(&hard_iface->bat_v.aggr_list_lock);
230*f89255a0SLinus Lüssing }
231*f89255a0SLinus Lüssing 
232*f89255a0SLinus Lüssing /**
2337e9a8c2cSSven Eckelmann  * batadv_v_ogm_send() - periodic worker broadcasting the own OGM
2340da00359SAntonio Quartulli  * @work: work queue item
2350da00359SAntonio Quartulli  */
2360da00359SAntonio Quartulli static void batadv_v_ogm_send(struct work_struct *work)
2370da00359SAntonio Quartulli {
2380da00359SAntonio Quartulli 	struct batadv_hard_iface *hard_iface;
2390da00359SAntonio Quartulli 	struct batadv_priv_bat_v *bat_v;
2400da00359SAntonio Quartulli 	struct batadv_priv *bat_priv;
2410da00359SAntonio Quartulli 	struct batadv_ogm2_packet *ogm_packet;
2420da00359SAntonio Quartulli 	struct sk_buff *skb, *skb_tmp;
243e04de486SSven Eckelmann 	unsigned char *ogm_buff;
2440da00359SAntonio Quartulli 	int ogm_buff_len;
2450da00359SAntonio Quartulli 	u16 tvlv_len = 0;
2463111beedSLinus Lüssing 	int ret;
2470da00359SAntonio Quartulli 
2480da00359SAntonio Quartulli 	bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
2490da00359SAntonio Quartulli 	bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
2500da00359SAntonio Quartulli 
2510da00359SAntonio Quartulli 	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
2520da00359SAntonio Quartulli 		goto out;
2530da00359SAntonio Quartulli 
2540da00359SAntonio Quartulli 	ogm_buff = bat_priv->bat_v.ogm_buff;
2550da00359SAntonio Quartulli 	ogm_buff_len = bat_priv->bat_v.ogm_buff_len;
2560da00359SAntonio Quartulli 	/* tt changes have to be committed before the tvlv data is
2570da00359SAntonio Quartulli 	 * appended as it may alter the tt tvlv container
2580da00359SAntonio Quartulli 	 */
2590da00359SAntonio Quartulli 	batadv_tt_local_commit_changes(bat_priv);
2600da00359SAntonio Quartulli 	tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
2610da00359SAntonio Quartulli 						    &ogm_buff_len,
2620da00359SAntonio Quartulli 						    BATADV_OGM2_HLEN);
2630da00359SAntonio Quartulli 
2640da00359SAntonio Quartulli 	bat_priv->bat_v.ogm_buff = ogm_buff;
2650da00359SAntonio Quartulli 	bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
2660da00359SAntonio Quartulli 
2670da00359SAntonio Quartulli 	skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
2680da00359SAntonio Quartulli 	if (!skb)
2690da00359SAntonio Quartulli 		goto reschedule;
2700da00359SAntonio Quartulli 
2710da00359SAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
272e04de486SSven Eckelmann 	skb_put_data(skb, ogm_buff, ogm_buff_len);
2730da00359SAntonio Quartulli 
2740da00359SAntonio Quartulli 	ogm_packet = (struct batadv_ogm2_packet *)skb->data;
2750da00359SAntonio Quartulli 	ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
2760da00359SAntonio Quartulli 	atomic_inc(&bat_priv->bat_v.ogm_seqno);
2770da00359SAntonio Quartulli 	ogm_packet->tvlv_len = htons(tvlv_len);
2780da00359SAntonio Quartulli 
2790da00359SAntonio Quartulli 	/* broadcast on every interface */
2800da00359SAntonio Quartulli 	rcu_read_lock();
2810da00359SAntonio Quartulli 	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
2820da00359SAntonio Quartulli 		if (hard_iface->soft_iface != bat_priv->soft_iface)
2830da00359SAntonio Quartulli 			continue;
2840da00359SAntonio Quartulli 
28527353446SSven Eckelmann 		if (!kref_get_unless_zero(&hard_iface->refcount))
28627353446SSven Eckelmann 			continue;
28727353446SSven Eckelmann 
2883111beedSLinus Lüssing 		ret = batadv_hardif_no_broadcast(hard_iface, NULL, NULL);
2893111beedSLinus Lüssing 		if (ret) {
2903111beedSLinus Lüssing 			char *type;
2913111beedSLinus Lüssing 
2923111beedSLinus Lüssing 			switch (ret) {
2933111beedSLinus Lüssing 			case BATADV_HARDIF_BCAST_NORECIPIENT:
2943111beedSLinus Lüssing 				type = "no neighbor";
2953111beedSLinus Lüssing 				break;
2963111beedSLinus Lüssing 			case BATADV_HARDIF_BCAST_DUPFWD:
2973111beedSLinus Lüssing 				type = "single neighbor is source";
2983111beedSLinus Lüssing 				break;
2993111beedSLinus Lüssing 			case BATADV_HARDIF_BCAST_DUPORIG:
3003111beedSLinus Lüssing 				type = "single neighbor is originator";
3013111beedSLinus Lüssing 				break;
3023111beedSLinus Lüssing 			default:
3033111beedSLinus Lüssing 				type = "unknown";
3043111beedSLinus Lüssing 			}
3053111beedSLinus Lüssing 
306f25cbb2aSColin Ian King 			batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 from ourselves on %s suppressed: %s\n",
3073111beedSLinus Lüssing 				   hard_iface->net_dev->name, type);
3083111beedSLinus Lüssing 
3093111beedSLinus Lüssing 			batadv_hardif_put(hard_iface);
3103111beedSLinus Lüssing 			continue;
3113111beedSLinus Lüssing 		}
3123111beedSLinus Lüssing 
3130da00359SAntonio Quartulli 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
3140da00359SAntonio Quartulli 			   "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
3150da00359SAntonio Quartulli 			   ogm_packet->orig, ntohl(ogm_packet->seqno),
3160da00359SAntonio Quartulli 			   ntohl(ogm_packet->throughput), ogm_packet->ttl,
3170da00359SAntonio Quartulli 			   hard_iface->net_dev->name,
3180da00359SAntonio Quartulli 			   hard_iface->net_dev->dev_addr);
3190da00359SAntonio Quartulli 
3200da00359SAntonio Quartulli 		/* this skb gets consumed by batadv_v_ogm_send_to_if() */
3210da00359SAntonio Quartulli 		skb_tmp = skb_clone(skb, GFP_ATOMIC);
32227353446SSven Eckelmann 		if (!skb_tmp) {
32327353446SSven Eckelmann 			batadv_hardif_put(hard_iface);
3240da00359SAntonio Quartulli 			break;
32527353446SSven Eckelmann 		}
3260da00359SAntonio Quartulli 
327*f89255a0SLinus Lüssing 		batadv_v_ogm_queue_on_if(skb_tmp, hard_iface);
32827353446SSven Eckelmann 		batadv_hardif_put(hard_iface);
3290da00359SAntonio Quartulli 	}
3300da00359SAntonio Quartulli 	rcu_read_unlock();
3310da00359SAntonio Quartulli 
3320da00359SAntonio Quartulli 	consume_skb(skb);
3330da00359SAntonio Quartulli 
3340da00359SAntonio Quartulli reschedule:
3350da00359SAntonio Quartulli 	batadv_v_ogm_start_timer(bat_priv);
3360da00359SAntonio Quartulli out:
3370da00359SAntonio Quartulli 	return;
3380da00359SAntonio Quartulli }
3390da00359SAntonio Quartulli 
3400da00359SAntonio Quartulli /**
341*f89255a0SLinus Lüssing  * batadv_v_ogm_aggr_work() - OGM queue periodic task per interface
342*f89255a0SLinus Lüssing  * @work: work queue item
343*f89255a0SLinus Lüssing  *
344*f89255a0SLinus Lüssing  * Emits aggregated OGM message in regular intervals.
345*f89255a0SLinus Lüssing  */
346*f89255a0SLinus Lüssing void batadv_v_ogm_aggr_work(struct work_struct *work)
347*f89255a0SLinus Lüssing {
348*f89255a0SLinus Lüssing 	struct batadv_hard_iface_bat_v *batv;
349*f89255a0SLinus Lüssing 	struct batadv_hard_iface *hard_iface;
350*f89255a0SLinus Lüssing 
351*f89255a0SLinus Lüssing 	batv = container_of(work, struct batadv_hard_iface_bat_v, aggr_wq.work);
352*f89255a0SLinus Lüssing 	hard_iface = container_of(batv, struct batadv_hard_iface, bat_v);
353*f89255a0SLinus Lüssing 
354*f89255a0SLinus Lüssing 	spin_lock_bh(&hard_iface->bat_v.aggr_list_lock);
355*f89255a0SLinus Lüssing 	batadv_v_ogm_aggr_send(hard_iface);
356*f89255a0SLinus Lüssing 	spin_unlock_bh(&hard_iface->bat_v.aggr_list_lock);
357*f89255a0SLinus Lüssing 
358*f89255a0SLinus Lüssing 	batadv_v_ogm_start_queue_timer(hard_iface);
359*f89255a0SLinus Lüssing }
360*f89255a0SLinus Lüssing 
361*f89255a0SLinus Lüssing /**
3627e9a8c2cSSven Eckelmann  * batadv_v_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. V
3630da00359SAntonio Quartulli  * @hard_iface: the interface to prepare
3640da00359SAntonio Quartulli  *
3650da00359SAntonio Quartulli  * Takes care of scheduling own OGM sending routine for this interface.
3660da00359SAntonio Quartulli  *
3670da00359SAntonio Quartulli  * Return: 0 on success or a negative error code otherwise
3680da00359SAntonio Quartulli  */
3690da00359SAntonio Quartulli int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
3700da00359SAntonio Quartulli {
3710da00359SAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
3720da00359SAntonio Quartulli 
373*f89255a0SLinus Lüssing 	batadv_v_ogm_start_queue_timer(hard_iface);
3740da00359SAntonio Quartulli 	batadv_v_ogm_start_timer(bat_priv);
3750da00359SAntonio Quartulli 
3760da00359SAntonio Quartulli 	return 0;
3770da00359SAntonio Quartulli }
3780da00359SAntonio Quartulli 
3790da00359SAntonio Quartulli /**
380*f89255a0SLinus Lüssing  * batadv_v_ogm_iface_disable() - release OGM interface private resources
381*f89255a0SLinus Lüssing  * @hard_iface: interface for which the resources have to be released
382*f89255a0SLinus Lüssing  */
383*f89255a0SLinus Lüssing void batadv_v_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
384*f89255a0SLinus Lüssing {
385*f89255a0SLinus Lüssing 	cancel_delayed_work_sync(&hard_iface->bat_v.aggr_wq);
386*f89255a0SLinus Lüssing 
387*f89255a0SLinus Lüssing 	spin_lock_bh(&hard_iface->bat_v.aggr_list_lock);
388*f89255a0SLinus Lüssing 	batadv_v_ogm_aggr_list_free(hard_iface);
389*f89255a0SLinus Lüssing 	spin_unlock_bh(&hard_iface->bat_v.aggr_list_lock);
390*f89255a0SLinus Lüssing }
391*f89255a0SLinus Lüssing 
392*f89255a0SLinus Lüssing /**
3937e9a8c2cSSven Eckelmann  * batadv_v_ogm_primary_iface_set() - set a new primary interface
3940da00359SAntonio Quartulli  * @primary_iface: the new primary interface
3950da00359SAntonio Quartulli  */
3960da00359SAntonio Quartulli void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface)
3970da00359SAntonio Quartulli {
3980da00359SAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(primary_iface->soft_iface);
3990da00359SAntonio Quartulli 	struct batadv_ogm2_packet *ogm_packet;
4000da00359SAntonio Quartulli 
4010da00359SAntonio Quartulli 	if (!bat_priv->bat_v.ogm_buff)
4020da00359SAntonio Quartulli 		return;
4030da00359SAntonio Quartulli 
4040da00359SAntonio Quartulli 	ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
4050da00359SAntonio Quartulli 	ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
4060da00359SAntonio Quartulli }
4070da00359SAntonio Quartulli 
4080da00359SAntonio Quartulli /**
4097e9a8c2cSSven Eckelmann  * batadv_v_forward_penalty() - apply a penalty to the throughput metric
4107e9a8c2cSSven Eckelmann  *  forwarded with B.A.T.M.A.N. V OGMs
4119323158eSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
4129323158eSAntonio Quartulli  * @if_incoming: the interface where the OGM has been received
4139323158eSAntonio Quartulli  * @if_outgoing: the interface where the OGM has to be forwarded to
4149323158eSAntonio Quartulli  * @throughput: the current throughput
4159323158eSAntonio Quartulli  *
4169323158eSAntonio Quartulli  * Apply a penalty on the current throughput metric value based on the
4179323158eSAntonio Quartulli  * characteristic of the interface where the OGM has been received. The return
4189323158eSAntonio Quartulli  * value is computed as follows:
4199323158eSAntonio Quartulli  * - throughput * 50%          if the incoming and outgoing interface are the
4209323158eSAntonio Quartulli  *                             same WiFi interface and the throughput is above
4219323158eSAntonio Quartulli  *                             1MBit/s
4229323158eSAntonio Quartulli  * - throughput                if the outgoing interface is the default
4239323158eSAntonio Quartulli  *                             interface (i.e. this OGM is processed for the
4249323158eSAntonio Quartulli  *                             internal table and not forwarded)
4259323158eSAntonio Quartulli  * - throughput * hop penalty  otherwise
4269323158eSAntonio Quartulli  *
4279323158eSAntonio Quartulli  * Return: the penalised throughput metric.
4289323158eSAntonio Quartulli  */
4299323158eSAntonio Quartulli static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv,
4309323158eSAntonio Quartulli 				    struct batadv_hard_iface *if_incoming,
4319323158eSAntonio Quartulli 				    struct batadv_hard_iface *if_outgoing,
4329323158eSAntonio Quartulli 				    u32 throughput)
4339323158eSAntonio Quartulli {
4349323158eSAntonio Quartulli 	int hop_penalty = atomic_read(&bat_priv->hop_penalty);
4359323158eSAntonio Quartulli 	int hop_penalty_max = BATADV_TQ_MAX_VALUE;
4369323158eSAntonio Quartulli 
4379323158eSAntonio Quartulli 	/* Don't apply hop penalty in default originator table. */
4389323158eSAntonio Quartulli 	if (if_outgoing == BATADV_IF_DEFAULT)
4399323158eSAntonio Quartulli 		return throughput;
4409323158eSAntonio Quartulli 
4419323158eSAntonio Quartulli 	/* Forwarding on the same WiFi interface cuts the throughput in half
4429323158eSAntonio Quartulli 	 * due to the store & forward characteristics of WIFI.
4439323158eSAntonio Quartulli 	 * Very low throughput values are the exception.
4449323158eSAntonio Quartulli 	 */
445825ffe1fSSven Eckelmann 	if (throughput > 10 &&
446825ffe1fSSven Eckelmann 	    if_incoming == if_outgoing &&
447c833484eSAntonio Quartulli 	    !(if_incoming->bat_v.flags & BATADV_FULL_DUPLEX))
4489323158eSAntonio Quartulli 		return throughput / 2;
4499323158eSAntonio Quartulli 
4509323158eSAntonio Quartulli 	/* hop penalty of 255 equals 100% */
4519323158eSAntonio Quartulli 	return throughput * (hop_penalty_max - hop_penalty) / hop_penalty_max;
4529323158eSAntonio Quartulli }
4539323158eSAntonio Quartulli 
4549323158eSAntonio Quartulli /**
4557e9a8c2cSSven Eckelmann  * batadv_v_ogm_forward() - check conditions and forward an OGM to the given
456efcc9d30SSimon Wunderlich  *  outgoing interface
4579323158eSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
4589323158eSAntonio Quartulli  * @ogm_received: previously received OGM to be forwarded
459efcc9d30SSimon Wunderlich  * @orig_node: the originator which has been updated
460efcc9d30SSimon Wunderlich  * @neigh_node: the neigh_node through with the OGM has been received
4619323158eSAntonio Quartulli  * @if_incoming: the interface on which this OGM was received on
4629323158eSAntonio Quartulli  * @if_outgoing: the interface to which the OGM has to be forwarded to
4639323158eSAntonio Quartulli  *
4649323158eSAntonio Quartulli  * Forward an OGM to an interface after having altered the throughput metric and
4659323158eSAntonio Quartulli  * the TTL value contained in it. The original OGM isn't modified.
4669323158eSAntonio Quartulli  */
4679323158eSAntonio Quartulli static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
4689323158eSAntonio Quartulli 				 const struct batadv_ogm2_packet *ogm_received,
469efcc9d30SSimon Wunderlich 				 struct batadv_orig_node *orig_node,
470efcc9d30SSimon Wunderlich 				 struct batadv_neigh_node *neigh_node,
4719323158eSAntonio Quartulli 				 struct batadv_hard_iface *if_incoming,
4729323158eSAntonio Quartulli 				 struct batadv_hard_iface *if_outgoing)
4739323158eSAntonio Quartulli {
474efcc9d30SSimon Wunderlich 	struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
475efcc9d30SSimon Wunderlich 	struct batadv_orig_ifinfo *orig_ifinfo = NULL;
476efcc9d30SSimon Wunderlich 	struct batadv_neigh_node *router = NULL;
4779323158eSAntonio Quartulli 	struct batadv_ogm2_packet *ogm_forward;
4789323158eSAntonio Quartulli 	unsigned char *skb_buff;
4799323158eSAntonio Quartulli 	struct sk_buff *skb;
4809323158eSAntonio Quartulli 	size_t packet_len;
4819323158eSAntonio Quartulli 	u16 tvlv_len;
4829323158eSAntonio Quartulli 
483efcc9d30SSimon Wunderlich 	/* only forward for specific interfaces, not for the default one. */
484efcc9d30SSimon Wunderlich 	if (if_outgoing == BATADV_IF_DEFAULT)
485efcc9d30SSimon Wunderlich 		goto out;
486efcc9d30SSimon Wunderlich 
487efcc9d30SSimon Wunderlich 	orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
488efcc9d30SSimon Wunderlich 	if (!orig_ifinfo)
489efcc9d30SSimon Wunderlich 		goto out;
490efcc9d30SSimon Wunderlich 
491efcc9d30SSimon Wunderlich 	/* acquire possibly updated router */
492efcc9d30SSimon Wunderlich 	router = batadv_orig_router_get(orig_node, if_outgoing);
493efcc9d30SSimon Wunderlich 
494efcc9d30SSimon Wunderlich 	/* strict rule: forward packets coming from the best next hop only */
495efcc9d30SSimon Wunderlich 	if (neigh_node != router)
496efcc9d30SSimon Wunderlich 		goto out;
497efcc9d30SSimon Wunderlich 
498efcc9d30SSimon Wunderlich 	/* don't forward the same seqno twice on one interface */
499efcc9d30SSimon Wunderlich 	if (orig_ifinfo->last_seqno_forwarded == ntohl(ogm_received->seqno))
500efcc9d30SSimon Wunderlich 		goto out;
501efcc9d30SSimon Wunderlich 
502efcc9d30SSimon Wunderlich 	orig_ifinfo->last_seqno_forwarded = ntohl(ogm_received->seqno);
503efcc9d30SSimon Wunderlich 
5049323158eSAntonio Quartulli 	if (ogm_received->ttl <= 1) {
5059323158eSAntonio Quartulli 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n");
506efcc9d30SSimon Wunderlich 		goto out;
5079323158eSAntonio Quartulli 	}
5089323158eSAntonio Quartulli 
509efcc9d30SSimon Wunderlich 	neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
510efcc9d30SSimon Wunderlich 	if (!neigh_ifinfo)
511efcc9d30SSimon Wunderlich 		goto out;
512efcc9d30SSimon Wunderlich 
5139323158eSAntonio Quartulli 	tvlv_len = ntohs(ogm_received->tvlv_len);
5149323158eSAntonio Quartulli 
5159323158eSAntonio Quartulli 	packet_len = BATADV_OGM2_HLEN + tvlv_len;
5169323158eSAntonio Quartulli 	skb = netdev_alloc_skb_ip_align(if_outgoing->net_dev,
5179323158eSAntonio Quartulli 					ETH_HLEN + packet_len);
5189323158eSAntonio Quartulli 	if (!skb)
519efcc9d30SSimon Wunderlich 		goto out;
5209323158eSAntonio Quartulli 
5219323158eSAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
52259ae1d12SJohannes Berg 	skb_buff = skb_put_data(skb, ogm_received, packet_len);
5239323158eSAntonio Quartulli 
5249323158eSAntonio Quartulli 	/* apply forward penalty */
5259323158eSAntonio Quartulli 	ogm_forward = (struct batadv_ogm2_packet *)skb_buff;
526efcc9d30SSimon Wunderlich 	ogm_forward->throughput = htonl(neigh_ifinfo->bat_v.throughput);
5279323158eSAntonio Quartulli 	ogm_forward->ttl--;
5289323158eSAntonio Quartulli 
5299323158eSAntonio Quartulli 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
5309323158eSAntonio Quartulli 		   "Forwarding OGM2 packet on %s: throughput %u, ttl %u, received via %s\n",
531efcc9d30SSimon Wunderlich 		   if_outgoing->net_dev->name, ntohl(ogm_forward->throughput),
532efcc9d30SSimon Wunderlich 		   ogm_forward->ttl, if_incoming->net_dev->name);
5339323158eSAntonio Quartulli 
534*f89255a0SLinus Lüssing 	batadv_v_ogm_queue_on_if(skb, if_outgoing);
535efcc9d30SSimon Wunderlich 
536efcc9d30SSimon Wunderlich out:
537efcc9d30SSimon Wunderlich 	if (orig_ifinfo)
538efcc9d30SSimon Wunderlich 		batadv_orig_ifinfo_put(orig_ifinfo);
539efcc9d30SSimon Wunderlich 	if (router)
540efcc9d30SSimon Wunderlich 		batadv_neigh_node_put(router);
541efcc9d30SSimon Wunderlich 	if (neigh_ifinfo)
542efcc9d30SSimon Wunderlich 		batadv_neigh_ifinfo_put(neigh_ifinfo);
5439323158eSAntonio Quartulli }
5449323158eSAntonio Quartulli 
5459323158eSAntonio Quartulli /**
5467e9a8c2cSSven Eckelmann  * batadv_v_ogm_metric_update() - update route metric based on OGM
5479323158eSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
5489323158eSAntonio Quartulli  * @ogm2: OGM2 structure
5499323158eSAntonio Quartulli  * @orig_node: Originator structure for which the OGM has been received
5509323158eSAntonio Quartulli  * @neigh_node: the neigh_node through with the OGM has been received
5519323158eSAntonio Quartulli  * @if_incoming: the interface where this packet was received
5529323158eSAntonio Quartulli  * @if_outgoing: the interface for which the packet should be considered
5539323158eSAntonio Quartulli  *
5549323158eSAntonio Quartulli  * Return:
5559323158eSAntonio Quartulli  *  1  if the OGM is new,
5569323158eSAntonio Quartulli  *  0  if it is not new but valid,
5579323158eSAntonio Quartulli  *  <0 on error (e.g. old OGM)
5589323158eSAntonio Quartulli  */
5599323158eSAntonio Quartulli static int batadv_v_ogm_metric_update(struct batadv_priv *bat_priv,
5609323158eSAntonio Quartulli 				      const struct batadv_ogm2_packet *ogm2,
5619323158eSAntonio Quartulli 				      struct batadv_orig_node *orig_node,
5629323158eSAntonio Quartulli 				      struct batadv_neigh_node *neigh_node,
5639323158eSAntonio Quartulli 				      struct batadv_hard_iface *if_incoming,
5649323158eSAntonio Quartulli 				      struct batadv_hard_iface *if_outgoing)
5659323158eSAntonio Quartulli {
566422d2f77SSven Eckelmann 	struct batadv_orig_ifinfo *orig_ifinfo;
5679323158eSAntonio Quartulli 	struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
5689323158eSAntonio Quartulli 	bool protection_started = false;
5699323158eSAntonio Quartulli 	int ret = -EINVAL;
5709323158eSAntonio Quartulli 	u32 path_throughput;
5719323158eSAntonio Quartulli 	s32 seq_diff;
5729323158eSAntonio Quartulli 
5739323158eSAntonio Quartulli 	orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
5749323158eSAntonio Quartulli 	if (!orig_ifinfo)
5759323158eSAntonio Quartulli 		goto out;
5769323158eSAntonio Quartulli 
5779323158eSAntonio Quartulli 	seq_diff = ntohl(ogm2->seqno) - orig_ifinfo->last_real_seqno;
5789323158eSAntonio Quartulli 
5799323158eSAntonio Quartulli 	if (!hlist_empty(&orig_node->neigh_list) &&
5809323158eSAntonio Quartulli 	    batadv_window_protected(bat_priv, seq_diff,
5819323158eSAntonio Quartulli 				    BATADV_OGM_MAX_AGE,
5829323158eSAntonio Quartulli 				    &orig_ifinfo->batman_seqno_reset,
5839323158eSAntonio Quartulli 				    &protection_started)) {
5849323158eSAntonio Quartulli 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
5859323158eSAntonio Quartulli 			   "Drop packet: packet within window protection time from %pM\n",
5869323158eSAntonio Quartulli 			   ogm2->orig);
5879323158eSAntonio Quartulli 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
5889323158eSAntonio Quartulli 			   "Last reset: %ld, %ld\n",
5899323158eSAntonio Quartulli 			   orig_ifinfo->batman_seqno_reset, jiffies);
5909323158eSAntonio Quartulli 		goto out;
5919323158eSAntonio Quartulli 	}
5929323158eSAntonio Quartulli 
5939323158eSAntonio Quartulli 	/* drop packets with old seqnos, however accept the first packet after
5949323158eSAntonio Quartulli 	 * a host has been rebooted.
5959323158eSAntonio Quartulli 	 */
596825ffe1fSSven Eckelmann 	if (seq_diff < 0 && !protection_started)
5979323158eSAntonio Quartulli 		goto out;
5989323158eSAntonio Quartulli 
5999323158eSAntonio Quartulli 	neigh_node->last_seen = jiffies;
6009323158eSAntonio Quartulli 
6019323158eSAntonio Quartulli 	orig_node->last_seen = jiffies;
6029323158eSAntonio Quartulli 
6039323158eSAntonio Quartulli 	orig_ifinfo->last_real_seqno = ntohl(ogm2->seqno);
6049323158eSAntonio Quartulli 	orig_ifinfo->last_ttl = ogm2->ttl;
6059323158eSAntonio Quartulli 
6069323158eSAntonio Quartulli 	neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
6079323158eSAntonio Quartulli 	if (!neigh_ifinfo)
6089323158eSAntonio Quartulli 		goto out;
6099323158eSAntonio Quartulli 
6109323158eSAntonio Quartulli 	path_throughput = batadv_v_forward_penalty(bat_priv, if_incoming,
6119323158eSAntonio Quartulli 						   if_outgoing,
6129323158eSAntonio Quartulli 						   ntohl(ogm2->throughput));
6139323158eSAntonio Quartulli 	neigh_ifinfo->bat_v.throughput = path_throughput;
6149323158eSAntonio Quartulli 	neigh_ifinfo->bat_v.last_seqno = ntohl(ogm2->seqno);
6159323158eSAntonio Quartulli 	neigh_ifinfo->last_ttl = ogm2->ttl;
6169323158eSAntonio Quartulli 
6179323158eSAntonio Quartulli 	if (seq_diff > 0 || protection_started)
6189323158eSAntonio Quartulli 		ret = 1;
6199323158eSAntonio Quartulli 	else
6209323158eSAntonio Quartulli 		ret = 0;
6219323158eSAntonio Quartulli out:
6229323158eSAntonio Quartulli 	if (orig_ifinfo)
6239323158eSAntonio Quartulli 		batadv_orig_ifinfo_put(orig_ifinfo);
6249323158eSAntonio Quartulli 	if (neigh_ifinfo)
6259323158eSAntonio Quartulli 		batadv_neigh_ifinfo_put(neigh_ifinfo);
6269323158eSAntonio Quartulli 
6279323158eSAntonio Quartulli 	return ret;
6289323158eSAntonio Quartulli }
6299323158eSAntonio Quartulli 
6309323158eSAntonio Quartulli /**
6317e9a8c2cSSven Eckelmann  * batadv_v_ogm_route_update() - update routes based on OGM
6329323158eSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
6339323158eSAntonio Quartulli  * @ethhdr: the Ethernet header of the OGM2
6349323158eSAntonio Quartulli  * @ogm2: OGM2 structure
6359323158eSAntonio Quartulli  * @orig_node: Originator structure for which the OGM has been received
6369323158eSAntonio Quartulli  * @neigh_node: the neigh_node through with the OGM has been received
6379323158eSAntonio Quartulli  * @if_incoming: the interface where this packet was received
6389323158eSAntonio Quartulli  * @if_outgoing: the interface for which the packet should be considered
639efcc9d30SSimon Wunderlich  *
640efcc9d30SSimon Wunderlich  * Return: true if the packet should be forwarded, false otherwise
6419323158eSAntonio Quartulli  */
642efcc9d30SSimon Wunderlich static bool batadv_v_ogm_route_update(struct batadv_priv *bat_priv,
6439323158eSAntonio Quartulli 				      const struct ethhdr *ethhdr,
6449323158eSAntonio Quartulli 				      const struct batadv_ogm2_packet *ogm2,
6459323158eSAntonio Quartulli 				      struct batadv_orig_node *orig_node,
6469323158eSAntonio Quartulli 				      struct batadv_neigh_node *neigh_node,
6479323158eSAntonio Quartulli 				      struct batadv_hard_iface *if_incoming,
6489323158eSAntonio Quartulli 				      struct batadv_hard_iface *if_outgoing)
6499323158eSAntonio Quartulli {
6509323158eSAntonio Quartulli 	struct batadv_neigh_node *router = NULL;
651422d2f77SSven Eckelmann 	struct batadv_orig_node *orig_neigh_node;
6529323158eSAntonio Quartulli 	struct batadv_neigh_node *orig_neigh_router = NULL;
65386de37c1SSimon Wunderlich 	struct batadv_neigh_ifinfo *router_ifinfo = NULL, *neigh_ifinfo = NULL;
65486de37c1SSimon Wunderlich 	u32 router_throughput, neigh_throughput;
65586de37c1SSimon Wunderlich 	u32 router_last_seqno;
65686de37c1SSimon Wunderlich 	u32 neigh_last_seqno;
65786de37c1SSimon Wunderlich 	s32 neigh_seq_diff;
658efcc9d30SSimon Wunderlich 	bool forward = false;
6599323158eSAntonio Quartulli 
6609323158eSAntonio Quartulli 	orig_neigh_node = batadv_v_ogm_orig_get(bat_priv, ethhdr->h_source);
6619323158eSAntonio Quartulli 	if (!orig_neigh_node)
6629323158eSAntonio Quartulli 		goto out;
6639323158eSAntonio Quartulli 
6649323158eSAntonio Quartulli 	orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
6659323158eSAntonio Quartulli 						   if_outgoing);
6669323158eSAntonio Quartulli 
6679323158eSAntonio Quartulli 	/* drop packet if sender is not a direct neighbor and if we
6689323158eSAntonio Quartulli 	 * don't route towards it
6699323158eSAntonio Quartulli 	 */
6709323158eSAntonio Quartulli 	router = batadv_orig_router_get(orig_node, if_outgoing);
6719323158eSAntonio Quartulli 	if (router && router->orig_node != orig_node && !orig_neigh_router) {
6729323158eSAntonio Quartulli 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
6739323158eSAntonio Quartulli 			   "Drop packet: OGM via unknown neighbor!\n");
6749323158eSAntonio Quartulli 		goto out;
6759323158eSAntonio Quartulli 	}
6769323158eSAntonio Quartulli 
67786de37c1SSimon Wunderlich 	/* Mark the OGM to be considered for forwarding, and update routes
67886de37c1SSimon Wunderlich 	 * if needed.
67986de37c1SSimon Wunderlich 	 */
680efcc9d30SSimon Wunderlich 	forward = true;
68186de37c1SSimon Wunderlich 
68286de37c1SSimon Wunderlich 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
68386de37c1SSimon Wunderlich 		   "Searching and updating originator entry of received packet\n");
68486de37c1SSimon Wunderlich 
68586de37c1SSimon Wunderlich 	/* if this neighbor already is our next hop there is nothing
68686de37c1SSimon Wunderlich 	 * to change
68786de37c1SSimon Wunderlich 	 */
68886de37c1SSimon Wunderlich 	if (router == neigh_node)
68986de37c1SSimon Wunderlich 		goto out;
69086de37c1SSimon Wunderlich 
69186de37c1SSimon Wunderlich 	/* don't consider neighbours with worse throughput.
69286de37c1SSimon Wunderlich 	 * also switch route if this seqno is BATADV_V_MAX_ORIGDIFF newer than
69386de37c1SSimon Wunderlich 	 * the last received seqno from our best next hop.
69486de37c1SSimon Wunderlich 	 */
69586de37c1SSimon Wunderlich 	if (router) {
69686de37c1SSimon Wunderlich 		router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
69786de37c1SSimon Wunderlich 		neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
69886de37c1SSimon Wunderlich 
69986de37c1SSimon Wunderlich 		/* if these are not allocated, something is wrong. */
70086de37c1SSimon Wunderlich 		if (!router_ifinfo || !neigh_ifinfo)
70186de37c1SSimon Wunderlich 			goto out;
70286de37c1SSimon Wunderlich 
70386de37c1SSimon Wunderlich 		neigh_last_seqno = neigh_ifinfo->bat_v.last_seqno;
70486de37c1SSimon Wunderlich 		router_last_seqno = router_ifinfo->bat_v.last_seqno;
70586de37c1SSimon Wunderlich 		neigh_seq_diff = neigh_last_seqno - router_last_seqno;
70686de37c1SSimon Wunderlich 		router_throughput = router_ifinfo->bat_v.throughput;
70786de37c1SSimon Wunderlich 		neigh_throughput = neigh_ifinfo->bat_v.throughput;
70886de37c1SSimon Wunderlich 
709825ffe1fSSven Eckelmann 		if (neigh_seq_diff < BATADV_OGM_MAX_ORIGDIFF &&
710825ffe1fSSven Eckelmann 		    router_throughput >= neigh_throughput)
71186de37c1SSimon Wunderlich 			goto out;
71286de37c1SSimon Wunderlich 	}
71386de37c1SSimon Wunderlich 
71486de37c1SSimon Wunderlich 	batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
7159323158eSAntonio Quartulli out:
7169323158eSAntonio Quartulli 	if (router)
7179323158eSAntonio Quartulli 		batadv_neigh_node_put(router);
7189323158eSAntonio Quartulli 	if (orig_neigh_router)
7199323158eSAntonio Quartulli 		batadv_neigh_node_put(orig_neigh_router);
7209323158eSAntonio Quartulli 	if (orig_neigh_node)
7219323158eSAntonio Quartulli 		batadv_orig_node_put(orig_neigh_node);
72286de37c1SSimon Wunderlich 	if (router_ifinfo)
72386de37c1SSimon Wunderlich 		batadv_neigh_ifinfo_put(router_ifinfo);
72486de37c1SSimon Wunderlich 	if (neigh_ifinfo)
72586de37c1SSimon Wunderlich 		batadv_neigh_ifinfo_put(neigh_ifinfo);
726efcc9d30SSimon Wunderlich 
727efcc9d30SSimon Wunderlich 	return forward;
7289323158eSAntonio Quartulli }
7299323158eSAntonio Quartulli 
7309323158eSAntonio Quartulli /**
7317e9a8c2cSSven Eckelmann  * batadv_v_ogm_process_per_outif() - process a batman v OGM for an outgoing if
7329323158eSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
7339323158eSAntonio Quartulli  * @ethhdr: the Ethernet header of the OGM2
7349323158eSAntonio Quartulli  * @ogm2: OGM2 structure
7359323158eSAntonio Quartulli  * @orig_node: Originator structure for which the OGM has been received
7369323158eSAntonio Quartulli  * @neigh_node: the neigh_node through with the OGM has been received
7379323158eSAntonio Quartulli  * @if_incoming: the interface where this packet was received
7389323158eSAntonio Quartulli  * @if_outgoing: the interface for which the packet should be considered
7399323158eSAntonio Quartulli  */
7409323158eSAntonio Quartulli static void
7419323158eSAntonio Quartulli batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
7429323158eSAntonio Quartulli 			       const struct ethhdr *ethhdr,
7439323158eSAntonio Quartulli 			       const struct batadv_ogm2_packet *ogm2,
7449323158eSAntonio Quartulli 			       struct batadv_orig_node *orig_node,
7459323158eSAntonio Quartulli 			       struct batadv_neigh_node *neigh_node,
7469323158eSAntonio Quartulli 			       struct batadv_hard_iface *if_incoming,
7479323158eSAntonio Quartulli 			       struct batadv_hard_iface *if_outgoing)
7489323158eSAntonio Quartulli {
7499323158eSAntonio Quartulli 	int seqno_age;
750efcc9d30SSimon Wunderlich 	bool forward;
7519323158eSAntonio Quartulli 
7529323158eSAntonio Quartulli 	/* first, update the metric with according sanity checks */
7539323158eSAntonio Quartulli 	seqno_age = batadv_v_ogm_metric_update(bat_priv, ogm2, orig_node,
7549323158eSAntonio Quartulli 					       neigh_node, if_incoming,
7559323158eSAntonio Quartulli 					       if_outgoing);
7569323158eSAntonio Quartulli 
7579323158eSAntonio Quartulli 	/* outdated sequence numbers are to be discarded */
7589323158eSAntonio Quartulli 	if (seqno_age < 0)
7599323158eSAntonio Quartulli 		return;
7609323158eSAntonio Quartulli 
7619323158eSAntonio Quartulli 	/* only unknown & newer OGMs contain TVLVs we are interested in */
762825ffe1fSSven Eckelmann 	if (seqno_age > 0 && if_outgoing == BATADV_IF_DEFAULT)
7639323158eSAntonio Quartulli 		batadv_tvlv_containers_process(bat_priv, true, orig_node,
7649323158eSAntonio Quartulli 					       NULL, NULL,
7659323158eSAntonio Quartulli 					       (unsigned char *)(ogm2 + 1),
7669323158eSAntonio Quartulli 					       ntohs(ogm2->tvlv_len));
7679323158eSAntonio Quartulli 
7689323158eSAntonio Quartulli 	/* if the metric update went through, update routes if needed */
769efcc9d30SSimon Wunderlich 	forward = batadv_v_ogm_route_update(bat_priv, ethhdr, ogm2, orig_node,
770efcc9d30SSimon Wunderlich 					    neigh_node, if_incoming,
771efcc9d30SSimon Wunderlich 					    if_outgoing);
772efcc9d30SSimon Wunderlich 
773efcc9d30SSimon Wunderlich 	/* if the routes have been processed correctly, check and forward */
774efcc9d30SSimon Wunderlich 	if (forward)
775efcc9d30SSimon Wunderlich 		batadv_v_ogm_forward(bat_priv, ogm2, orig_node, neigh_node,
776efcc9d30SSimon Wunderlich 				     if_incoming, if_outgoing);
7779323158eSAntonio Quartulli }
7789323158eSAntonio Quartulli 
7799323158eSAntonio Quartulli /**
7807e9a8c2cSSven Eckelmann  * batadv_v_ogm_aggr_packet() - checks if there is another OGM aggregated
7819323158eSAntonio Quartulli  * @buff_pos: current position in the skb
7829323158eSAntonio Quartulli  * @packet_len: total length of the skb
7839323158eSAntonio Quartulli  * @tvlv_len: tvlv length of the previously considered OGM
7849323158eSAntonio Quartulli  *
7859323158eSAntonio Quartulli  * Return: true if there is enough space for another OGM, false otherwise.
7869323158eSAntonio Quartulli  */
7879323158eSAntonio Quartulli static bool batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
7889323158eSAntonio Quartulli 				     __be16 tvlv_len)
7899323158eSAntonio Quartulli {
7909323158eSAntonio Quartulli 	int next_buff_pos = 0;
7919323158eSAntonio Quartulli 
7929323158eSAntonio Quartulli 	next_buff_pos += buff_pos + BATADV_OGM2_HLEN;
7939323158eSAntonio Quartulli 	next_buff_pos += ntohs(tvlv_len);
7949323158eSAntonio Quartulli 
7959323158eSAntonio Quartulli 	return (next_buff_pos <= packet_len) &&
7969323158eSAntonio Quartulli 	       (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
7979323158eSAntonio Quartulli }
7989323158eSAntonio Quartulli 
7999323158eSAntonio Quartulli /**
8007e9a8c2cSSven Eckelmann  * batadv_v_ogm_process() - process an incoming batman v OGM
8019323158eSAntonio Quartulli  * @skb: the skb containing the OGM
8029323158eSAntonio Quartulli  * @ogm_offset: offset to the OGM which should be processed (for aggregates)
8039323158eSAntonio Quartulli  * @if_incoming: the interface where this packet was receved
8049323158eSAntonio Quartulli  */
8059323158eSAntonio Quartulli static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
8069323158eSAntonio Quartulli 				 struct batadv_hard_iface *if_incoming)
8079323158eSAntonio Quartulli {
8089323158eSAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
8099323158eSAntonio Quartulli 	struct ethhdr *ethhdr;
8109323158eSAntonio Quartulli 	struct batadv_orig_node *orig_node = NULL;
8119323158eSAntonio Quartulli 	struct batadv_hardif_neigh_node *hardif_neigh = NULL;
8129323158eSAntonio Quartulli 	struct batadv_neigh_node *neigh_node = NULL;
8139323158eSAntonio Quartulli 	struct batadv_hard_iface *hard_iface;
8149323158eSAntonio Quartulli 	struct batadv_ogm2_packet *ogm_packet;
8159323158eSAntonio Quartulli 	u32 ogm_throughput, link_throughput, path_throughput;
8163111beedSLinus Lüssing 	int ret;
8179323158eSAntonio Quartulli 
8189323158eSAntonio Quartulli 	ethhdr = eth_hdr(skb);
8199323158eSAntonio Quartulli 	ogm_packet = (struct batadv_ogm2_packet *)(skb->data + ogm_offset);
8209323158eSAntonio Quartulli 
8219323158eSAntonio Quartulli 	ogm_throughput = ntohl(ogm_packet->throughput);
8229323158eSAntonio Quartulli 
8239323158eSAntonio Quartulli 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
824f25cbb2aSColin Ian King 		   "Received OGM2 packet via NB: %pM, IF: %s [%pM] (from OG: %pM, seqno %u, throughput %u, TTL %u, V %u, tvlv_len %u)\n",
8259323158eSAntonio Quartulli 		   ethhdr->h_source, if_incoming->net_dev->name,
8269323158eSAntonio Quartulli 		   if_incoming->net_dev->dev_addr, ogm_packet->orig,
8279323158eSAntonio Quartulli 		   ntohl(ogm_packet->seqno), ogm_throughput, ogm_packet->ttl,
8289323158eSAntonio Quartulli 		   ogm_packet->version, ntohs(ogm_packet->tvlv_len));
8299323158eSAntonio Quartulli 
830f25cbb2aSColin Ian King 	/* If the throughput metric is 0, immediately drop the packet. No need
831f25cbb2aSColin Ian King 	 * to create orig_node / neigh_node for an unusable route.
8329323158eSAntonio Quartulli 	 */
8339323158eSAntonio Quartulli 	if (ogm_throughput == 0) {
8349323158eSAntonio Quartulli 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
835f25cbb2aSColin Ian King 			   "Drop packet: originator packet with throughput metric of 0\n");
8369323158eSAntonio Quartulli 		return;
8379323158eSAntonio Quartulli 	}
8389323158eSAntonio Quartulli 
8399323158eSAntonio Quartulli 	/* require ELP packets be to received from this neighbor first */
8409323158eSAntonio Quartulli 	hardif_neigh = batadv_hardif_neigh_get(if_incoming, ethhdr->h_source);
8419323158eSAntonio Quartulli 	if (!hardif_neigh) {
8429323158eSAntonio Quartulli 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
8439323158eSAntonio Quartulli 			   "Drop packet: OGM via unknown neighbor!\n");
8449323158eSAntonio Quartulli 		goto out;
8459323158eSAntonio Quartulli 	}
8469323158eSAntonio Quartulli 
8479323158eSAntonio Quartulli 	orig_node = batadv_v_ogm_orig_get(bat_priv, ogm_packet->orig);
8489323158eSAntonio Quartulli 	if (!orig_node)
8499323158eSAntonio Quartulli 		return;
8509323158eSAntonio Quartulli 
8516f0a6b5eSMarek Lindner 	neigh_node = batadv_neigh_node_get_or_create(orig_node, if_incoming,
8529323158eSAntonio Quartulli 						     ethhdr->h_source);
8539323158eSAntonio Quartulli 	if (!neigh_node)
8549323158eSAntonio Quartulli 		goto out;
8559323158eSAntonio Quartulli 
8569323158eSAntonio Quartulli 	/* Update the received throughput metric to match the link
8579323158eSAntonio Quartulli 	 * characteristic:
8589323158eSAntonio Quartulli 	 *  - If this OGM traveled one hop so far (emitted by single hop
8599323158eSAntonio Quartulli 	 *    neighbor) the path throughput metric equals the link throughput.
8609323158eSAntonio Quartulli 	 *  - For OGMs traversing more than hop the path throughput metric is
8619323158eSAntonio Quartulli 	 *    the smaller of the path throughput and the link throughput.
8629323158eSAntonio Quartulli 	 */
8639323158eSAntonio Quartulli 	link_throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
8649323158eSAntonio Quartulli 	path_throughput = min_t(u32, link_throughput, ogm_throughput);
8659323158eSAntonio Quartulli 	ogm_packet->throughput = htonl(path_throughput);
8669323158eSAntonio Quartulli 
8679323158eSAntonio Quartulli 	batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, orig_node,
8689323158eSAntonio Quartulli 				       neigh_node, if_incoming,
8699323158eSAntonio Quartulli 				       BATADV_IF_DEFAULT);
8709323158eSAntonio Quartulli 
8719323158eSAntonio Quartulli 	rcu_read_lock();
8729323158eSAntonio Quartulli 	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
8739323158eSAntonio Quartulli 		if (hard_iface->if_status != BATADV_IF_ACTIVE)
8749323158eSAntonio Quartulli 			continue;
8759323158eSAntonio Quartulli 
8769323158eSAntonio Quartulli 		if (hard_iface->soft_iface != bat_priv->soft_iface)
8779323158eSAntonio Quartulli 			continue;
8789323158eSAntonio Quartulli 
87927353446SSven Eckelmann 		if (!kref_get_unless_zero(&hard_iface->refcount))
88027353446SSven Eckelmann 			continue;
88127353446SSven Eckelmann 
8823111beedSLinus Lüssing 		ret = batadv_hardif_no_broadcast(hard_iface,
8833111beedSLinus Lüssing 						 ogm_packet->orig,
8843111beedSLinus Lüssing 						 hardif_neigh->orig);
8853111beedSLinus Lüssing 
8863111beedSLinus Lüssing 		if (ret) {
8873111beedSLinus Lüssing 			char *type;
8883111beedSLinus Lüssing 
8893111beedSLinus Lüssing 			switch (ret) {
8903111beedSLinus Lüssing 			case BATADV_HARDIF_BCAST_NORECIPIENT:
8913111beedSLinus Lüssing 				type = "no neighbor";
8923111beedSLinus Lüssing 				break;
8933111beedSLinus Lüssing 			case BATADV_HARDIF_BCAST_DUPFWD:
8943111beedSLinus Lüssing 				type = "single neighbor is source";
8953111beedSLinus Lüssing 				break;
8963111beedSLinus Lüssing 			case BATADV_HARDIF_BCAST_DUPORIG:
8973111beedSLinus Lüssing 				type = "single neighbor is originator";
8983111beedSLinus Lüssing 				break;
8993111beedSLinus Lüssing 			default:
9003111beedSLinus Lüssing 				type = "unknown";
9013111beedSLinus Lüssing 			}
9023111beedSLinus Lüssing 
903f25cbb2aSColin Ian King 			batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 packet from %pM on %s suppressed: %s\n",
9043111beedSLinus Lüssing 				   ogm_packet->orig, hard_iface->net_dev->name,
9053111beedSLinus Lüssing 				   type);
9063111beedSLinus Lüssing 
9073111beedSLinus Lüssing 			batadv_hardif_put(hard_iface);
9083111beedSLinus Lüssing 			continue;
9093111beedSLinus Lüssing 		}
9103111beedSLinus Lüssing 
9119323158eSAntonio Quartulli 		batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet,
9129323158eSAntonio Quartulli 					       orig_node, neigh_node,
9139323158eSAntonio Quartulli 					       if_incoming, hard_iface);
91427353446SSven Eckelmann 
91527353446SSven Eckelmann 		batadv_hardif_put(hard_iface);
9169323158eSAntonio Quartulli 	}
9179323158eSAntonio Quartulli 	rcu_read_unlock();
9189323158eSAntonio Quartulli out:
9199323158eSAntonio Quartulli 	if (orig_node)
9209323158eSAntonio Quartulli 		batadv_orig_node_put(orig_node);
9219323158eSAntonio Quartulli 	if (neigh_node)
9229323158eSAntonio Quartulli 		batadv_neigh_node_put(neigh_node);
9239323158eSAntonio Quartulli 	if (hardif_neigh)
9249323158eSAntonio Quartulli 		batadv_hardif_neigh_put(hardif_neigh);
9259323158eSAntonio Quartulli }
9269323158eSAntonio Quartulli 
9279323158eSAntonio Quartulli /**
9287e9a8c2cSSven Eckelmann  * batadv_v_ogm_packet_recv() - OGM2 receiving handler
9290da00359SAntonio Quartulli  * @skb: the received OGM
9300da00359SAntonio Quartulli  * @if_incoming: the interface where this OGM has been received
9310da00359SAntonio Quartulli  *
9320da00359SAntonio Quartulli  * Return: NET_RX_SUCCESS and consume the skb on success or returns NET_RX_DROP
9330da00359SAntonio Quartulli  * (without freeing the skb) on failure
9340da00359SAntonio Quartulli  */
9350da00359SAntonio Quartulli int batadv_v_ogm_packet_recv(struct sk_buff *skb,
9360da00359SAntonio Quartulli 			     struct batadv_hard_iface *if_incoming)
9370da00359SAntonio Quartulli {
9380da00359SAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
9390da00359SAntonio Quartulli 	struct batadv_ogm2_packet *ogm_packet;
9400da00359SAntonio Quartulli 	struct ethhdr *ethhdr = eth_hdr(skb);
9419323158eSAntonio Quartulli 	int ogm_offset;
9429323158eSAntonio Quartulli 	u8 *packet_pos;
9439323158eSAntonio Quartulli 	int ret = NET_RX_DROP;
9440da00359SAntonio Quartulli 
9450da00359SAntonio Quartulli 	/* did we receive a OGM2 packet on an interface that does not have
9460da00359SAntonio Quartulli 	 * B.A.T.M.A.N. V enabled ?
9470da00359SAntonio Quartulli 	 */
94829824a55SAntonio Quartulli 	if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0)
949b91a2543SSven Eckelmann 		goto free_skb;
9500da00359SAntonio Quartulli 
9510da00359SAntonio Quartulli 	if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
952b91a2543SSven Eckelmann 		goto free_skb;
9530da00359SAntonio Quartulli 
9540da00359SAntonio Quartulli 	if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
955b91a2543SSven Eckelmann 		goto free_skb;
9560da00359SAntonio Quartulli 
9570da00359SAntonio Quartulli 	ogm_packet = (struct batadv_ogm2_packet *)skb->data;
9580da00359SAntonio Quartulli 
9590da00359SAntonio Quartulli 	if (batadv_is_my_mac(bat_priv, ogm_packet->orig))
960b91a2543SSven Eckelmann 		goto free_skb;
9610da00359SAntonio Quartulli 
9620da00359SAntonio Quartulli 	batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
9630da00359SAntonio Quartulli 	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
9640da00359SAntonio Quartulli 			   skb->len + ETH_HLEN);
9650da00359SAntonio Quartulli 
9669323158eSAntonio Quartulli 	ogm_offset = 0;
9679323158eSAntonio Quartulli 	ogm_packet = (struct batadv_ogm2_packet *)skb->data;
9689323158eSAntonio Quartulli 
9699323158eSAntonio Quartulli 	while (batadv_v_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
9709323158eSAntonio Quartulli 					ogm_packet->tvlv_len)) {
9719323158eSAntonio Quartulli 		batadv_v_ogm_process(skb, ogm_offset, if_incoming);
9729323158eSAntonio Quartulli 
9739323158eSAntonio Quartulli 		ogm_offset += BATADV_OGM2_HLEN;
9749323158eSAntonio Quartulli 		ogm_offset += ntohs(ogm_packet->tvlv_len);
9759323158eSAntonio Quartulli 
9769323158eSAntonio Quartulli 		packet_pos = skb->data + ogm_offset;
9779323158eSAntonio Quartulli 		ogm_packet = (struct batadv_ogm2_packet *)packet_pos;
9789323158eSAntonio Quartulli 	}
9799323158eSAntonio Quartulli 
9809323158eSAntonio Quartulli 	ret = NET_RX_SUCCESS;
981b91a2543SSven Eckelmann 
982b91a2543SSven Eckelmann free_skb:
983b91a2543SSven Eckelmann 	if (ret == NET_RX_SUCCESS)
9840da00359SAntonio Quartulli 		consume_skb(skb);
985b91a2543SSven Eckelmann 	else
986b91a2543SSven Eckelmann 		kfree_skb(skb);
9879323158eSAntonio Quartulli 
9889323158eSAntonio Quartulli 	return ret;
9890da00359SAntonio Quartulli }
9900da00359SAntonio Quartulli 
9910da00359SAntonio Quartulli /**
9927e9a8c2cSSven Eckelmann  * batadv_v_ogm_init() - initialise the OGM2 engine
9930da00359SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
9940da00359SAntonio Quartulli  *
9950da00359SAntonio Quartulli  * Return: 0 on success or a negative error code in case of failure
9960da00359SAntonio Quartulli  */
9970da00359SAntonio Quartulli int batadv_v_ogm_init(struct batadv_priv *bat_priv)
9980da00359SAntonio Quartulli {
9990da00359SAntonio Quartulli 	struct batadv_ogm2_packet *ogm_packet;
10000da00359SAntonio Quartulli 	unsigned char *ogm_buff;
10010da00359SAntonio Quartulli 	u32 random_seqno;
10020da00359SAntonio Quartulli 
10030da00359SAntonio Quartulli 	bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
10040da00359SAntonio Quartulli 	ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
10050da00359SAntonio Quartulli 	if (!ogm_buff)
10060da00359SAntonio Quartulli 		return -ENOMEM;
10070da00359SAntonio Quartulli 
10080da00359SAntonio Quartulli 	bat_priv->bat_v.ogm_buff = ogm_buff;
10090da00359SAntonio Quartulli 	ogm_packet = (struct batadv_ogm2_packet *)ogm_buff;
10100da00359SAntonio Quartulli 	ogm_packet->packet_type = BATADV_OGM2;
10110da00359SAntonio Quartulli 	ogm_packet->version = BATADV_COMPAT_VERSION;
10120da00359SAntonio Quartulli 	ogm_packet->ttl = BATADV_TTL;
10130da00359SAntonio Quartulli 	ogm_packet->flags = BATADV_NO_FLAGS;
10140da00359SAntonio Quartulli 	ogm_packet->throughput = htonl(BATADV_THROUGHPUT_MAX_VALUE);
10150da00359SAntonio Quartulli 
10160da00359SAntonio Quartulli 	/* randomize initial seqno to avoid collision */
10170da00359SAntonio Quartulli 	get_random_bytes(&random_seqno, sizeof(random_seqno));
10180da00359SAntonio Quartulli 	atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
10190da00359SAntonio Quartulli 	INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
10200da00359SAntonio Quartulli 
10210da00359SAntonio Quartulli 	return 0;
10220da00359SAntonio Quartulli }
10230da00359SAntonio Quartulli 
10240da00359SAntonio Quartulli /**
10257e9a8c2cSSven Eckelmann  * batadv_v_ogm_free() - free OGM private resources
10260da00359SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
10270da00359SAntonio Quartulli  */
10280da00359SAntonio Quartulli void batadv_v_ogm_free(struct batadv_priv *bat_priv)
10290da00359SAntonio Quartulli {
10300da00359SAntonio Quartulli 	cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
10310da00359SAntonio Quartulli 
10320da00359SAntonio Quartulli 	kfree(bat_priv->bat_v.ogm_buff);
10330da00359SAntonio Quartulli 	bat_priv->bat_v.ogm_buff = NULL;
10340da00359SAntonio Quartulli 	bat_priv->bat_v.ogm_buff_len = 0;
10350da00359SAntonio Quartulli }
1036