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