Blame view

net/batman-adv/bat_iv_ogm.c 82.6 KB
ac79cbb96   Sven Eckelmann   batman-adv: updat...
1
  /* Copyright (C) 2007-2017  B.A.T.M.A.N. contributors:
fc9572756   Marek Lindner   batman-adv: agglo...
2
3
4
5
6
7
8
9
10
11
12
13
14
   *
   * Marek Lindner, Simon Wunderlich
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
ebf38fb7a   Antonio Quartulli   batman-adv: remov...
15
   * along with this program; if not, see <http://www.gnu.org/licenses/>.
fc9572756   Marek Lindner   batman-adv: agglo...
16
   */
a2d081660   Sven Eckelmann   batman-adv: Fix b...
17
  #include "bat_iv_ogm.h"
fc9572756   Marek Lindner   batman-adv: agglo...
18
  #include "main.h"
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
19
20
21
22
23
24
25
26
27
28
29
30
31
  
  #include <linux/atomic.h>
  #include <linux/bitmap.h>
  #include <linux/bitops.h>
  #include <linux/bug.h>
  #include <linux/byteorder/generic.h>
  #include <linux/cache.h>
  #include <linux/errno.h>
  #include <linux/etherdevice.h>
  #include <linux/fs.h>
  #include <linux/if_ether.h>
  #include <linux/init.h>
  #include <linux/jiffies.h>
f0d97253f   Antonio Quartulli   batman-adv: remov...
32
  #include <linux/kernel.h>
77ae32e89   Sven Eckelmann   batman-adv: Conve...
33
  #include <linux/kref.h>
fcafa5e74   Sven Eckelmann   batman-adv: Keep ...
34
  #include <linux/list.h>
64ae74455   Sven Eckelmann   batman-adv: Split...
35
  #include <linux/lockdep.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
36
  #include <linux/netdevice.h>
024f99cb4   Matthias Schiffer   batman-adv: add B...
37
  #include <linux/netlink.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
38
39
40
41
42
43
44
45
46
47
48
49
50
  #include <linux/pkt_sched.h>
  #include <linux/printk.h>
  #include <linux/random.h>
  #include <linux/rculist.h>
  #include <linux/rcupdate.h>
  #include <linux/seq_file.h>
  #include <linux/skbuff.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/stddef.h>
  #include <linux/string.h>
  #include <linux/types.h>
  #include <linux/workqueue.h>
024f99cb4   Matthias Schiffer   batman-adv: add B...
51
52
53
  #include <net/genetlink.h>
  #include <net/netlink.h>
  #include <uapi/linux/batman_adv.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
54

a2d081660   Sven Eckelmann   batman-adv: Fix b...
55
  #include "bat_algo.h"
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
56
  #include "bitarray.h"
34d99cfef   Antonio Quartulli   batman-adv: make ...
57
  #include "gateway_client.h"
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
58
59
  #include "hard-interface.h"
  #include "hash.h"
ba412080f   Sven Eckelmann   batman-adv: Conso...
60
  #include "log.h"
024f99cb4   Matthias Schiffer   batman-adv: add B...
61
  #include "netlink.h"
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
62
  #include "network-coding.h"
fc9572756   Marek Lindner   batman-adv: agglo...
63
  #include "originator.h"
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
64
  #include "packet.h"
fc9572756   Marek Lindner   batman-adv: agglo...
65
  #include "routing.h"
fc9572756   Marek Lindner   batman-adv: agglo...
66
  #include "send.h"
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
67
  #include "translation-table.h"
1f8dce499   Markus Pargmann   batman-adv: split...
68
  #include "tvlv.h"
fc9572756   Marek Lindner   batman-adv: agglo...
69

f0d97253f   Antonio Quartulli   batman-adv: remov...
70
  static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work);
791c2a2d3   Antonio Quartulli   batman-adv: move ...
71
  /**
95298a91f   Martin Hundebøll   batman-adv: kerne...
72
   * enum batadv_dup_status - duplicate status
9f52ee19c   Markus Pargmann   batman-adv: iv_og...
73
   * @BATADV_NO_DUP: the packet is no duplicate
791c2a2d3   Antonio Quartulli   batman-adv: move ...
74
75
76
77
78
79
80
81
82
83
84
   * @BATADV_ORIG_DUP: OGM is a duplicate in the originator (but not for the
   *  neighbor)
   * @BATADV_NEIGH_DUP: OGM is a duplicate for the neighbor
   * @BATADV_PROTECTED: originator is currently protected (after reboot)
   */
  enum batadv_dup_status {
  	BATADV_NO_DUP = 0,
  	BATADV_ORIG_DUP,
  	BATADV_NEIGH_DUP,
  	BATADV_PROTECTED,
  };
24a5deeb8   Antonio Quartulli   batman-adv: move ...
85
86
87
88
89
90
  /**
   * batadv_ring_buffer_set - update the ring buffer with the given value
   * @lq_recv: pointer to the ring buffer
   * @lq_index: index to store the value at
   * @value: value to store in the ring buffer
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
91
  static void batadv_ring_buffer_set(u8 lq_recv[], u8 *lq_index, u8 value)
24a5deeb8   Antonio Quartulli   batman-adv: move ...
92
93
94
95
96
97
  {
  	lq_recv[*lq_index] = value;
  	*lq_index = (*lq_index + 1) % BATADV_TQ_GLOBAL_WINDOW_SIZE;
  }
  
  /**
d491dbb68   Markus Pargmann   batman-adv: iv_og...
98
   * batadv_ring_buffer_avg - compute the average of all non-zero values stored
24a5deeb8   Antonio Quartulli   batman-adv: move ...
99
100
101
   * in the given ring buffer
   * @lq_recv: pointer to the ring buffer
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
102
   * Return: computed average value.
24a5deeb8   Antonio Quartulli   batman-adv: move ...
103
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
104
  static u8 batadv_ring_buffer_avg(const u8 lq_recv[])
24a5deeb8   Antonio Quartulli   batman-adv: move ...
105
  {
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
106
107
108
109
  	const u8 *ptr;
  	u16 count = 0;
  	u16 i = 0;
  	u16 sum = 0;
24a5deeb8   Antonio Quartulli   batman-adv: move ...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  
  	ptr = lq_recv;
  
  	while (i < BATADV_TQ_GLOBAL_WINDOW_SIZE) {
  		if (*ptr != 0) {
  			count++;
  			sum += *ptr;
  		}
  
  		i++;
  		ptr++;
  	}
  
  	if (count == 0)
  		return 0;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
125
  	return (u8)(sum / count);
24a5deeb8   Antonio Quartulli   batman-adv: move ...
126
  }
d98cae64e   David S. Miller   Merge git://git.k...
127

bbad0a5e3   Antonio Quartulli   batman-adv: make ...
128
  /**
d0015fdd3   Antonio Quartulli   batman-adv: provi...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
   * batadv_iv_ogm_orig_free - free the private resources allocated for this
   *  orig_node
   * @orig_node: the orig_node for which the resources have to be free'd
   */
  static void batadv_iv_ogm_orig_free(struct batadv_orig_node *orig_node)
  {
  	kfree(orig_node->bat_iv.bcast_own);
  	kfree(orig_node->bat_iv.bcast_own_sum);
  }
  
  /**
   * batadv_iv_ogm_orig_add_if - change the private structures of the orig_node to
   *  include the new hard-interface
   * @orig_node: the orig_node that has to be changed
   * @max_if_num: the current amount of interfaces
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
145
   * Return: 0 on success, a negative error code otherwise.
d0015fdd3   Antonio Quartulli   batman-adv: provi...
146
147
148
149
150
   */
  static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node,
  				     int max_if_num)
  {
  	void *data_ptr;
0185dda64   Antonio Quartulli   batman-adv: prefe...
151
  	size_t old_size;
d0015fdd3   Antonio Quartulli   batman-adv: provi...
152
153
154
  	int ret = -ENOMEM;
  
  	spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
d0015fdd3   Antonio Quartulli   batman-adv: provi...
155
  	old_size = (max_if_num - 1) * sizeof(unsigned long) * BATADV_NUM_WORDS;
0185dda64   Antonio Quartulli   batman-adv: prefe...
156
157
158
  	data_ptr = kmalloc_array(max_if_num,
  				 BATADV_NUM_WORDS * sizeof(unsigned long),
  				 GFP_ATOMIC);
d0015fdd3   Antonio Quartulli   batman-adv: provi...
159
160
161
162
163
164
  	if (!data_ptr)
  		goto unlock;
  
  	memcpy(data_ptr, orig_node->bat_iv.bcast_own, old_size);
  	kfree(orig_node->bat_iv.bcast_own);
  	orig_node->bat_iv.bcast_own = data_ptr;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
165
  	data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC);
f7dcdf5fd   Sven Eckelmann   batman-adv: Fix u...
166
  	if (!data_ptr)
d0015fdd3   Antonio Quartulli   batman-adv: provi...
167
  		goto unlock;
d0015fdd3   Antonio Quartulli   batman-adv: provi...
168
169
  
  	memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
170
  	       (max_if_num - 1) * sizeof(u8));
d0015fdd3   Antonio Quartulli   batman-adv: provi...
171
172
173
174
175
176
177
178
179
180
181
182
  	kfree(orig_node->bat_iv.bcast_own_sum);
  	orig_node->bat_iv.bcast_own_sum = data_ptr;
  
  	ret = 0;
  
  unlock:
  	spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
  
  	return ret;
  }
  
  /**
64ae74455   Sven Eckelmann   batman-adv: Split...
183
   * batadv_iv_ogm_drop_bcast_own_entry - drop section of bcast_own
d0015fdd3   Antonio Quartulli   batman-adv: provi...
184
185
186
   * @orig_node: the orig_node that has to be changed
   * @max_if_num: the current amount of interfaces
   * @del_if_num: the index of the interface being removed
d0015fdd3   Antonio Quartulli   batman-adv: provi...
187
   */
64ae74455   Sven Eckelmann   batman-adv: Split...
188
189
190
  static void
  batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node,
  				   int max_if_num, int del_if_num)
d0015fdd3   Antonio Quartulli   batman-adv: provi...
191
  {
64ae74455   Sven Eckelmann   batman-adv: Split...
192
193
194
  	size_t chunk_size;
  	size_t if_offset;
  	void *data_ptr;
d0015fdd3   Antonio Quartulli   batman-adv: provi...
195

64ae74455   Sven Eckelmann   batman-adv: Split...
196
  	lockdep_assert_held(&orig_node->bat_iv.ogm_cnt_lock);
d0015fdd3   Antonio Quartulli   batman-adv: provi...
197
198
  
  	chunk_size = sizeof(unsigned long) * BATADV_NUM_WORDS;
0185dda64   Antonio Quartulli   batman-adv: prefe...
199
  	data_ptr = kmalloc_array(max_if_num, chunk_size, GFP_ATOMIC);
d0015fdd3   Antonio Quartulli   batman-adv: provi...
200
  	if (!data_ptr)
64ae74455   Sven Eckelmann   batman-adv: Split...
201
202
  		/* use old buffer when new one could not be allocated */
  		data_ptr = orig_node->bat_iv.bcast_own;
d0015fdd3   Antonio Quartulli   batman-adv: provi...
203
204
  
  	/* copy first part */
64ae74455   Sven Eckelmann   batman-adv: Split...
205
  	memmove(data_ptr, orig_node->bat_iv.bcast_own, del_if_num * chunk_size);
d0015fdd3   Antonio Quartulli   batman-adv: provi...
206
207
  
  	/* copy second part */
13bbdd370   Sven Eckelmann   batman-adv: Fix i...
208
  	if_offset = (del_if_num + 1) * chunk_size;
64ae74455   Sven Eckelmann   batman-adv: Split...
209
210
211
  	memmove((char *)data_ptr + del_if_num * chunk_size,
  		(uint8_t *)orig_node->bat_iv.bcast_own + if_offset,
  		(max_if_num - del_if_num) * chunk_size);
d0015fdd3   Antonio Quartulli   batman-adv: provi...
212

64ae74455   Sven Eckelmann   batman-adv: Split...
213
214
215
216
217
218
  	/* bcast_own was shrunk down in new buffer; free old one */
  	if (orig_node->bat_iv.bcast_own != data_ptr) {
  		kfree(orig_node->bat_iv.bcast_own);
  		orig_node->bat_iv.bcast_own = data_ptr;
  	}
  }
d0015fdd3   Antonio Quartulli   batman-adv: provi...
219

64ae74455   Sven Eckelmann   batman-adv: Split...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  /**
   * batadv_iv_ogm_drop_bcast_own_sum_entry - drop section of bcast_own_sum
   * @orig_node: the orig_node that has to be changed
   * @max_if_num: the current amount of interfaces
   * @del_if_num: the index of the interface being removed
   */
  static void
  batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node,
  				       int max_if_num, int del_if_num)
  {
  	size_t if_offset;
  	void *data_ptr;
  
  	lockdep_assert_held(&orig_node->bat_iv.ogm_cnt_lock);
d0015fdd3   Antonio Quartulli   batman-adv: provi...
234

6b5e971a2   Sven Eckelmann   batman-adv: Repla...
235
  	data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC);
64ae74455   Sven Eckelmann   batman-adv: Split...
236
237
238
  	if (!data_ptr)
  		/* use old buffer when new one could not be allocated */
  		data_ptr = orig_node->bat_iv.bcast_own_sum;
d0015fdd3   Antonio Quartulli   batman-adv: provi...
239

64ae74455   Sven Eckelmann   batman-adv: Split...
240
241
  	memmove(data_ptr, orig_node->bat_iv.bcast_own_sum,
  		del_if_num * sizeof(u8));
d0015fdd3   Antonio Quartulli   batman-adv: provi...
242

6b5e971a2   Sven Eckelmann   batman-adv: Repla...
243
  	if_offset = (del_if_num + 1) * sizeof(u8);
64ae74455   Sven Eckelmann   batman-adv: Split...
244
245
246
247
248
249
250
251
252
253
  	memmove((char *)data_ptr + del_if_num * sizeof(u8),
  		orig_node->bat_iv.bcast_own_sum + if_offset,
  		(max_if_num - del_if_num) * sizeof(u8));
  
  	/* bcast_own_sum was shrunk down in new buffer; free old one */
  	if (orig_node->bat_iv.bcast_own_sum != data_ptr) {
  		kfree(orig_node->bat_iv.bcast_own_sum);
  		orig_node->bat_iv.bcast_own_sum = data_ptr;
  	}
  }
d0015fdd3   Antonio Quartulli   batman-adv: provi...
254

64ae74455   Sven Eckelmann   batman-adv: Split...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  /**
   * batadv_iv_ogm_orig_del_if - change the private structures of the orig_node to
   *  exclude the removed interface
   * @orig_node: the orig_node that has to be changed
   * @max_if_num: the current amount of interfaces
   * @del_if_num: the index of the interface being removed
   *
   * Return: 0 on success, a negative error code otherwise.
   */
  static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node,
  				     int max_if_num, int del_if_num)
  {
  	spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
  
  	if (max_if_num == 0) {
  		kfree(orig_node->bat_iv.bcast_own);
  		kfree(orig_node->bat_iv.bcast_own_sum);
  		orig_node->bat_iv.bcast_own = NULL;
  		orig_node->bat_iv.bcast_own_sum = NULL;
  	} else {
  		batadv_iv_ogm_drop_bcast_own_entry(orig_node, max_if_num,
  						   del_if_num);
  		batadv_iv_ogm_drop_bcast_own_sum_entry(orig_node, max_if_num,
  						       del_if_num);
  	}
d0015fdd3   Antonio Quartulli   batman-adv: provi...
280

d0015fdd3   Antonio Quartulli   batman-adv: provi...
281
  	spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
64ae74455   Sven Eckelmann   batman-adv: Split...
282
  	return 0;
d0015fdd3   Antonio Quartulli   batman-adv: provi...
283
284
285
  }
  
  /**
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
286
287
288
289
   * batadv_iv_ogm_orig_get - retrieve or create (if does not exist) an originator
   * @bat_priv: the bat priv with all the soft interface information
   * @addr: mac address of the originator
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
290
   * Return: the originator object corresponding to the passed mac address or NULL
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
291
292
293
294
   * on failure.
   * If the object does not exists it is created an initialised.
   */
  static struct batadv_orig_node *
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
295
  batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  {
  	struct batadv_orig_node *orig_node;
  	int size, hash_added;
  
  	orig_node = batadv_orig_hash_find(bat_priv, addr);
  	if (orig_node)
  		return orig_node;
  
  	orig_node = batadv_orig_node_new(bat_priv, addr);
  	if (!orig_node)
  		return NULL;
  
  	spin_lock_init(&orig_node->bat_iv.ogm_cnt_lock);
  
  	size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS;
  	orig_node->bat_iv.bcast_own = kzalloc(size, GFP_ATOMIC);
  	if (!orig_node->bat_iv.bcast_own)
  		goto free_orig_node;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
314
  	size = bat_priv->num_ifaces * sizeof(u8);
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
315
316
  	orig_node->bat_iv.bcast_own_sum = kzalloc(size, GFP_ATOMIC);
  	if (!orig_node->bat_iv.bcast_own_sum)
a5a5cb8ca   Antonio Quartulli   batman-adv: avoid...
317
  		goto free_orig_node;
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
318

55db2d590   Sven Eckelmann   batman-adv: Place...
319
  	kref_get(&orig_node->refcount);
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
320
321
322
323
  	hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
  				     batadv_choose_orig, orig_node,
  				     &orig_node->hash_entry);
  	if (hash_added != 0)
55db2d590   Sven Eckelmann   batman-adv: Place...
324
  		goto free_orig_node_hash;
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
325
326
  
  	return orig_node;
55db2d590   Sven Eckelmann   batman-adv: Place...
327
  free_orig_node_hash:
5d9673109   Sven Eckelmann   batman-adv: Renam...
328
  	batadv_orig_node_put(orig_node);
55db2d590   Sven Eckelmann   batman-adv: Place...
329
  free_orig_node:
5d9673109   Sven Eckelmann   batman-adv: Renam...
330
  	batadv_orig_node_put(orig_node);
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
331
332
333
  
  	return NULL;
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
334
335
  static struct batadv_neigh_node *
  batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
336
  			const u8 *neigh_addr,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
337
  			struct batadv_orig_node *orig_node,
863dd7a82   Antonio Quartulli   batman-adv: drop ...
338
  			struct batadv_orig_node *orig_neigh)
7ae8b2852   Marek Lindner   batman-adv: split...
339
  {
741aa06bf   Marek Lindner   batman-adv: move ...
340
  	struct batadv_neigh_node *neigh_node;
7ae8b2852   Marek Lindner   batman-adv: split...
341

6f0a6b5ee   Marek Lindner   batman-adv: refac...
342
343
  	neigh_node = batadv_neigh_node_get_or_create(orig_node,
  						     hard_iface, neigh_addr);
7ae8b2852   Marek Lindner   batman-adv: split...
344
345
  	if (!neigh_node)
  		goto out;
89652331c   Simon Wunderlich   batman-adv: split...
346
  	neigh_node->orig_node = orig_neigh;
7ae8b2852   Marek Lindner   batman-adv: split...
347

7ae8b2852   Marek Lindner   batman-adv: split...
348
349
350
  out:
  	return neigh_node;
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
351
  static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
d0b9fd89c   Marek Lindner   batman-adv: move ...
352
  {
964126901   Sven Eckelmann   batman-adv: Prefi...
353
  	struct batadv_ogm_packet *batadv_ogm_packet;
14511519d   Marek Lindner   batman-adv: split...
354
  	unsigned char *ogm_buff;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
355
  	u32 random_seqno;
d7d32ec0f   Marek Lindner   batman-adv: rando...
356
357
358
  
  	/* randomize initial seqno to avoid collision */
  	get_random_bytes(&random_seqno, sizeof(random_seqno));
14511519d   Marek Lindner   batman-adv: split...
359
  	atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
d0b9fd89c   Marek Lindner   batman-adv: move ...
360

14511519d   Marek Lindner   batman-adv: split...
361
362
363
  	hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN;
  	ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC);
  	if (!ogm_buff)
42d9f2cbd   Markus Pargmann   batman-adv: iv_og...
364
  		return -ENOMEM;
77af7575c   Marek Lindner   batman-adv: handl...
365

14511519d   Marek Lindner   batman-adv: split...
366
367
368
  	hard_iface->bat_iv.ogm_buff = ogm_buff;
  
  	batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
a40d9b075   Simon Wunderlich   batman-adv: fix h...
369
370
371
  	batadv_ogm_packet->packet_type = BATADV_IV_OGM;
  	batadv_ogm_packet->version = BATADV_COMPAT_VERSION;
  	batadv_ogm_packet->ttl = 2;
964126901   Sven Eckelmann   batman-adv: Prefi...
372
  	batadv_ogm_packet->flags = BATADV_NO_FLAGS;
414254e34   Marek Lindner   batman-adv: tvlv ...
373
  	batadv_ogm_packet->reserved = 0;
964126901   Sven Eckelmann   batman-adv: Prefi...
374
  	batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE;
77af7575c   Marek Lindner   batman-adv: handl...
375

42d9f2cbd   Markus Pargmann   batman-adv: iv_og...
376
  	return 0;
d0b9fd89c   Marek Lindner   batman-adv: move ...
377
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
378
  static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
00a50076a   Marek Lindner   batman-adv: add i...
379
  {
14511519d   Marek Lindner   batman-adv: split...
380
381
  	kfree(hard_iface->bat_iv.ogm_buff);
  	hard_iface->bat_iv.ogm_buff = NULL;
00a50076a   Marek Lindner   batman-adv: add i...
382
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
383
  static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
d0b9fd89c   Marek Lindner   batman-adv: move ...
384
  {
964126901   Sven Eckelmann   batman-adv: Prefi...
385
  	struct batadv_ogm_packet *batadv_ogm_packet;
14511519d   Marek Lindner   batman-adv: split...
386
  	unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
d0b9fd89c   Marek Lindner   batman-adv: move ...
387

14511519d   Marek Lindner   batman-adv: split...
388
  	batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
8fdd01530   Antonio Quartulli   batman-adv: prefe...
389
390
391
392
  	ether_addr_copy(batadv_ogm_packet->orig,
  			hard_iface->net_dev->dev_addr);
  	ether_addr_copy(batadv_ogm_packet->prev_sender,
  			hard_iface->net_dev->dev_addr);
d0b9fd89c   Marek Lindner   batman-adv: move ...
393
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
394
395
  static void
  batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
d0b9fd89c   Marek Lindner   batman-adv: move ...
396
  {
964126901   Sven Eckelmann   batman-adv: Prefi...
397
  	struct batadv_ogm_packet *batadv_ogm_packet;
14511519d   Marek Lindner   batman-adv: split...
398
  	unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
d0b9fd89c   Marek Lindner   batman-adv: move ...
399

14511519d   Marek Lindner   batman-adv: split...
400
  	batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
a40d9b075   Simon Wunderlich   batman-adv: fix h...
401
  	batadv_ogm_packet->ttl = BATADV_TTL;
d0b9fd89c   Marek Lindner   batman-adv: move ...
402
  }
b9dacc521   Marek Lindner   batman-adv: agglo...
403
  /* when do we schedule our own ogm to be sent */
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
404
  static unsigned long
56303d34a   Sven Eckelmann   batman-adv: Prefi...
405
  batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv)
b9dacc521   Marek Lindner   batman-adv: agglo...
406
  {
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
407
408
409
  	unsigned int msecs;
  
  	msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
e76e4320a   Akinobu Mita   batman-adv: renam...
410
  	msecs += prandom_u32() % (2 * BATADV_JITTER);
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
411
412
  
  	return jiffies + msecs_to_jiffies(msecs);
b9dacc521   Marek Lindner   batman-adv: agglo...
413
414
415
  }
  
  /* when do we schedule a ogm packet to be sent */
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
416
  static unsigned long batadv_iv_ogm_fwd_send_time(void)
b9dacc521   Marek Lindner   batman-adv: agglo...
417
  {
e76e4320a   Akinobu Mita   batman-adv: renam...
418
  	return jiffies + msecs_to_jiffies(prandom_u32() % (BATADV_JITTER / 2));
b9dacc521   Marek Lindner   batman-adv: agglo...
419
420
421
  }
  
  /* apply hop penalty for a normal link */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
422
  static u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv)
b9dacc521   Marek Lindner   batman-adv: agglo...
423
424
  {
  	int hop_penalty = atomic_read(&bat_priv->hop_penalty);
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
425
426
427
428
429
430
  	int new_tq;
  
  	new_tq = tq * (BATADV_TQ_MAX_VALUE - hop_penalty);
  	new_tq /= BATADV_TQ_MAX_VALUE;
  
  	return new_tq;
b9dacc521   Marek Lindner   batman-adv: agglo...
431
  }
600184b70   Simon Wunderlich   batman-adv: add k...
432
433
434
435
436
437
438
439
  /**
   * batadv_iv_ogm_aggr_packet - checks if there is another OGM attached
   * @buff_pos: current position in the skb
   * @packet_len: total length of the skb
   * @tvlv_len: tvlv length of the previously considered OGM
   *
   * Return: true if there is enough space for another OGM, false otherwise.
   */
9fd9b19ea   Markus Pargmann   batman-adv: iv_og...
440
441
  static bool batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
  				      __be16 tvlv_len)
fc9572756   Marek Lindner   batman-adv: agglo...
442
  {
08c36d3e8   Sven Eckelmann   batman-adv: Prefi...
443
  	int next_buff_pos = 0;
7e071c79a   Sven Eckelmann   batman-adv: Prefi...
444
  	next_buff_pos += buff_pos + BATADV_OGM_HLEN;
ef2615774   Marek Lindner   batman-adv: tvlv ...
445
  	next_buff_pos += ntohs(tvlv_len);
fc9572756   Marek Lindner   batman-adv: agglo...
446
447
  
  	return (next_buff_pos <= packet_len) &&
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
448
  	       (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
fc9572756   Marek Lindner   batman-adv: agglo...
449
  }
b9dacc521   Marek Lindner   batman-adv: agglo...
450
  /* send a batman ogm to a given interface */
56303d34a   Sven Eckelmann   batman-adv: Prefi...
451
452
  static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
  				     struct batadv_hard_iface *hard_iface)
b9dacc521   Marek Lindner   batman-adv: agglo...
453
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
454
  	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
de12baece   Markus Pargmann   batman-adv: iv_og...
455
  	const char *fwd_str;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
456
457
  	u8 packet_num;
  	s16 buff_pos;
964126901   Sven Eckelmann   batman-adv: Prefi...
458
  	struct batadv_ogm_packet *batadv_ogm_packet;
b9dacc521   Marek Lindner   batman-adv: agglo...
459
  	struct sk_buff *skb;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
460
  	u8 *packet_pos;
b9dacc521   Marek Lindner   batman-adv: agglo...
461

e9a4f295e   Sven Eckelmann   batman-adv: Prefi...
462
  	if (hard_iface->if_status != BATADV_IF_ACTIVE)
b9dacc521   Marek Lindner   batman-adv: agglo...
463
464
465
466
  		return;
  
  	packet_num = 0;
  	buff_pos = 0;
c67893d17   Sven Eckelmann   batman-adv: Reduc...
467
468
  	packet_pos = forw_packet->skb->data;
  	batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
b9dacc521   Marek Lindner   batman-adv: agglo...
469
470
  
  	/* adjust all flags and log packets */
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
471
  	while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
ef2615774   Marek Lindner   batman-adv: tvlv ...
472
  					 batadv_ogm_packet->tvlv_len)) {
b9dacc521   Marek Lindner   batman-adv: agglo...
473
  		/* we might have aggregated direct link packets with an
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
474
475
  		 * ordinary base packet
  		 */
8de47de57   Sven Eckelmann   batman-adv: Use B...
476
477
  		if (forw_packet->direct_link_flags & BIT(packet_num) &&
  		    forw_packet->if_incoming == hard_iface)
964126901   Sven Eckelmann   batman-adv: Prefi...
478
  			batadv_ogm_packet->flags |= BATADV_DIRECTLINK;
b9dacc521   Marek Lindner   batman-adv: agglo...
479
  		else
964126901   Sven Eckelmann   batman-adv: Prefi...
480
  			batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK;
b9dacc521   Marek Lindner   batman-adv: agglo...
481

c67893d17   Sven Eckelmann   batman-adv: Reduc...
482
483
484
485
  		if (packet_num > 0 || !forw_packet->own)
  			fwd_str = "Forwarding";
  		else
  			fwd_str = "Sending own";
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
486
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
e1bf0c140   Marek Lindner   batman-adv: tvlv ...
487
488
  			   "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s) on interface %s [%pM]
  ",
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
489
  			   fwd_str, (packet_num > 0 ? "aggregated " : ""),
964126901   Sven Eckelmann   batman-adv: Prefi...
490
491
  			   batadv_ogm_packet->orig,
  			   ntohl(batadv_ogm_packet->seqno),
a40d9b075   Simon Wunderlich   batman-adv: fix h...
492
  			   batadv_ogm_packet->tq, batadv_ogm_packet->ttl,
a2f2b6cd4   Sven Eckelmann   batman-adv: Clari...
493
  			   ((batadv_ogm_packet->flags & BATADV_DIRECTLINK) ?
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
494
  			    "on" : "off"),
e1bf0c140   Marek Lindner   batman-adv: tvlv ...
495
  			   hard_iface->net_dev->name,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
496
  			   hard_iface->net_dev->dev_addr);
b9dacc521   Marek Lindner   batman-adv: agglo...
497

7e071c79a   Sven Eckelmann   batman-adv: Prefi...
498
  		buff_pos += BATADV_OGM_HLEN;
ef2615774   Marek Lindner   batman-adv: tvlv ...
499
  		buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
b9dacc521   Marek Lindner   batman-adv: agglo...
500
  		packet_num++;
c67893d17   Sven Eckelmann   batman-adv: Reduc...
501
502
  		packet_pos = forw_packet->skb->data + buff_pos;
  		batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
b9dacc521   Marek Lindner   batman-adv: agglo...
503
504
505
506
  	}
  
  	/* create clone because function is called more than once */
  	skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
f8214865a   Martin Hundebøll   batman-adv: Add g...
507
  	if (skb) {
d69909d2f   Sven Eckelmann   batman-adv: Prefi...
508
509
  		batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
  		batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
f8214865a   Martin Hundebøll   batman-adv: Add g...
510
  				   skb->len + ETH_HLEN);
95d392784   Antonio Quartulli   batman-adv: keep ...
511
  		batadv_send_broadcast_skb(skb, hard_iface);
f8214865a   Martin Hundebøll   batman-adv: Add g...
512
  	}
b9dacc521   Marek Lindner   batman-adv: agglo...
513
514
515
  }
  
  /* send a batman ogm packet */
56303d34a   Sven Eckelmann   batman-adv: Prefi...
516
  static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
b9dacc521   Marek Lindner   batman-adv: agglo...
517
  {
b9dacc521   Marek Lindner   batman-adv: agglo...
518
  	struct net_device *soft_iface;
b9dacc521   Marek Lindner   batman-adv: agglo...
519
520
  
  	if (!forw_packet->if_incoming) {
86ceb3605   Sven Eckelmann   batman-adv: Ignor...
521
522
  		pr_err("Error - can't forward packet: incoming iface not specified
  ");
f55a2e844   Linus LĂĽssing   batman-adv: Remov...
523
  		return;
b9dacc521   Marek Lindner   batman-adv: agglo...
524
525
526
  	}
  
  	soft_iface = forw_packet->if_incoming->soft_iface;
b9dacc521   Marek Lindner   batman-adv: agglo...
527

ef0a937f7   Simon Wunderlich   batman-adv: consi...
528
  	if (WARN_ON(!forw_packet->if_outgoing))
f55a2e844   Linus LĂĽssing   batman-adv: Remov...
529
  		return;
b9dacc521   Marek Lindner   batman-adv: agglo...
530

ef0a937f7   Simon Wunderlich   batman-adv: consi...
531
  	if (WARN_ON(forw_packet->if_outgoing->soft_iface != soft_iface))
f55a2e844   Linus LĂĽssing   batman-adv: Remov...
532
  		return;
b9dacc521   Marek Lindner   batman-adv: agglo...
533

ef0a937f7   Simon Wunderlich   batman-adv: consi...
534
  	if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
f55a2e844   Linus LĂĽssing   batman-adv: Remov...
535
  		return;
b9dacc521   Marek Lindner   batman-adv: agglo...
536

ef0a937f7   Simon Wunderlich   batman-adv: consi...
537
538
  	/* only for one specific outgoing interface */
  	batadv_iv_ogm_send_to_if(forw_packet, forw_packet->if_outgoing);
b9dacc521   Marek Lindner   batman-adv: agglo...
539
  }
ef0a937f7   Simon Wunderlich   batman-adv: consi...
540
541
542
543
544
545
546
  /**
   * batadv_iv_ogm_can_aggregate - find out if an OGM can be aggregated on an
   *  existing forward packet
   * @new_bat_ogm_packet: OGM packet to be aggregated
   * @bat_priv: the bat priv with all the soft interface information
   * @packet_len: (total) length of the OGM
   * @send_time: timestamp (jiffies) when the packet is to be sent
95298a91f   Martin Hundebøll   batman-adv: kerne...
547
   * @directlink: true if this is a direct link packet
ef0a937f7   Simon Wunderlich   batman-adv: consi...
548
549
550
551
   * @if_incoming: interface where the packet was received
   * @if_outgoing: interface for which the retransmission should be considered
   * @forw_packet: the forwarded packet which should be checked
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
552
   * Return: true if new_packet can be aggregated with forw_packet
ef0a937f7   Simon Wunderlich   batman-adv: consi...
553
   */
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
554
  static bool
964126901   Sven Eckelmann   batman-adv: Prefi...
555
  batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
556
  			    struct batadv_priv *bat_priv,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
557
558
  			    int packet_len, unsigned long send_time,
  			    bool directlink,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
559
  			    const struct batadv_hard_iface *if_incoming,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
560
  			    const struct batadv_hard_iface *if_outgoing,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
561
  			    const struct batadv_forw_packet *forw_packet)
b9dacc521   Marek Lindner   batman-adv: agglo...
562
  {
964126901   Sven Eckelmann   batman-adv: Prefi...
563
  	struct batadv_ogm_packet *batadv_ogm_packet;
b9dacc521   Marek Lindner   batman-adv: agglo...
564
  	int aggregated_bytes = forw_packet->packet_len + packet_len;
56303d34a   Sven Eckelmann   batman-adv: Prefi...
565
  	struct batadv_hard_iface *primary_if = NULL;
b9dacc521   Marek Lindner   batman-adv: agglo...
566
  	bool res = false;
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
567
  	unsigned long aggregation_end_time;
b9dacc521   Marek Lindner   batman-adv: agglo...
568

964126901   Sven Eckelmann   batman-adv: Prefi...
569
  	batadv_ogm_packet = (struct batadv_ogm_packet *)forw_packet->skb->data;
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
570
571
  	aggregation_end_time = send_time;
  	aggregation_end_time += msecs_to_jiffies(BATADV_MAX_AGGREGATION_MS);
b9dacc521   Marek Lindner   batman-adv: agglo...
572

9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
573
  	/* we can aggregate the current packet to this aggregated packet
b9dacc521   Marek Lindner   batman-adv: agglo...
574
575
576
577
578
  	 * if:
  	 *
  	 * - the send time is within our MAX_AGGREGATION_MS time
  	 * - the resulting packet wont be bigger than
  	 *   MAX_AGGREGATION_BYTES
8f34b3887   Markus Pargmann   batman-adv: iv_og...
579
  	 * otherwise aggregation is not possible
b9dacc521   Marek Lindner   batman-adv: agglo...
580
  	 */
8f34b3887   Markus Pargmann   batman-adv: iv_og...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  	if (!time_before(send_time, forw_packet->send_time) ||
  	    !time_after_eq(aggregation_end_time, forw_packet->send_time))
  		return false;
  
  	if (aggregated_bytes > BATADV_MAX_AGGREGATION_BYTES)
  		return false;
  
  	/* packet is not leaving on the same interface. */
  	if (forw_packet->if_outgoing != if_outgoing)
  		return false;
  
  	/* check aggregation compatibility
  	 * -> direct link packets are broadcasted on
  	 *    their interface only
  	 * -> aggregate packet if the current packet is
  	 *    a "global" packet as well as the base
  	 *    packet
  	 */
  	primary_if = batadv_primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		return false;
ef0a937f7   Simon Wunderlich   batman-adv: consi...
602

8f34b3887   Markus Pargmann   batman-adv: iv_og...
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  	/* packets without direct link flag and high TTL
  	 * are flooded through the net
  	 */
  	if (!directlink &&
  	    !(batadv_ogm_packet->flags & BATADV_DIRECTLINK) &&
  	    batadv_ogm_packet->ttl != 1 &&
  
  	    /* own packets originating non-primary
  	     * interfaces leave only that interface
  	     */
  	    (!forw_packet->own ||
  	     forw_packet->if_incoming == primary_if)) {
  		res = true;
  		goto out;
  	}
b9dacc521   Marek Lindner   batman-adv: agglo...
618

8f34b3887   Markus Pargmann   batman-adv: iv_og...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  	/* if the incoming packet is sent via this one
  	 * interface only - we still can aggregate
  	 */
  	if (directlink &&
  	    new_bat_ogm_packet->ttl == 1 &&
  	    forw_packet->if_incoming == if_incoming &&
  
  	    /* packets from direct neighbors or
  	     * own secondary interface packets
  	     * (= secondary interface packets in general)
  	     */
  	    (batadv_ogm_packet->flags & BATADV_DIRECTLINK ||
  	     (forw_packet->own &&
  	      forw_packet->if_incoming != primary_if))) {
  		res = true;
  		goto out;
b9dacc521   Marek Lindner   batman-adv: agglo...
635
636
637
638
  	}
  
  out:
  	if (primary_if)
82047ad7f   Sven Eckelmann   batman-adv: Renam...
639
  		batadv_hardif_put(primary_if);
b9dacc521   Marek Lindner   batman-adv: agglo...
640
641
  	return res;
  }
1b371d130   Simon Wunderlich   batman-adv: use c...
642
643
  /**
   * batadv_iv_ogm_aggregate_new - create a new aggregated packet and add this
ef0a937f7   Simon Wunderlich   batman-adv: consi...
644
645
646
647
648
649
650
651
652
   *  packet to it.
   * @packet_buff: pointer to the OGM
   * @packet_len: (total) length of the OGM
   * @send_time: timestamp (jiffies) when the packet is to be sent
   * @direct_link: whether this OGM has direct link status
   * @if_incoming: interface where the packet was received
   * @if_outgoing: interface for which the retransmission should be considered
   * @own_packet: true if it is a self-generated ogm
   */
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
653
654
655
  static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
  					int packet_len, unsigned long send_time,
  					bool direct_link,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
656
  					struct batadv_hard_iface *if_incoming,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
657
  					struct batadv_hard_iface *if_outgoing,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
658
  					int own_packet)
b9dacc521   Marek Lindner   batman-adv: agglo...
659
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
660
661
  	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
  	struct batadv_forw_packet *forw_packet_aggr;
99ba18ef0   Linus LĂĽssing   batman-adv: priva...
662
  	struct sk_buff *skb;
b9dacc521   Marek Lindner   batman-adv: agglo...
663
  	unsigned char *skb_buff;
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
664
  	unsigned int skb_size;
a65e54813   Linus LĂĽssing   batman-adv: Intro...
665
  	atomic_t *queue_left = own_packet ? NULL : &bat_priv->batman_queue_left;
b9dacc521   Marek Lindner   batman-adv: agglo...
666

940d156f5   Markus Pargmann   batman-adv: iv_og...
667
668
  	if (atomic_read(&bat_priv->aggregated_ogms) &&
  	    packet_len < BATADV_MAX_AGGREGATION_BYTES)
5b2465744   Sven Eckelmann   batman-adv: Reser...
669
  		skb_size = BATADV_MAX_AGGREGATION_BYTES;
b9dacc521   Marek Lindner   batman-adv: agglo...
670
  	else
5b2465744   Sven Eckelmann   batman-adv: Reser...
671
  		skb_size = packet_len;
41ab6c489   Antonio Quartulli   batman-adv: don't...
672
  	skb_size += ETH_HLEN;
b9dacc521   Marek Lindner   batman-adv: agglo...
673

99ba18ef0   Linus LĂĽssing   batman-adv: priva...
674
675
676
677
678
679
680
681
  	skb = netdev_alloc_skb_ip_align(NULL, skb_size);
  	if (!skb)
  		return;
  
  	forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing,
  						    queue_left, bat_priv, skb);
  	if (!forw_packet_aggr) {
  		kfree_skb(skb);
a65e54813   Linus LĂĽssing   batman-adv: Intro...
682
683
  		return;
  	}
c54f38c9a   Simon Wunderlich   batman-adv: set s...
684
  	forw_packet_aggr->skb->priority = TC_PRIO_CONTROL;
41ab6c489   Antonio Quartulli   batman-adv: don't...
685
  	skb_reserve(forw_packet_aggr->skb, ETH_HLEN);
b9dacc521   Marek Lindner   batman-adv: agglo...
686

b9dacc521   Marek Lindner   batman-adv: agglo...
687
688
689
690
691
  	skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
  	forw_packet_aggr->packet_len = packet_len;
  	memcpy(skb_buff, packet_buff, packet_len);
  
  	forw_packet_aggr->own = own_packet;
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
692
  	forw_packet_aggr->direct_link_flags = BATADV_NO_FLAGS;
b9dacc521   Marek Lindner   batman-adv: agglo...
693
694
695
696
697
  	forw_packet_aggr->send_time = send_time;
  
  	/* save packet direct link flag status */
  	if (direct_link)
  		forw_packet_aggr->direct_link_flags |= 1;
b9dacc521   Marek Lindner   batman-adv: agglo...
698
  	INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
f0d97253f   Antonio Quartulli   batman-adv: remov...
699
  			  batadv_iv_send_outstanding_bat_ogm_packet);
9b4aec647   Linus LĂĽssing   batman-adv: fix r...
700
701
  
  	batadv_forw_packet_ogmv1_queue(bat_priv, forw_packet_aggr, send_time);
b9dacc521   Marek Lindner   batman-adv: agglo...
702
703
704
  }
  
  /* aggregate a new packet into the existing ogm packet */
56303d34a   Sven Eckelmann   batman-adv: Prefi...
705
  static void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
706
707
  				    const unsigned char *packet_buff,
  				    int packet_len, bool direct_link)
b9dacc521   Marek Lindner   batman-adv: agglo...
708
  {
8de47de57   Sven Eckelmann   batman-adv: Use B...
709
  	unsigned long new_direct_link_flag;
b9dacc521   Marek Lindner   batman-adv: agglo...
710

e04de4861   Sven Eckelmann   batman-adv: Remov...
711
  	skb_put_data(forw_packet_aggr->skb, packet_buff, packet_len);
b9dacc521   Marek Lindner   batman-adv: agglo...
712
713
714
715
  	forw_packet_aggr->packet_len += packet_len;
  	forw_packet_aggr->num_packets++;
  
  	/* save packet direct link flag status */
8de47de57   Sven Eckelmann   batman-adv: Use B...
716
717
718
719
  	if (direct_link) {
  		new_direct_link_flag = BIT(forw_packet_aggr->num_packets);
  		forw_packet_aggr->direct_link_flags |= new_direct_link_flag;
  	}
b9dacc521   Marek Lindner   batman-adv: agglo...
720
  }
ef0a937f7   Simon Wunderlich   batman-adv: consi...
721
722
723
724
725
726
727
728
729
730
  /**
   * batadv_iv_ogm_queue_add - queue up an OGM for transmission
   * @bat_priv: the bat priv with all the soft interface information
   * @packet_buff: pointer to the OGM
   * @packet_len: (total) length of the OGM
   * @if_incoming: interface where the packet was received
   * @if_outgoing: interface for which the retransmission should be considered
   * @own_packet: true if it is a self-generated ogm
   * @send_time: timestamp (jiffies) when the packet is to be sent
   */
56303d34a   Sven Eckelmann   batman-adv: Prefi...
731
  static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
732
733
  				    unsigned char *packet_buff,
  				    int packet_len,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
734
  				    struct batadv_hard_iface *if_incoming,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
735
  				    struct batadv_hard_iface *if_outgoing,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
736
  				    int own_packet, unsigned long send_time)
b9dacc521   Marek Lindner   batman-adv: agglo...
737
  {
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
738
  	/* _aggr -> pointer to the packet we want to aggregate with
b9dacc521   Marek Lindner   batman-adv: agglo...
739
740
  	 * _pos -> pointer to the position in the queue
  	 */
56303d34a   Sven Eckelmann   batman-adv: Prefi...
741
742
  	struct batadv_forw_packet *forw_packet_aggr = NULL;
  	struct batadv_forw_packet *forw_packet_pos = NULL;
964126901   Sven Eckelmann   batman-adv: Prefi...
743
  	struct batadv_ogm_packet *batadv_ogm_packet;
b9dacc521   Marek Lindner   batman-adv: agglo...
744
  	bool direct_link;
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
745
  	unsigned long max_aggregation_jiffies;
b9dacc521   Marek Lindner   batman-adv: agglo...
746

964126901   Sven Eckelmann   batman-adv: Prefi...
747
  	batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff;
564891510   Markus Pargmann   batman-adv: iv_og...
748
  	direct_link = !!(batadv_ogm_packet->flags & BATADV_DIRECTLINK);
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
749
  	max_aggregation_jiffies = msecs_to_jiffies(BATADV_MAX_AGGREGATION_MS);
b9dacc521   Marek Lindner   batman-adv: agglo...
750
751
752
753
  
  	/* find position for the packet in the forward queue */
  	spin_lock_bh(&bat_priv->forw_bat_list_lock);
  	/* own packets are not to be aggregated */
564891510   Markus Pargmann   batman-adv: iv_og...
754
  	if (atomic_read(&bat_priv->aggregated_ogms) && !own_packet) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
755
  		hlist_for_each_entry(forw_packet_pos,
b9dacc521   Marek Lindner   batman-adv: agglo...
756
  				     &bat_priv->forw_bat_list, list) {
964126901   Sven Eckelmann   batman-adv: Prefi...
757
  			if (batadv_iv_ogm_can_aggregate(batadv_ogm_packet,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
758
759
760
  							bat_priv, packet_len,
  							send_time, direct_link,
  							if_incoming,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
761
  							if_outgoing,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
762
  							forw_packet_pos)) {
b9dacc521   Marek Lindner   batman-adv: agglo...
763
764
765
766
767
768
769
  				forw_packet_aggr = forw_packet_pos;
  				break;
  			}
  		}
  	}
  
  	/* nothing to aggregate with - either aggregation disabled or no
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
770
771
  	 * suitable aggregation packet found
  	 */
b9dacc521   Marek Lindner   batman-adv: agglo...
772
773
774
  	if (!forw_packet_aggr) {
  		/* the following section can run without the lock */
  		spin_unlock_bh(&bat_priv->forw_bat_list_lock);
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
775
  		/* if we could not aggregate this packet with one of the others
b9dacc521   Marek Lindner   batman-adv: agglo...
776
777
778
  		 * we hold it back for a while, so that it might be aggregated
  		 * later on
  		 */
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
779
780
  		if (!own_packet && atomic_read(&bat_priv->aggregated_ogms))
  			send_time += max_aggregation_jiffies;
b9dacc521   Marek Lindner   batman-adv: agglo...
781

fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
782
783
  		batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
  					    send_time, direct_link,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
784
785
  					    if_incoming, if_outgoing,
  					    own_packet);
b9dacc521   Marek Lindner   batman-adv: agglo...
786
  	} else {
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
787
788
  		batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff,
  					packet_len, direct_link);
b9dacc521   Marek Lindner   batman-adv: agglo...
789
790
791
  		spin_unlock_bh(&bat_priv->forw_bat_list_lock);
  	}
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
792
  static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
793
  				  const struct ethhdr *ethhdr,
964126901   Sven Eckelmann   batman-adv: Prefi...
794
  				  struct batadv_ogm_packet *batadv_ogm_packet,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
795
796
  				  bool is_single_hop_neigh,
  				  bool is_from_best_next_hop,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
797
798
  				  struct batadv_hard_iface *if_incoming,
  				  struct batadv_hard_iface *if_outgoing)
b9dacc521   Marek Lindner   batman-adv: agglo...
799
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
800
  	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
801
  	u16 tvlv_len;
b9dacc521   Marek Lindner   batman-adv: agglo...
802

a40d9b075   Simon Wunderlich   batman-adv: fix h...
803
  	if (batadv_ogm_packet->ttl <= 1) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
804
805
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded
  ");
b9dacc521   Marek Lindner   batman-adv: agglo...
806
807
  		return;
  	}
13b2541b1   Marek Lindner   batman-adv: avoid...
808
809
810
811
812
813
814
815
  	if (!is_from_best_next_hop) {
  		/* Mark the forwarded packet when it is not coming from our
  		 * best next hop. We still need to forward the packet for our
  		 * neighbor link quality detection to work in case the packet
  		 * originated from a single hop neighbor. Otherwise we can
  		 * simply drop the ogm.
  		 */
  		if (is_single_hop_neigh)
964126901   Sven Eckelmann   batman-adv: Prefi...
816
  			batadv_ogm_packet->flags |= BATADV_NOT_BEST_NEXT_HOP;
13b2541b1   Marek Lindner   batman-adv: avoid...
817
818
819
  		else
  			return;
  	}
b9dacc521   Marek Lindner   batman-adv: agglo...
820

ef2615774   Marek Lindner   batman-adv: tvlv ...
821
  	tvlv_len = ntohs(batadv_ogm_packet->tvlv_len);
b9dacc521   Marek Lindner   batman-adv: agglo...
822

a40d9b075   Simon Wunderlich   batman-adv: fix h...
823
  	batadv_ogm_packet->ttl--;
8fdd01530   Antonio Quartulli   batman-adv: prefe...
824
  	ether_addr_copy(batadv_ogm_packet->prev_sender, ethhdr->h_source);
b9dacc521   Marek Lindner   batman-adv: agglo...
825

b9dacc521   Marek Lindner   batman-adv: agglo...
826
  	/* apply hop penalty */
964126901   Sven Eckelmann   batman-adv: Prefi...
827
  	batadv_ogm_packet->tq = batadv_hop_penalty(batadv_ogm_packet->tq,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
828
  						   bat_priv);
b9dacc521   Marek Lindner   batman-adv: agglo...
829

39c75a51e   Sven Eckelmann   batman-adv: Prefi...
830
  	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
831
832
  		   "Forwarding packet: tq: %i, ttl: %i
  ",
a40d9b075   Simon Wunderlich   batman-adv: fix h...
833
  		   batadv_ogm_packet->tq, batadv_ogm_packet->ttl);
b9dacc521   Marek Lindner   batman-adv: agglo...
834

75cd33f86   Marek Lindner   batman-adv: intro...
835
  	if (is_single_hop_neigh)
964126901   Sven Eckelmann   batman-adv: Prefi...
836
  		batadv_ogm_packet->flags |= BATADV_DIRECTLINK;
b9dacc521   Marek Lindner   batman-adv: agglo...
837
  	else
964126901   Sven Eckelmann   batman-adv: Prefi...
838
  		batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK;
b9dacc521   Marek Lindner   batman-adv: agglo...
839

964126901   Sven Eckelmann   batman-adv: Prefi...
840
  	batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet,
ef2615774   Marek Lindner   batman-adv: tvlv ...
841
  				BATADV_OGM_HLEN + tvlv_len,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
842
843
  				if_incoming, if_outgoing, 0,
  				batadv_iv_ogm_fwd_send_time());
b9dacc521   Marek Lindner   batman-adv: agglo...
844
  }
d98966173   Antonio Quartulli   batman-adv: move ...
845
846
847
848
849
850
851
852
853
854
855
856
857
  /**
   * batadv_iv_ogm_slide_own_bcast_window - bitshift own OGM broadcast windows for
   * the given interface
   * @hard_iface: the interface for which the windows have to be shifted
   */
  static void
  batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface)
  {
  	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
  	struct batadv_hashtable *hash = bat_priv->orig_hash;
  	struct hlist_head *head;
  	struct batadv_orig_node *orig_node;
  	unsigned long *word;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
858
  	u32 i;
d98966173   Antonio Quartulli   batman-adv: move ...
859
  	size_t word_index;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
860
  	u8 *w;
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
861
  	int if_num;
d98966173   Antonio Quartulli   batman-adv: move ...
862
863
864
865
866
867
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  
  		rcu_read_lock();
  		hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
868
  			spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
d98966173   Antonio Quartulli   batman-adv: move ...
869
  			word_index = hard_iface->if_num * BATADV_NUM_WORDS;
32db6aaaf   Antonio Quartulli   batman-adv: check...
870
  			word = &orig_node->bat_iv.bcast_own[word_index];
d98966173   Antonio Quartulli   batman-adv: move ...
871
872
  
  			batadv_bit_get_packet(bat_priv, word, 1, 0);
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
873
874
  			if_num = hard_iface->if_num;
  			w = &orig_node->bat_iv.bcast_own_sum[if_num];
d98966173   Antonio Quartulli   batman-adv: move ...
875
  			*w = bitmap_weight(word, BATADV_TQ_LOCAL_WINDOW_SIZE);
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
876
  			spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
d98966173   Antonio Quartulli   batman-adv: move ...
877
878
879
880
  		}
  		rcu_read_unlock();
  	}
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
881
  static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
b9dacc521   Marek Lindner   batman-adv: agglo...
882
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
883
  	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
14511519d   Marek Lindner   batman-adv: split...
884
  	unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
964126901   Sven Eckelmann   batman-adv: Prefi...
885
  	struct batadv_ogm_packet *batadv_ogm_packet;
ef0a937f7   Simon Wunderlich   batman-adv: consi...
886
  	struct batadv_hard_iface *primary_if, *tmp_hard_iface;
14511519d   Marek Lindner   batman-adv: split...
887
  	int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
888
889
  	u32 seqno;
  	u16 tvlv_len = 0;
ef0a937f7   Simon Wunderlich   batman-adv: consi...
890
  	unsigned long send_time;
b9dacc521   Marek Lindner   batman-adv: agglo...
891

f0d97253f   Antonio Quartulli   batman-adv: remov...
892
893
894
895
896
897
898
899
900
901
902
903
  	if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) ||
  	    (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED))
  		return;
  
  	/* the interface gets activated here to avoid race conditions between
  	 * the moment of activating the interface in
  	 * hardif_activate_interface() where the originator mac is set and
  	 * outdated packets (especially uninitialized mac addresses) in the
  	 * packet queue
  	 */
  	if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
  		hard_iface->if_status = BATADV_IF_ACTIVE;
e5d89254b   Sven Eckelmann   batman-adv: Prefi...
904
  	primary_if = batadv_primary_if_get_selected(bat_priv);
b9dacc521   Marek Lindner   batman-adv: agglo...
905

e1bf0c140   Marek Lindner   batman-adv: tvlv ...
906
907
908
909
910
  	if (hard_iface == primary_if) {
  		/* tt changes have to be committed before the tvlv data is
  		 * appended as it may alter the tt tvlv container
  		 */
  		batadv_tt_local_commit_changes(bat_priv);
ef2615774   Marek Lindner   batman-adv: tvlv ...
911
912
913
  		tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
  							    ogm_buff_len,
  							    BATADV_OGM_HLEN);
e1bf0c140   Marek Lindner   batman-adv: tvlv ...
914
  	}
be9aa4c1e   Marek Lindner   batman-adv: turn ...
915

14511519d   Marek Lindner   batman-adv: split...
916
  	batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff);
ef2615774   Marek Lindner   batman-adv: tvlv ...
917
  	batadv_ogm_packet->tvlv_len = htons(tvlv_len);
b9dacc521   Marek Lindner   batman-adv: agglo...
918
919
  
  	/* change sequence number to network order */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
920
  	seqno = (u32)atomic_read(&hard_iface->bat_iv.ogm_seqno);
bbb1f90ef   Sven Eckelmann   batman-adv: Don't...
921
  	batadv_ogm_packet->seqno = htonl(seqno);
14511519d   Marek Lindner   batman-adv: split...
922
  	atomic_inc(&hard_iface->bat_iv.ogm_seqno);
b9dacc521   Marek Lindner   batman-adv: agglo...
923

d98966173   Antonio Quartulli   batman-adv: move ...
924
  	batadv_iv_ogm_slide_own_bcast_window(hard_iface);
b9dacc521   Marek Lindner   batman-adv: agglo...
925

ef0a937f7   Simon Wunderlich   batman-adv: consi...
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
  	send_time = batadv_iv_ogm_emit_send_time(bat_priv);
  
  	if (hard_iface != primary_if) {
  		/* OGMs from secondary interfaces are only scheduled on their
  		 * respective interfaces.
  		 */
  		batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
  					hard_iface, hard_iface, 1, send_time);
  		goto out;
  	}
  
  	/* OGMs from primary interfaces are scheduled on all
  	 * interfaces.
  	 */
  	rcu_read_lock();
  	list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) {
  		if (tmp_hard_iface->soft_iface != hard_iface->soft_iface)
87b40f534   Sven Eckelmann   batman-adv: Fix c...
943
  			continue;
273534468   Sven Eckelmann   batman-adv: Check...
944
945
946
  
  		if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
  			continue;
ef0a937f7   Simon Wunderlich   batman-adv: consi...
947
948
949
  		batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
  					*ogm_buff_len, hard_iface,
  					tmp_hard_iface, 1, send_time);
273534468   Sven Eckelmann   batman-adv: Check...
950
951
  
  		batadv_hardif_put(tmp_hard_iface);
ef0a937f7   Simon Wunderlich   batman-adv: consi...
952
953
954
955
  	}
  	rcu_read_unlock();
  
  out:
b9dacc521   Marek Lindner   batman-adv: agglo...
956
  	if (primary_if)
82047ad7f   Sven Eckelmann   batman-adv: Renam...
957
  		batadv_hardif_put(primary_if);
b9dacc521   Marek Lindner   batman-adv: agglo...
958
  }
89652331c   Simon Wunderlich   batman-adv: split...
959
960
961
962
963
  /**
   * batadv_iv_ogm_orig_update - use OGM to update corresponding data in an
   *  originator
   * @bat_priv: the bat priv with all the soft interface information
   * @orig_node: the orig node who originally emitted the ogm packet
7351a4822   Simon Wunderlich   batman-adv: split...
964
   * @orig_ifinfo: ifinfo for the outgoing interface of the orig_node
89652331c   Simon Wunderlich   batman-adv: split...
965
966
967
968
   * @ethhdr: Ethernet header of the OGM
   * @batadv_ogm_packet: the ogm packet
   * @if_incoming: interface where the packet was received
   * @if_outgoing: interface for which the retransmission should be considered
89652331c   Simon Wunderlich   batman-adv: split...
969
970
   * @dup_status: the duplicate status of this ogm packet.
   */
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
971
  static void
56303d34a   Sven Eckelmann   batman-adv: Prefi...
972
973
  batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
  			  struct batadv_orig_node *orig_node,
7351a4822   Simon Wunderlich   batman-adv: split...
974
  			  struct batadv_orig_ifinfo *orig_ifinfo,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
975
  			  const struct ethhdr *ethhdr,
964126901   Sven Eckelmann   batman-adv: Prefi...
976
  			  const struct batadv_ogm_packet *batadv_ogm_packet,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
977
  			  struct batadv_hard_iface *if_incoming,
89652331c   Simon Wunderlich   batman-adv: split...
978
  			  struct batadv_hard_iface *if_outgoing,
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
979
  			  enum batadv_dup_status dup_status)
fc9572756   Marek Lindner   batman-adv: agglo...
980
  {
89652331c   Simon Wunderlich   batman-adv: split...
981
982
  	struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
  	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
4f248cff9   Sven Eckelmann   batman-adv: Remov...
983
984
  	struct batadv_neigh_node *neigh_node = NULL;
  	struct batadv_neigh_node *tmp_neigh_node = NULL;
56303d34a   Sven Eckelmann   batman-adv: Prefi...
985
986
  	struct batadv_neigh_node *router = NULL;
  	struct batadv_orig_node *orig_node_tmp;
7caf69fb9   Linus LĂĽssing   batman-adv: Fix s...
987
  	int if_num;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
988
989
990
  	u8 sum_orig, sum_neigh;
  	u8 *neigh_addr;
  	u8 tq_avg;
fc9572756   Marek Lindner   batman-adv: agglo...
991

39c75a51e   Sven Eckelmann   batman-adv: Prefi...
992
  	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
22f0502ed   Sven Eckelmann   batman-adv: Print...
993
994
995
  		   "%s(): Searching and updating originator entry of received packet
  ",
  		   __func__);
fc9572756   Marek Lindner   batman-adv: agglo...
996
997
  
  	rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
998
  	hlist_for_each_entry_rcu(tmp_neigh_node,
fc9572756   Marek Lindner   batman-adv: agglo...
999
  				 &orig_node->neigh_list, list) {
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1000
1001
1002
  		neigh_addr = tmp_neigh_node->addr;
  		if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
  		    tmp_neigh_node->if_incoming == if_incoming &&
77ae32e89   Sven Eckelmann   batman-adv: Conve...
1003
  		    kref_get_unless_zero(&tmp_neigh_node->refcount)) {
38dc40ef5   Antonio Quartulli   batman-adv: do no...
1004
  			if (WARN(neigh_node, "too many matching neigh_nodes"))
25bb25099   Sven Eckelmann   batman-adv: Renam...
1005
  				batadv_neigh_node_put(neigh_node);
fc9572756   Marek Lindner   batman-adv: agglo...
1006
1007
1008
  			neigh_node = tmp_neigh_node;
  			continue;
  		}
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1009
  		if (dup_status != BATADV_NO_DUP)
fc9572756   Marek Lindner   batman-adv: agglo...
1010
  			continue;
89652331c   Simon Wunderlich   batman-adv: split...
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
  		/* only update the entry for this outgoing interface */
  		neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node,
  						       if_outgoing);
  		if (!neigh_ifinfo)
  			continue;
  
  		spin_lock_bh(&tmp_neigh_node->ifinfo_lock);
  		batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
  				       &neigh_ifinfo->bat_iv.tq_index, 0);
  		tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
  		neigh_ifinfo->bat_iv.tq_avg = tq_avg;
  		spin_unlock_bh(&tmp_neigh_node->ifinfo_lock);
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
1023
  		batadv_neigh_ifinfo_put(neigh_ifinfo);
89652331c   Simon Wunderlich   batman-adv: split...
1024
  		neigh_ifinfo = NULL;
fc9572756   Marek Lindner   batman-adv: agglo...
1025
1026
1027
  	}
  
  	if (!neigh_node) {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1028
  		struct batadv_orig_node *orig_tmp;
fc9572756   Marek Lindner   batman-adv: agglo...
1029

bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1030
  		orig_tmp = batadv_iv_ogm_orig_get(bat_priv, ethhdr->h_source);
fc9572756   Marek Lindner   batman-adv: agglo...
1031
1032
  		if (!orig_tmp)
  			goto unlock;
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
1033
1034
  		neigh_node = batadv_iv_ogm_neigh_new(if_incoming,
  						     ethhdr->h_source,
863dd7a82   Antonio Quartulli   batman-adv: drop ...
1035
  						     orig_node, orig_tmp);
fc9572756   Marek Lindner   batman-adv: agglo...
1036

5d9673109   Sven Eckelmann   batman-adv: Renam...
1037
  		batadv_orig_node_put(orig_tmp);
fc9572756   Marek Lindner   batman-adv: agglo...
1038
1039
  		if (!neigh_node)
  			goto unlock;
23badd6db   Markus Pargmann   batman-adv: iv_og...
1040
  	} else {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1041
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1042
1043
  			   "Updating existing last-hop neighbor of originator
  ");
23badd6db   Markus Pargmann   batman-adv: iv_og...
1044
  	}
fc9572756   Marek Lindner   batman-adv: agglo...
1045
1046
  
  	rcu_read_unlock();
89652331c   Simon Wunderlich   batman-adv: split...
1047
1048
1049
  	neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
  	if (!neigh_ifinfo)
  		goto out;
fc9572756   Marek Lindner   batman-adv: agglo...
1050

d7b2a97e0   Marek Lindner   batman-adv: renam...
1051
  	neigh_node->last_seen = jiffies;
fc9572756   Marek Lindner   batman-adv: agglo...
1052

89652331c   Simon Wunderlich   batman-adv: split...
1053
1054
1055
  	spin_lock_bh(&neigh_node->ifinfo_lock);
  	batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
  			       &neigh_ifinfo->bat_iv.tq_index,
964126901   Sven Eckelmann   batman-adv: Prefi...
1056
  			       batadv_ogm_packet->tq);
89652331c   Simon Wunderlich   batman-adv: split...
1057
1058
1059
  	tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
  	neigh_ifinfo->bat_iv.tq_avg = tq_avg;
  	spin_unlock_bh(&neigh_node->ifinfo_lock);
fc9572756   Marek Lindner   batman-adv: agglo...
1060

7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1061
  	if (dup_status == BATADV_NO_DUP) {
7351a4822   Simon Wunderlich   batman-adv: split...
1062
  		orig_ifinfo->last_ttl = batadv_ogm_packet->ttl;
89652331c   Simon Wunderlich   batman-adv: split...
1063
  		neigh_ifinfo->last_ttl = batadv_ogm_packet->ttl;
fc9572756   Marek Lindner   batman-adv: agglo...
1064
  	}
fc9572756   Marek Lindner   batman-adv: agglo...
1065
  	/* if this neighbor already is our next hop there is nothing
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
1066
1067
  	 * to change
  	 */
7351a4822   Simon Wunderlich   batman-adv: split...
1068
  	router = batadv_orig_router_get(orig_node, if_outgoing);
fc9572756   Marek Lindner   batman-adv: agglo...
1069
  	if (router == neigh_node)
e1bf0c140   Marek Lindner   batman-adv: tvlv ...
1070
  		goto out;
fc9572756   Marek Lindner   batman-adv: agglo...
1071

89652331c   Simon Wunderlich   batman-adv: split...
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
  	if (router) {
  		router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
  		if (!router_ifinfo)
  			goto out;
  
  		/* if this neighbor does not offer a better TQ we won't
  		 * consider it
  		 */
  		if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg)
  			goto out;
  	}
fc9572756   Marek Lindner   batman-adv: agglo...
1083
1084
  
  	/* if the TQ is the same and the link not more symmetric we
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
1085
1086
  	 * won't consider it either
  	 */
89652331c   Simon Wunderlich   batman-adv: split...
1087
  	if (router_ifinfo &&
01b97a3ee   Markus Pargmann   batman-adv: iv_og...
1088
  	    neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg) {
fc9572756   Marek Lindner   batman-adv: agglo...
1089
  		orig_node_tmp = router->orig_node;
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1090
  		spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
7caf69fb9   Linus LĂĽssing   batman-adv: Fix s...
1091
  		if_num = router->if_incoming->if_num;
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1092
1093
  		sum_orig = orig_node_tmp->bat_iv.bcast_own_sum[if_num];
  		spin_unlock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
fc9572756   Marek Lindner   batman-adv: agglo...
1094
1095
  
  		orig_node_tmp = neigh_node->orig_node;
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1096
  		spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
7caf69fb9   Linus LĂĽssing   batman-adv: Fix s...
1097
  		if_num = neigh_node->if_incoming->if_num;
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1098
1099
  		sum_neigh = orig_node_tmp->bat_iv.bcast_own_sum[if_num];
  		spin_unlock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
fc9572756   Marek Lindner   batman-adv: agglo...
1100

bbb1f90ef   Sven Eckelmann   batman-adv: Don't...
1101
  		if (sum_orig >= sum_neigh)
e1bf0c140   Marek Lindner   batman-adv: tvlv ...
1102
  			goto out;
fc9572756   Marek Lindner   batman-adv: agglo...
1103
  	}
7351a4822   Simon Wunderlich   batman-adv: split...
1104
  	batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
fc9572756   Marek Lindner   batman-adv: agglo...
1105
1106
1107
1108
1109
1110
  	goto out;
  
  unlock:
  	rcu_read_unlock();
  out:
  	if (neigh_node)
25bb25099   Sven Eckelmann   batman-adv: Renam...
1111
  		batadv_neigh_node_put(neigh_node);
fc9572756   Marek Lindner   batman-adv: agglo...
1112
  	if (router)
25bb25099   Sven Eckelmann   batman-adv: Renam...
1113
  		batadv_neigh_node_put(router);
89652331c   Simon Wunderlich   batman-adv: split...
1114
  	if (neigh_ifinfo)
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
1115
  		batadv_neigh_ifinfo_put(neigh_ifinfo);
89652331c   Simon Wunderlich   batman-adv: split...
1116
  	if (router_ifinfo)
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
1117
  		batadv_neigh_ifinfo_put(router_ifinfo);
fc9572756   Marek Lindner   batman-adv: agglo...
1118
  }
89652331c   Simon Wunderlich   batman-adv: split...
1119
1120
1121
1122
1123
1124
1125
1126
  /**
   * batadv_iv_ogm_calc_tq - calculate tq for current received ogm packet
   * @orig_node: the orig node who originally emitted the ogm packet
   * @orig_neigh_node: the orig node struct of the neighbor who sent the packet
   * @batadv_ogm_packet: the ogm packet
   * @if_incoming: interface where the packet was received
   * @if_outgoing: interface for which the retransmission should be considered
   *
4b426b108   Sven Eckelmann   batman-adv: Use b...
1127
   * Return: true if the link can be considered bidirectional, false otherwise
89652331c   Simon Wunderlich   batman-adv: split...
1128
   */
4b426b108   Sven Eckelmann   batman-adv: Use b...
1129
1130
1131
1132
1133
  static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
  				  struct batadv_orig_node *orig_neigh_node,
  				  struct batadv_ogm_packet *batadv_ogm_packet,
  				  struct batadv_hard_iface *if_incoming,
  				  struct batadv_hard_iface *if_outgoing)
fc9572756   Marek Lindner   batman-adv: agglo...
1134
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1135
1136
  	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
  	struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node;
89652331c   Simon Wunderlich   batman-adv: split...
1137
  	struct batadv_neigh_ifinfo *neigh_ifinfo;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1138
1139
  	u8 total_count;
  	u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
1140
  	unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
d285f52cc   Sven Eckelmann   batman-adv: Fix i...
1141
1142
  	int if_num;
  	unsigned int tq_asym_penalty, inv_asym_penalty;
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
1143
  	unsigned int combined_tq;
d285f52cc   Sven Eckelmann   batman-adv: Fix i...
1144
  	unsigned int tq_iface_penalty;
4b426b108   Sven Eckelmann   batman-adv: Use b...
1145
  	bool ret = false;
fc9572756   Marek Lindner   batman-adv: agglo...
1146
1147
1148
  
  	/* find corresponding one hop neighbor */
  	rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
1149
  	hlist_for_each_entry_rcu(tmp_neigh_node,
fc9572756   Marek Lindner   batman-adv: agglo...
1150
  				 &orig_neigh_node->neigh_list, list) {
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1151
1152
  		if (!batadv_compare_eth(tmp_neigh_node->addr,
  					orig_neigh_node->orig))
fc9572756   Marek Lindner   batman-adv: agglo...
1153
1154
1155
1156
  			continue;
  
  		if (tmp_neigh_node->if_incoming != if_incoming)
  			continue;
77ae32e89   Sven Eckelmann   batman-adv: Conve...
1157
  		if (!kref_get_unless_zero(&tmp_neigh_node->refcount))
fc9572756   Marek Lindner   batman-adv: agglo...
1158
1159
1160
1161
1162
1163
1164
1165
  			continue;
  
  		neigh_node = tmp_neigh_node;
  		break;
  	}
  	rcu_read_unlock();
  
  	if (!neigh_node)
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
1166
1167
1168
  		neigh_node = batadv_iv_ogm_neigh_new(if_incoming,
  						     orig_neigh_node->orig,
  						     orig_neigh_node,
863dd7a82   Antonio Quartulli   batman-adv: drop ...
1169
  						     orig_neigh_node);
fc9572756   Marek Lindner   batman-adv: agglo...
1170
1171
1172
  
  	if (!neigh_node)
  		goto out;
d7b2a97e0   Marek Lindner   batman-adv: renam...
1173
  	/* if orig_node is direct neighbor update neigh_node last_seen */
fc9572756   Marek Lindner   batman-adv: agglo...
1174
  	if (orig_node == orig_neigh_node)
d7b2a97e0   Marek Lindner   batman-adv: renam...
1175
  		neigh_node->last_seen = jiffies;
fc9572756   Marek Lindner   batman-adv: agglo...
1176

d7b2a97e0   Marek Lindner   batman-adv: renam...
1177
  	orig_node->last_seen = jiffies;
fc9572756   Marek Lindner   batman-adv: agglo...
1178
1179
  
  	/* find packet count of corresponding one hop neighbor */
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1180
1181
1182
  	spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
  	if_num = if_incoming->if_num;
  	orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num];
89652331c   Simon Wunderlich   batman-adv: split...
1183
1184
1185
  	neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
  	if (neigh_ifinfo) {
  		neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count;
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
1186
  		batadv_neigh_ifinfo_put(neigh_ifinfo);
89652331c   Simon Wunderlich   batman-adv: split...
1187
1188
1189
  	} else {
  		neigh_rq_count = 0;
  	}
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1190
  	spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
fc9572756   Marek Lindner   batman-adv: agglo...
1191
1192
  
  	/* pay attention to not get a value bigger than 100 % */
c67893d17   Sven Eckelmann   batman-adv: Reduc...
1193
1194
1195
1196
  	if (orig_eq_count > neigh_rq_count)
  		total_count = neigh_rq_count;
  	else
  		total_count = orig_eq_count;
fc9572756   Marek Lindner   batman-adv: agglo...
1197

9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
1198
1199
1200
  	/* if we have too few packets (too less data) we set tq_own to zero
  	 * if we receive too few packets it is not considered bidirectional
  	 */
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
1201
1202
  	if (total_count < BATADV_TQ_LOCAL_BIDRECT_SEND_MINIMUM ||
  	    neigh_rq_count < BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM)
fc9572756   Marek Lindner   batman-adv: agglo...
1203
1204
1205
1206
  		tq_own = 0;
  	else
  		/* neigh_node->real_packet_count is never zero as we
  		 * only purge old information when getting new
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
1207
1208
  		 * information
  		 */
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
1209
  		tq_own = (BATADV_TQ_MAX_VALUE * total_count) /	neigh_rq_count;
fc9572756   Marek Lindner   batman-adv: agglo...
1210

21a1236bc   Sven Eckelmann   batman-adv: Don't...
1211
  	/* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
fc9572756   Marek Lindner   batman-adv: agglo...
1212
1213
1214
1215
  	 * affect the nearly-symmetric links only a little, but
  	 * punishes asymmetric links more.  This will give a value
  	 * between 0 and TQ_MAX_VALUE
  	 */
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
1216
1217
1218
1219
1220
1221
1222
1223
  	neigh_rq_inv = BATADV_TQ_LOCAL_WINDOW_SIZE - neigh_rq_count;
  	neigh_rq_inv_cube = neigh_rq_inv * neigh_rq_inv * neigh_rq_inv;
  	neigh_rq_max_cube = BATADV_TQ_LOCAL_WINDOW_SIZE *
  			    BATADV_TQ_LOCAL_WINDOW_SIZE *
  			    BATADV_TQ_LOCAL_WINDOW_SIZE;
  	inv_asym_penalty = BATADV_TQ_MAX_VALUE * neigh_rq_inv_cube;
  	inv_asym_penalty /= neigh_rq_max_cube;
  	tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty;
c03987689   Simon Wunderlich   batman-adv: add W...
1224
1225
1226
1227
1228
1229
  	/* penalize if the OGM is forwarded on the same interface. WiFi
  	 * interfaces and other half duplex devices suffer from throughput
  	 * drops as they can't send and receive at the same time.
  	 */
  	tq_iface_penalty = BATADV_TQ_MAX_VALUE;
  	if (if_outgoing && (if_incoming == if_outgoing) &&
10b1bbb46   Sven Eckelmann   batman-adv: Cache...
1230
  	    batadv_is_wifi_hardif(if_outgoing))
c03987689   Simon Wunderlich   batman-adv: add W...
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
  		tq_iface_penalty = batadv_hop_penalty(BATADV_TQ_MAX_VALUE,
  						      bat_priv);
  
  	combined_tq = batadv_ogm_packet->tq *
  		      tq_own *
  		      tq_asym_penalty *
  		      tq_iface_penalty;
  	combined_tq /= BATADV_TQ_MAX_VALUE *
  		       BATADV_TQ_MAX_VALUE *
  		       BATADV_TQ_MAX_VALUE;
964126901   Sven Eckelmann   batman-adv: Prefi...
1241
  	batadv_ogm_packet->tq = combined_tq;
fc9572756   Marek Lindner   batman-adv: agglo...
1242

39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1243
  	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
6a04be8d8   Sven Eckelmann   batman-adv: Remov...
1244
1245
  		   "bidirectional: orig = %pM neigh = %pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, iface_penalty: %3i, total tq: %3i, if_incoming = %s, if_outgoing = %s
  ",
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1246
  		   orig_node->orig, orig_neigh_node->orig, total_count,
c03987689   Simon Wunderlich   batman-adv: add W...
1247
1248
1249
  		   neigh_rq_count, tq_own, tq_asym_penalty, tq_iface_penalty,
  		   batadv_ogm_packet->tq, if_incoming->net_dev->name,
  		   if_outgoing ? if_outgoing->net_dev->name : "DEFAULT");
fc9572756   Marek Lindner   batman-adv: agglo...
1250
1251
  
  	/* if link has the minimum required transmission quality
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
1252
1253
  	 * consider it bidirectional
  	 */
964126901   Sven Eckelmann   batman-adv: Prefi...
1254
  	if (batadv_ogm_packet->tq >= BATADV_TQ_TOTAL_BIDRECT_LIMIT)
4b426b108   Sven Eckelmann   batman-adv: Use b...
1255
  		ret = true;
fc9572756   Marek Lindner   batman-adv: agglo...
1256
1257
1258
  
  out:
  	if (neigh_node)
25bb25099   Sven Eckelmann   batman-adv: Renam...
1259
  		batadv_neigh_node_put(neigh_node);
fc9572756   Marek Lindner   batman-adv: agglo...
1260
1261
  	return ret;
  }
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1262
1263
1264
1265
1266
1267
  /**
   * batadv_iv_ogm_update_seqnos -  process a batman packet for all interfaces,
   *  adjust the sequence number and find out whether it is a duplicate
   * @ethhdr: ethernet header of the packet
   * @batadv_ogm_packet: OGM packet to be considered
   * @if_incoming: interface on which the OGM packet was received
89652331c   Simon Wunderlich   batman-adv: split...
1268
   * @if_outgoing: interface for which the retransmission should be considered
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1269
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1270
   * Return: duplicate status as enum batadv_dup_status
fc9572756   Marek Lindner   batman-adv: agglo...
1271
   */
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1272
  static enum batadv_dup_status
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
1273
  batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
964126901   Sven Eckelmann   batman-adv: Prefi...
1274
  			    const struct batadv_ogm_packet *batadv_ogm_packet,
89652331c   Simon Wunderlich   batman-adv: split...
1275
1276
  			    const struct batadv_hard_iface *if_incoming,
  			    struct batadv_hard_iface *if_outgoing)
fc9572756   Marek Lindner   batman-adv: agglo...
1277
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1278
1279
  	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
  	struct batadv_orig_node *orig_node;
7351a4822   Simon Wunderlich   batman-adv: split...
1280
  	struct batadv_orig_ifinfo *orig_ifinfo = NULL;
89652331c   Simon Wunderlich   batman-adv: split...
1281
1282
  	struct batadv_neigh_node *neigh_node;
  	struct batadv_neigh_ifinfo *neigh_ifinfo;
4b426b108   Sven Eckelmann   batman-adv: Use b...
1283
  	bool is_dup;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1284
  	s32 seq_diff;
4b426b108   Sven Eckelmann   batman-adv: Use b...
1285
  	bool need_update = false;
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1286
1287
  	int set_mark;
  	enum batadv_dup_status ret = BATADV_NO_DUP;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1288
1289
1290
  	u32 seqno = ntohl(batadv_ogm_packet->seqno);
  	u8 *neigh_addr;
  	u8 packet_count;
0538f7599   Antonio Quartulli   batman-adv: make ...
1291
  	unsigned long *bitmap;
fc9572756   Marek Lindner   batman-adv: agglo...
1292

bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1293
  	orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig);
fc9572756   Marek Lindner   batman-adv: agglo...
1294
  	if (!orig_node)
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1295
  		return BATADV_NO_DUP;
fc9572756   Marek Lindner   batman-adv: agglo...
1296

7351a4822   Simon Wunderlich   batman-adv: split...
1297
1298
  	orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
  	if (WARN_ON(!orig_ifinfo)) {
5d9673109   Sven Eckelmann   batman-adv: Renam...
1299
  		batadv_orig_node_put(orig_node);
7351a4822   Simon Wunderlich   batman-adv: split...
1300
1301
  		return 0;
  	}
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1302
  	spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
7351a4822   Simon Wunderlich   batman-adv: split...
1303
  	seq_diff = seqno - orig_ifinfo->last_real_seqno;
fc9572756   Marek Lindner   batman-adv: agglo...
1304
1305
  
  	/* signalize caller that the packet is to be dropped. */
1e5cc266d   Antonio Quartulli   batman-adv: skip ...
1306
  	if (!hlist_empty(&orig_node->neigh_list) &&
30d3c5113   Sven Eckelmann   batman-adv: Prefi...
1307
  	    batadv_window_protected(bat_priv, seq_diff,
81f026835   Simon Wunderlich   batman-adv: add s...
1308
1309
  				    BATADV_TQ_LOCAL_WINDOW_SIZE,
  				    &orig_ifinfo->batman_seqno_reset, NULL)) {
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1310
  		ret = BATADV_PROTECTED;
fc9572756   Marek Lindner   batman-adv: agglo...
1311
  		goto out;
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1312
  	}
fc9572756   Marek Lindner   batman-adv: agglo...
1313
1314
  
  	rcu_read_lock();
89652331c   Simon Wunderlich   batman-adv: split...
1315
1316
1317
1318
1319
1320
1321
1322
  	hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
  		neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node,
  						       if_outgoing);
  		if (!neigh_ifinfo)
  			continue;
  
  		neigh_addr = neigh_node->addr;
  		is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits,
7351a4822   Simon Wunderlich   batman-adv: split...
1323
  					 orig_ifinfo->last_real_seqno,
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1324
  					 seqno);
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1325
  		if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
89652331c   Simon Wunderlich   batman-adv: split...
1326
  		    neigh_node->if_incoming == if_incoming) {
fc9572756   Marek Lindner   batman-adv: agglo...
1327
  			set_mark = 1;
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1328
1329
1330
  			if (is_dup)
  				ret = BATADV_NEIGH_DUP;
  		} else {
fc9572756   Marek Lindner   batman-adv: agglo...
1331
  			set_mark = 0;
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1332
1333
1334
  			if (is_dup && (ret != BATADV_NEIGH_DUP))
  				ret = BATADV_ORIG_DUP;
  		}
fc9572756   Marek Lindner   batman-adv: agglo...
1335
1336
  
  		/* if the window moved, set the update flag. */
89652331c   Simon Wunderlich   batman-adv: split...
1337
  		bitmap = neigh_ifinfo->bat_iv.real_bits;
0538f7599   Antonio Quartulli   batman-adv: make ...
1338
  		need_update |= batadv_bit_get_packet(bat_priv, bitmap,
0f5f93226   Sven Eckelmann   batman-adv: Prefi...
1339
  						     seq_diff, set_mark);
fc9572756   Marek Lindner   batman-adv: agglo...
1340

89652331c   Simon Wunderlich   batman-adv: split...
1341
  		packet_count = bitmap_weight(bitmap,
bbb1f90ef   Sven Eckelmann   batman-adv: Don't...
1342
  					     BATADV_TQ_LOCAL_WINDOW_SIZE);
89652331c   Simon Wunderlich   batman-adv: split...
1343
  		neigh_ifinfo->bat_iv.real_packet_count = packet_count;
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
1344
  		batadv_neigh_ifinfo_put(neigh_ifinfo);
fc9572756   Marek Lindner   batman-adv: agglo...
1345
1346
1347
1348
  	}
  	rcu_read_unlock();
  
  	if (need_update) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1349
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
7351a4822   Simon Wunderlich   batman-adv: split...
1350
1351
1352
1353
1354
  			   "%s updating last_seqno: old %u, new %u
  ",
  			   if_outgoing ? if_outgoing->net_dev->name : "DEFAULT",
  			   orig_ifinfo->last_real_seqno, seqno);
  		orig_ifinfo->last_real_seqno = seqno;
fc9572756   Marek Lindner   batman-adv: agglo...
1355
  	}
fc9572756   Marek Lindner   batman-adv: agglo...
1356
  out:
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1357
  	spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
5d9673109   Sven Eckelmann   batman-adv: Renam...
1358
  	batadv_orig_node_put(orig_node);
35f94779c   Sven Eckelmann   batman-adv: Renam...
1359
  	batadv_orig_ifinfo_put(orig_ifinfo);
fc9572756   Marek Lindner   batman-adv: agglo...
1360
1361
  	return ret;
  }
7351a4822   Simon Wunderlich   batman-adv: split...
1362
1363
1364
  /**
   * batadv_iv_ogm_process_per_outif - process a batman iv OGM for an outgoing if
   * @skb: the skb containing the OGM
95298a91f   Martin Hundebøll   batman-adv: kerne...
1365
   * @ogm_offset: offset from skb->data to start of ogm header
7351a4822   Simon Wunderlich   batman-adv: split...
1366
1367
1368
1369
1370
1371
1372
1373
1374
   * @orig_node: the (cached) orig node for the originator of this OGM
   * @if_incoming: the interface where this packet was received
   * @if_outgoing: the interface for which the packet should be considered
   */
  static void
  batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
  				struct batadv_orig_node *orig_node,
  				struct batadv_hard_iface *if_incoming,
  				struct batadv_hard_iface *if_outgoing)
fc9572756   Marek Lindner   batman-adv: agglo...
1375
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1376
  	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
4ff1e2a73   Marek Lindner   batman-adv: updat...
1377
  	struct batadv_hardif_neigh_node *hardif_neigh = NULL;
4f248cff9   Sven Eckelmann   batman-adv: Remov...
1378
1379
  	struct batadv_neigh_node *router = NULL;
  	struct batadv_neigh_node *router_router = NULL;
7351a4822   Simon Wunderlich   batman-adv: split...
1380
1381
  	struct batadv_orig_node *orig_neigh_node;
  	struct batadv_orig_ifinfo *orig_ifinfo;
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1382
  	struct batadv_neigh_node *orig_neigh_router = NULL;
89652331c   Simon Wunderlich   batman-adv: split...
1383
  	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
7351a4822   Simon Wunderlich   batman-adv: split...
1384
  	struct batadv_ogm_packet *ogm_packet;
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1385
  	enum batadv_dup_status dup_status;
7351a4822   Simon Wunderlich   batman-adv: split...
1386
1387
1388
1389
1390
  	bool is_from_best_next_hop = false;
  	bool is_single_hop_neigh = false;
  	bool sameseq, similar_ttl;
  	struct sk_buff *skb_priv;
  	struct ethhdr *ethhdr;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1391
  	u8 *prev_sender;
4b426b108   Sven Eckelmann   batman-adv: Use b...
1392
  	bool is_bidirect;
fc9572756   Marek Lindner   batman-adv: agglo...
1393

7351a4822   Simon Wunderlich   batman-adv: split...
1394
1395
  	/* create a private copy of the skb, as some functions change tq value
  	 * and/or flags.
fc9572756   Marek Lindner   batman-adv: agglo...
1396
  	 */
7351a4822   Simon Wunderlich   batman-adv: split...
1397
1398
  	skb_priv = skb_copy(skb, GFP_ATOMIC);
  	if (!skb_priv)
fc9572756   Marek Lindner   batman-adv: agglo...
1399
  		return;
7351a4822   Simon Wunderlich   batman-adv: split...
1400
1401
  	ethhdr = eth_hdr(skb_priv);
  	ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset);
fc9572756   Marek Lindner   batman-adv: agglo...
1402

7351a4822   Simon Wunderlich   batman-adv: split...
1403
1404
1405
  	dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet,
  						 if_incoming, if_outgoing);
  	if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig))
75cd33f86   Marek Lindner   batman-adv: intro...
1406
  		is_single_hop_neigh = true;
fc9572756   Marek Lindner   batman-adv: agglo...
1407

7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1408
  	if (dup_status == BATADV_PROTECTED) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1409
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1410
1411
1412
  			   "Drop packet: packet within seqno protection time (sender: %pM)
  ",
  			   ethhdr->h_source);
fc9572756   Marek Lindner   batman-adv: agglo...
1413
1414
  		goto out;
  	}
7351a4822   Simon Wunderlich   batman-adv: split...
1415
  	if (ogm_packet->tq == 0) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1416
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1417
1418
  			   "Drop packet: originator packet with tq equal 0
  ");
fc9572756   Marek Lindner   batman-adv: agglo...
1419
1420
  		goto out;
  	}
4ff1e2a73   Marek Lindner   batman-adv: updat...
1421
1422
1423
1424
1425
1426
  	if (is_single_hop_neigh) {
  		hardif_neigh = batadv_hardif_neigh_get(if_incoming,
  						       ethhdr->h_source);
  		if (hardif_neigh)
  			hardif_neigh->last_seen = jiffies;
  	}
7351a4822   Simon Wunderlich   batman-adv: split...
1427
  	router = batadv_orig_router_get(orig_node, if_outgoing);
0538f7599   Antonio Quartulli   batman-adv: make ...
1428
  	if (router) {
7351a4822   Simon Wunderlich   batman-adv: split...
1429
1430
1431
  		router_router = batadv_orig_router_get(router->orig_node,
  						       if_outgoing);
  		router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
0538f7599   Antonio Quartulli   batman-adv: make ...
1432
  	}
fc9572756   Marek Lindner   batman-adv: agglo...
1433

7351a4822   Simon Wunderlich   batman-adv: split...
1434
  	if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) &&
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1435
  	    (batadv_compare_eth(router->addr, ethhdr->h_source)))
13b2541b1   Marek Lindner   batman-adv: avoid...
1436
  		is_from_best_next_hop = true;
7351a4822   Simon Wunderlich   batman-adv: split...
1437
  	prev_sender = ogm_packet->prev_sender;
fc9572756   Marek Lindner   batman-adv: agglo...
1438
1439
  	/* avoid temporary routing loops */
  	if (router && router_router &&
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1440
  	    (batadv_compare_eth(router->addr, prev_sender)) &&
7351a4822   Simon Wunderlich   batman-adv: split...
1441
  	    !(batadv_compare_eth(ogm_packet->orig, prev_sender)) &&
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1442
  	    (batadv_compare_eth(router->addr, router_router->addr))) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1443
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1444
1445
1446
  			   "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)
  ",
  			   ethhdr->h_source);
fc9572756   Marek Lindner   batman-adv: agglo...
1447
1448
  		goto out;
  	}
7351a4822   Simon Wunderlich   batman-adv: split...
1449
1450
  	if (if_outgoing == BATADV_IF_DEFAULT)
  		batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1451

fc9572756   Marek Lindner   batman-adv: agglo...
1452
  	/* if sender is a direct neighbor the sender mac equals
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
1453
1454
  	 * originator mac
  	 */
c67893d17   Sven Eckelmann   batman-adv: Reduc...
1455
1456
1457
  	if (is_single_hop_neigh)
  		orig_neigh_node = orig_node;
  	else
bbad0a5e3   Antonio Quartulli   batman-adv: make ...
1458
1459
  		orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
  							 ethhdr->h_source);
c67893d17   Sven Eckelmann   batman-adv: Reduc...
1460

fc9572756   Marek Lindner   batman-adv: agglo...
1461
1462
  	if (!orig_neigh_node)
  		goto out;
d56b1705e   Martin Hundebøll   batman-adv: netwo...
1463
1464
  	/* Update nc_nodes of the originator */
  	batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
7351a4822   Simon Wunderlich   batman-adv: split...
1465
  				 ogm_packet, is_single_hop_neigh);
d56b1705e   Martin Hundebøll   batman-adv: netwo...
1466

7351a4822   Simon Wunderlich   batman-adv: split...
1467
1468
  	orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
  						   if_outgoing);
fc9572756   Marek Lindner   batman-adv: agglo...
1469
1470
  
  	/* drop packet if sender is not a direct neighbor and if we
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
1471
1472
  	 * don't route towards it
  	 */
fc9572756   Marek Lindner   batman-adv: agglo...
1473
  	if (!is_single_hop_neigh && (!orig_neigh_router)) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1474
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1475
1476
  			   "Drop packet: OGM via unknown neighbor!
  ");
fc9572756   Marek Lindner   batman-adv: agglo...
1477
1478
  		goto out_neigh;
  	}
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
1479
  	is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
7351a4822   Simon Wunderlich   batman-adv: split...
1480
1481
  					    ogm_packet, if_incoming,
  					    if_outgoing);
fc9572756   Marek Lindner   batman-adv: agglo...
1482

fc9572756   Marek Lindner   batman-adv: agglo...
1483
  	/* update ranking if it is not a duplicate or has the same
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
1484
1485
  	 * seqno and similar ttl as the non-duplicate
  	 */
7351a4822   Simon Wunderlich   batman-adv: split...
1486
1487
1488
1489
1490
1491
  	orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
  	if (!orig_ifinfo)
  		goto out_neigh;
  
  	sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno);
  	similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->ttl;
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1492
  	if (is_bidirect && ((dup_status == BATADV_NO_DUP) ||
7351a4822   Simon Wunderlich   batman-adv: split...
1493
1494
1495
1496
1497
1498
  			    (sameseq && similar_ttl))) {
  		batadv_iv_ogm_orig_update(bat_priv, orig_node,
  					  orig_ifinfo, ethhdr,
  					  ogm_packet, if_incoming,
  					  if_outgoing, dup_status);
  	}
35f94779c   Sven Eckelmann   batman-adv: Renam...
1499
  	batadv_orig_ifinfo_put(orig_ifinfo);
fc9572756   Marek Lindner   batman-adv: agglo...
1500

ef0a937f7   Simon Wunderlich   batman-adv: consi...
1501
1502
1503
  	/* only forward for specific interface, not for the default one. */
  	if (if_outgoing == BATADV_IF_DEFAULT)
  		goto out_neigh;
fc9572756   Marek Lindner   batman-adv: agglo...
1504
1505
  	/* is single hop (direct) neighbor */
  	if (is_single_hop_neigh) {
7351a4822   Simon Wunderlich   batman-adv: split...
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
  		/* OGMs from secondary interfaces should only scheduled once
  		 * per interface where it has been received, not multiple times
  		 */
  		if ((ogm_packet->ttl <= 2) &&
  		    (if_incoming != if_outgoing)) {
  			batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
  				   "Drop packet: OGM from secondary interface and wrong outgoing interface
  ");
  			goto out_neigh;
  		}
fc9572756   Marek Lindner   batman-adv: agglo...
1516
  		/* mark direct link on incoming interface */
7351a4822   Simon Wunderlich   batman-adv: split...
1517
  		batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
1518
  				      is_single_hop_neigh,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
1519
1520
  				      is_from_best_next_hop, if_incoming,
  				      if_outgoing);
fc9572756   Marek Lindner   batman-adv: agglo...
1521

39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1522
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1523
1524
  			   "Forwarding packet: rebroadcast neighbor packet with direct link flag
  ");
fc9572756   Marek Lindner   batman-adv: agglo...
1525
1526
1527
1528
  		goto out_neigh;
  	}
  
  	/* multihop originator */
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
1529
  	if (!is_bidirect) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1530
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1531
1532
  			   "Drop packet: not received via bidirectional link
  ");
fc9572756   Marek Lindner   batman-adv: agglo...
1533
1534
  		goto out_neigh;
  	}
7c24bbbea   Simon Wunderlich   batman-adv: forwa...
1535
  	if (dup_status == BATADV_NEIGH_DUP) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1536
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1537
1538
  			   "Drop packet: duplicate packet received
  ");
fc9572756   Marek Lindner   batman-adv: agglo...
1539
1540
  		goto out_neigh;
  	}
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
1541
  	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
1542
1543
  		   "Forwarding packet: rebroadcast originator packet
  ");
7351a4822   Simon Wunderlich   batman-adv: split...
1544
  	batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
1545
  			      is_single_hop_neigh, is_from_best_next_hop,
ef0a937f7   Simon Wunderlich   batman-adv: consi...
1546
  			      if_incoming, if_outgoing);
fc9572756   Marek Lindner   batman-adv: agglo...
1547
1548
1549
  
  out_neigh:
  	if ((orig_neigh_node) && (!is_single_hop_neigh))
5d9673109   Sven Eckelmann   batman-adv: Renam...
1550
  		batadv_orig_node_put(orig_neigh_node);
fc9572756   Marek Lindner   batman-adv: agglo...
1551
  out:
c1e517fbb   Simon Wunderlich   batman-adv: fix n...
1552
  	if (router_ifinfo)
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
1553
  		batadv_neigh_ifinfo_put(router_ifinfo);
fc9572756   Marek Lindner   batman-adv: agglo...
1554
  	if (router)
25bb25099   Sven Eckelmann   batman-adv: Renam...
1555
  		batadv_neigh_node_put(router);
fc9572756   Marek Lindner   batman-adv: agglo...
1556
  	if (router_router)
25bb25099   Sven Eckelmann   batman-adv: Renam...
1557
  		batadv_neigh_node_put(router_router);
fc9572756   Marek Lindner   batman-adv: agglo...
1558
  	if (orig_neigh_router)
25bb25099   Sven Eckelmann   batman-adv: Renam...
1559
  		batadv_neigh_node_put(orig_neigh_router);
4ff1e2a73   Marek Lindner   batman-adv: updat...
1560
  	if (hardif_neigh)
accadc35a   Sven Eckelmann   batman-adv: Renam...
1561
  		batadv_hardif_neigh_put(hardif_neigh);
fc9572756   Marek Lindner   batman-adv: agglo...
1562

bd687fe41   Sven Eckelmann   batman-adv: use c...
1563
  	consume_skb(skb_priv);
7351a4822   Simon Wunderlich   batman-adv: split...
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
  }
  
  /**
   * batadv_iv_ogm_process - process an incoming batman iv OGM
   * @skb: the skb containing the OGM
   * @ogm_offset: offset to the OGM which should be processed (for aggregates)
   * @if_incoming: the interface where this packet was receved
   */
  static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
  				  struct batadv_hard_iface *if_incoming)
  {
  	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
  	struct batadv_orig_node *orig_neigh_node, *orig_node;
  	struct batadv_hard_iface *hard_iface;
  	struct batadv_ogm_packet *ogm_packet;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1579
  	u32 if_incoming_seqno;
7351a4822   Simon Wunderlich   batman-adv: split...
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
  	bool has_directlink_flag;
  	struct ethhdr *ethhdr;
  	bool is_my_oldorig = false;
  	bool is_my_addr = false;
  	bool is_my_orig = false;
  
  	ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset);
  	ethhdr = eth_hdr(skb);
  
  	/* Silently drop when the batman packet is actually not a
  	 * correct packet.
  	 *
  	 * This might happen if a packet is padded (e.g. Ethernet has a
  	 * minimum frame length of 64 byte) and the aggregation interprets
  	 * it as an additional length.
  	 *
  	 * TODO: A more sane solution would be to have a bit in the
  	 * batadv_ogm_packet to detect whether the packet is the last
  	 * packet in an aggregation.  Here we expect that the padding
  	 * is always zero (or not 0x01)
  	 */
  	if (ogm_packet->packet_type != BATADV_IV_OGM)
  		return;
  
  	/* could be changed by schedule_own_packet() */
  	if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
  
  	if (ogm_packet->flags & BATADV_DIRECTLINK)
  		has_directlink_flag = true;
  	else
  		has_directlink_flag = false;
  
  	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
  		   "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)
  ",
  		   ethhdr->h_source, if_incoming->net_dev->name,
  		   if_incoming->net_dev->dev_addr, ogm_packet->orig,
  		   ogm_packet->prev_sender, ntohl(ogm_packet->seqno),
  		   ogm_packet->tq, ogm_packet->ttl,
  		   ogm_packet->version, has_directlink_flag);
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
  		if (hard_iface->if_status != BATADV_IF_ACTIVE)
  			continue;
  
  		if (hard_iface->soft_iface != if_incoming->soft_iface)
  			continue;
  
  		if (batadv_compare_eth(ethhdr->h_source,
  				       hard_iface->net_dev->dev_addr))
  			is_my_addr = true;
  
  		if (batadv_compare_eth(ogm_packet->orig,
  				       hard_iface->net_dev->dev_addr))
  			is_my_orig = true;
  
  		if (batadv_compare_eth(ogm_packet->prev_sender,
  				       hard_iface->net_dev->dev_addr))
  			is_my_oldorig = true;
  	}
  	rcu_read_unlock();
  
  	if (is_my_addr) {
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
  			   "Drop packet: received my own broadcast (sender: %pM)
  ",
  			   ethhdr->h_source);
  		return;
  	}
  
  	if (is_my_orig) {
  		unsigned long *word;
  		int offset;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1654
1655
1656
  		s32 bit_pos;
  		s16 if_num;
  		u8 *weight;
7351a4822   Simon Wunderlich   batman-adv: split...
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
  
  		orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
  							 ethhdr->h_source);
  		if (!orig_neigh_node)
  			return;
  
  		/* neighbor has to indicate direct link and it has to
  		 * come via the corresponding interface
  		 * save packet seqno for bidirectional check
  		 */
  		if (has_directlink_flag &&
  		    batadv_compare_eth(if_incoming->net_dev->dev_addr,
  				       ogm_packet->orig)) {
  			if_num = if_incoming->if_num;
  			offset = if_num * BATADV_NUM_WORDS;
  
  			spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
32db6aaaf   Antonio Quartulli   batman-adv: check...
1674
  			word = &orig_neigh_node->bat_iv.bcast_own[offset];
7351a4822   Simon Wunderlich   batman-adv: split...
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
  			bit_pos = if_incoming_seqno - 2;
  			bit_pos -= ntohl(ogm_packet->seqno);
  			batadv_set_bit(word, bit_pos);
  			weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num];
  			*weight = bitmap_weight(word,
  						BATADV_TQ_LOCAL_WINDOW_SIZE);
  			spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
  		}
  
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
  			   "Drop packet: originator packet from myself (via neighbor)
  ");
5d9673109   Sven Eckelmann   batman-adv: Renam...
1687
  		batadv_orig_node_put(orig_neigh_node);
7351a4822   Simon Wunderlich   batman-adv: split...
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
  		return;
  	}
  
  	if (is_my_oldorig) {
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
  			   "Drop packet: ignoring all rebroadcast echos (sender: %pM)
  ",
  			   ethhdr->h_source);
  		return;
  	}
  
  	if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
  			   "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)
  ",
  			   ethhdr->h_source);
  		return;
  	}
  
  	orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig);
  	if (!orig_node)
  		return;
  
  	batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
  					if_incoming, BATADV_IF_DEFAULT);
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
  		if (hard_iface->if_status != BATADV_IF_ACTIVE)
  			continue;
  
  		if (hard_iface->soft_iface != bat_priv->soft_iface)
  			continue;
273534468   Sven Eckelmann   batman-adv: Check...
1721
1722
  		if (!kref_get_unless_zero(&hard_iface->refcount))
  			continue;
7351a4822   Simon Wunderlich   batman-adv: split...
1723
1724
  		batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
  						if_incoming, hard_iface);
273534468   Sven Eckelmann   batman-adv: Check...
1725
1726
  
  		batadv_hardif_put(hard_iface);
7351a4822   Simon Wunderlich   batman-adv: split...
1727
1728
  	}
  	rcu_read_unlock();
5d9673109   Sven Eckelmann   batman-adv: Renam...
1729
  	batadv_orig_node_put(orig_node);
fc9572756   Marek Lindner   batman-adv: agglo...
1730
  }
f0d97253f   Antonio Quartulli   batman-adv: remov...
1731
1732
1733
1734
1735
  static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
  {
  	struct delayed_work *delayed_work;
  	struct batadv_forw_packet *forw_packet;
  	struct batadv_priv *bat_priv;
bd687fe41   Sven Eckelmann   batman-adv: use c...
1736
  	bool dropped = false;
f0d97253f   Antonio Quartulli   batman-adv: remov...
1737
1738
1739
1740
1741
  
  	delayed_work = to_delayed_work(work);
  	forw_packet = container_of(delayed_work, struct batadv_forw_packet,
  				   delayed_work);
  	bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
f0d97253f   Antonio Quartulli   batman-adv: remov...
1742

bd687fe41   Sven Eckelmann   batman-adv: use c...
1743
1744
  	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
  		dropped = true;
f0d97253f   Antonio Quartulli   batman-adv: remov...
1745
  		goto out;
bd687fe41   Sven Eckelmann   batman-adv: use c...
1746
  	}
f0d97253f   Antonio Quartulli   batman-adv: remov...
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
  
  	batadv_iv_ogm_emit(forw_packet);
  
  	/* we have to have at least one packet in the queue to determine the
  	 * queues wake up time unless we are shutting down.
  	 *
  	 * only re-schedule if this is the "original" copy, e.g. the OGM of the
  	 * primary interface should only be rescheduled once per period, but
  	 * this function will be called for the forw_packet instances of the
  	 * other secondary interfaces as well.
  	 */
  	if (forw_packet->own &&
  	    forw_packet->if_incoming == forw_packet->if_outgoing)
  		batadv_iv_ogm_schedule(forw_packet->if_incoming);
  
  out:
9b4aec647   Linus LĂĽssing   batman-adv: fix r...
1763
1764
1765
1766
  	/* do we get something for free()? */
  	if (batadv_forw_packet_steal(forw_packet,
  				     &bat_priv->forw_bat_list_lock))
  		batadv_forw_packet_free(forw_packet, dropped);
f0d97253f   Antonio Quartulli   batman-adv: remov...
1767
  }
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
1768
  static int batadv_iv_ogm_receive(struct sk_buff *skb,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1769
  				 struct batadv_hard_iface *if_incoming)
fc9572756   Marek Lindner   batman-adv: agglo...
1770
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1771
  	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
7351a4822   Simon Wunderlich   batman-adv: split...
1772
  	struct batadv_ogm_packet *ogm_packet;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1773
  	u8 *packet_pos;
7351a4822   Simon Wunderlich   batman-adv: split...
1774
  	int ogm_offset;
b91a2543b   Sven Eckelmann   batman-adv: Consu...
1775
1776
  	bool res;
  	int ret = NET_RX_DROP;
c3e29312c   Marek Lindner   batman-adv: regis...
1777

b91a2543b   Sven Eckelmann   batman-adv: Consu...
1778
1779
1780
  	res = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN);
  	if (!res)
  		goto free_skb;
fc9572756   Marek Lindner   batman-adv: agglo...
1781

edbf12ba5   Marek Lindner   batman-adv: ignor...
1782
1783
1784
  	/* did we receive a B.A.T.M.A.N. IV OGM packet on an interface
  	 * that does not have B.A.T.M.A.N. IV enabled ?
  	 */
29824a55c   Antonio Quartulli   batman-adv: split...
1785
  	if (bat_priv->algo_ops->iface.enable != batadv_iv_ogm_iface_enable)
b91a2543b   Sven Eckelmann   batman-adv: Consu...
1786
  		goto free_skb;
edbf12ba5   Marek Lindner   batman-adv: ignor...
1787

d69909d2f   Sven Eckelmann   batman-adv: Prefi...
1788
1789
  	batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
  	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
f8214865a   Martin Hundebøll   batman-adv: Add g...
1790
  			   skb->len + ETH_HLEN);
7351a4822   Simon Wunderlich   batman-adv: split...
1791
1792
  	ogm_offset = 0;
  	ogm_packet = (struct batadv_ogm_packet *)skb->data;
fc9572756   Marek Lindner   batman-adv: agglo...
1793
1794
  
  	/* unpack the aggregated packets and process them one by one */
7351a4822   Simon Wunderlich   batman-adv: split...
1795
1796
1797
  	while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
  					 ogm_packet->tvlv_len)) {
  		batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
fc9572756   Marek Lindner   batman-adv: agglo...
1798

7351a4822   Simon Wunderlich   batman-adv: split...
1799
1800
  		ogm_offset += BATADV_OGM_HLEN;
  		ogm_offset += ntohs(ogm_packet->tvlv_len);
fc9572756   Marek Lindner   batman-adv: agglo...
1801

7351a4822   Simon Wunderlich   batman-adv: split...
1802
1803
  		packet_pos = skb->data + ogm_offset;
  		ogm_packet = (struct batadv_ogm_packet *)packet_pos;
b47506d91   Marek Lindner   batman-adv: verif...
1804
  	}
c3e29312c   Marek Lindner   batman-adv: regis...
1805

b91a2543b   Sven Eckelmann   batman-adv: Consu...
1806
1807
1808
1809
1810
1811
1812
1813
1814
  	ret = NET_RX_SUCCESS;
  
  free_skb:
  	if (ret == NET_RX_SUCCESS)
  		consume_skb(skb);
  	else
  		kfree_skb(skb);
  
  	return ret;
fc9572756   Marek Lindner   batman-adv: agglo...
1815
  }
1c280471b   Marek Lindner   batman-adv: add i...
1816

dc1cbd145   Sven Eckelmann   batman-adv: Allow...
1817
  #ifdef CONFIG_BATMAN_ADV_DEBUGFS
1b371d130   Simon Wunderlich   batman-adv: use c...
1818
1819
  /**
   * batadv_iv_ogm_orig_print_neigh - print neighbors for the originator table
89652331c   Simon Wunderlich   batman-adv: split...
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
   * @orig_node: the orig_node for which the neighbors are printed
   * @if_outgoing: outgoing interface for these entries
   * @seq: debugfs table seq_file struct
   *
   * Must be called while holding an rcu lock.
   */
  static void
  batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node,
  			       struct batadv_hard_iface *if_outgoing,
  			       struct seq_file *seq)
  {
  	struct batadv_neigh_node *neigh_node;
  	struct batadv_neigh_ifinfo *n_ifinfo;
  
  	hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
  		n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
  		if (!n_ifinfo)
  			continue;
  
  		seq_printf(seq, " %pM (%3i)",
  			   neigh_node->addr,
  			   n_ifinfo->bat_iv.tq_avg);
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
1842
  		batadv_neigh_ifinfo_put(n_ifinfo);
89652331c   Simon Wunderlich   batman-adv: split...
1843
1844
  	}
  }
737a2a229   Antonio Quartulli   batman-adv: add b...
1845
1846
1847
1848
  /**
   * batadv_iv_ogm_orig_print - print the originator table
   * @bat_priv: the bat priv with all the soft interface information
   * @seq: debugfs table seq_file struct
cb1c92ec3   Simon Wunderlich   batman-adv: add d...
1849
   * @if_outgoing: the outgoing interface for which this should be printed
737a2a229   Antonio Quartulli   batman-adv: add b...
1850
1851
   */
  static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
cb1c92ec3   Simon Wunderlich   batman-adv: add d...
1852
1853
  				     struct seq_file *seq,
  				     struct batadv_hard_iface *if_outgoing)
737a2a229   Antonio Quartulli   batman-adv: add b...
1854
  {
89652331c   Simon Wunderlich   batman-adv: split...
1855
  	struct batadv_neigh_node *neigh_node;
737a2a229   Antonio Quartulli   batman-adv: add b...
1856
1857
1858
  	struct batadv_hashtable *hash = bat_priv->orig_hash;
  	int last_seen_msecs, last_seen_secs;
  	struct batadv_orig_node *orig_node;
89652331c   Simon Wunderlich   batman-adv: split...
1859
  	struct batadv_neigh_ifinfo *n_ifinfo;
737a2a229   Antonio Quartulli   batman-adv: add b...
1860
1861
1862
  	unsigned long last_seen_jiffies;
  	struct hlist_head *head;
  	int batman_count = 0;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1863
  	u32 i;
737a2a229   Antonio Quartulli   batman-adv: add b...
1864

925a6f379   Antonio Quartulli   batman-adv: use s...
1865
1866
1867
  	seq_puts(seq,
  		 "  Originator      last-seen (#/255)           Nexthop [outgoingIF]:   Potential nexthops ...
  ");
737a2a229   Antonio Quartulli   batman-adv: add b...
1868
1869
1870
1871
1872
1873
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  
  		rcu_read_lock();
  		hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
7351a4822   Simon Wunderlich   batman-adv: split...
1874
  			neigh_node = batadv_orig_router_get(orig_node,
cb1c92ec3   Simon Wunderlich   batman-adv: add d...
1875
  							    if_outgoing);
737a2a229   Antonio Quartulli   batman-adv: add b...
1876
1877
  			if (!neigh_node)
  				continue;
89652331c   Simon Wunderlich   batman-adv: split...
1878
  			n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
cb1c92ec3   Simon Wunderlich   batman-adv: add d...
1879
  							   if_outgoing);
89652331c   Simon Wunderlich   batman-adv: split...
1880
1881
1882
1883
  			if (!n_ifinfo)
  				goto next;
  
  			if (n_ifinfo->bat_iv.tq_avg == 0)
737a2a229   Antonio Quartulli   batman-adv: add b...
1884
1885
1886
1887
1888
1889
1890
1891
1892
  				goto next;
  
  			last_seen_jiffies = jiffies - orig_node->last_seen;
  			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
  			last_seen_secs = last_seen_msecs / 1000;
  			last_seen_msecs = last_seen_msecs % 1000;
  
  			seq_printf(seq, "%pM %4i.%03is   (%3i) %pM [%10s]:",
  				   orig_node->orig, last_seen_secs,
89652331c   Simon Wunderlich   batman-adv: split...
1893
  				   last_seen_msecs, n_ifinfo->bat_iv.tq_avg,
737a2a229   Antonio Quartulli   batman-adv: add b...
1894
1895
  				   neigh_node->addr,
  				   neigh_node->if_incoming->net_dev->name);
cb1c92ec3   Simon Wunderlich   batman-adv: add d...
1896
1897
  			batadv_iv_ogm_orig_print_neigh(orig_node, if_outgoing,
  						       seq);
626caae9f   Markus Elfring   batman-adv: Repla...
1898
1899
  			seq_putc(seq, '
  ');
737a2a229   Antonio Quartulli   batman-adv: add b...
1900
1901
1902
  			batman_count++;
  
  next:
25bb25099   Sven Eckelmann   batman-adv: Renam...
1903
  			batadv_neigh_node_put(neigh_node);
89652331c   Simon Wunderlich   batman-adv: split...
1904
  			if (n_ifinfo)
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
1905
  				batadv_neigh_ifinfo_put(n_ifinfo);
737a2a229   Antonio Quartulli   batman-adv: add b...
1906
1907
1908
1909
1910
1911
1912
1913
  		}
  		rcu_read_unlock();
  	}
  
  	if (batman_count == 0)
  		seq_puts(seq, "No batman nodes in range ...
  ");
  }
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
1914
  #endif
737a2a229   Antonio Quartulli   batman-adv: add b...
1915

a3285a8f2   Antonio Quartulli   batman-adv: add b...
1916
  /**
024f99cb4   Matthias Schiffer   batman-adv: add B...
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
   * batadv_iv_ogm_neigh_get_tq_avg - Get the TQ average for a neighbour on a
   *  given outgoing interface.
   * @neigh_node: Neighbour of interest
   * @if_outgoing: Outgoing interface of interest
   * @tq_avg: Pointer of where to store the TQ average
   *
   * Return: False if no average TQ available, otherwise true.
   */
  static bool
  batadv_iv_ogm_neigh_get_tq_avg(struct batadv_neigh_node *neigh_node,
  			       struct batadv_hard_iface *if_outgoing,
  			       u8 *tq_avg)
  {
  	struct batadv_neigh_ifinfo *n_ifinfo;
  
  	n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
  	if (!n_ifinfo)
  		return false;
  
  	*tq_avg = n_ifinfo->bat_iv.tq_avg;
  	batadv_neigh_ifinfo_put(n_ifinfo);
  
  	return true;
  }
  
  /**
   * batadv_iv_ogm_orig_dump_subentry - Dump an originator subentry into a
   *  message
   * @msg: Netlink message to dump into
   * @portid: Port making netlink request
   * @seq: Sequence number of netlink message
   * @bat_priv: The bat priv with all the soft interface information
   * @if_outgoing: Limit dump to entries with this outgoing interface
   * @orig_node: Originator to dump
   * @neigh_node: Single hops neighbour
   * @best: Is the best originator
   *
   * Return: Error code, or 0 on success
   */
  static int
  batadv_iv_ogm_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
  				 struct batadv_priv *bat_priv,
  				 struct batadv_hard_iface *if_outgoing,
  				 struct batadv_orig_node *orig_node,
  				 struct batadv_neigh_node *neigh_node,
  				 bool best)
  {
  	void *hdr;
  	u8 tq_avg;
  	unsigned int last_seen_msecs;
  
  	last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen);
  
  	if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node, if_outgoing, &tq_avg))
  		return 0;
  
  	if (if_outgoing != BATADV_IF_DEFAULT &&
  	    if_outgoing != neigh_node->if_incoming)
  		return 0;
  
  	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
  			  NLM_F_MULTI, BATADV_CMD_GET_ORIGINATORS);
  	if (!hdr)
  		return -ENOBUFS;
  
  	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
  		    orig_node->orig) ||
  	    nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
  		    neigh_node->addr) ||
  	    nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
  			neigh_node->if_incoming->net_dev->ifindex) ||
  	    nla_put_u8(msg, BATADV_ATTR_TQ, tq_avg) ||
  	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
  			last_seen_msecs))
  		goto nla_put_failure;
  
  	if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
  		goto nla_put_failure;
  
  	genlmsg_end(msg, hdr);
  	return 0;
  
   nla_put_failure:
  	genlmsg_cancel(msg, hdr);
  	return -EMSGSIZE;
  }
  
  /**
   * batadv_iv_ogm_orig_dump_entry - Dump an originator entry into a message
   * @msg: Netlink message to dump into
   * @portid: Port making netlink request
   * @seq: Sequence number of netlink message
   * @bat_priv: The bat priv with all the soft interface information
   * @if_outgoing: Limit dump to entries with this outgoing interface
   * @orig_node: Originator to dump
   * @sub_s: Number of sub entries to skip
   *
   * This function assumes the caller holds rcu_read_lock().
   *
   * Return: Error code, or 0 on success
   */
  static int
  batadv_iv_ogm_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
  			      struct batadv_priv *bat_priv,
  			      struct batadv_hard_iface *if_outgoing,
  			      struct batadv_orig_node *orig_node, int *sub_s)
  {
  	struct batadv_neigh_node *neigh_node_best;
  	struct batadv_neigh_node *neigh_node;
  	int sub = 0;
  	bool best;
  	u8 tq_avg_best;
  
  	neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing);
  	if (!neigh_node_best)
  		goto out;
  
  	if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node_best, if_outgoing,
  					    &tq_avg_best))
  		goto out;
  
  	if (tq_avg_best == 0)
  		goto out;
  
  	hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
  		if (sub++ < *sub_s)
  			continue;
  
  		best = (neigh_node == neigh_node_best);
  
  		if (batadv_iv_ogm_orig_dump_subentry(msg, portid, seq,
  						     bat_priv, if_outgoing,
  						     orig_node, neigh_node,
  						     best)) {
  			batadv_neigh_node_put(neigh_node_best);
  
  			*sub_s = sub - 1;
  			return -EMSGSIZE;
  		}
  	}
  
   out:
  	if (neigh_node_best)
  		batadv_neigh_node_put(neigh_node_best);
  
  	*sub_s = 0;
  	return 0;
  }
  
  /**
   * batadv_iv_ogm_orig_dump_bucket - Dump an originator bucket into a
   *  message
   * @msg: Netlink message to dump into
   * @portid: Port making netlink request
   * @seq: Sequence number of netlink message
   * @bat_priv: The bat priv with all the soft interface information
   * @if_outgoing: Limit dump to entries with this outgoing interface
   * @head: Bucket to be dumped
   * @idx_s: Number of entries to be skipped
   * @sub: Number of sub entries to be skipped
   *
   * Return: Error code, or 0 on success
   */
  static int
  batadv_iv_ogm_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
  			       struct batadv_priv *bat_priv,
  			       struct batadv_hard_iface *if_outgoing,
  			       struct hlist_head *head, int *idx_s, int *sub)
  {
  	struct batadv_orig_node *orig_node;
  	int idx = 0;
  
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
  		if (idx++ < *idx_s)
  			continue;
  
  		if (batadv_iv_ogm_orig_dump_entry(msg, portid, seq, bat_priv,
  						  if_outgoing, orig_node,
  						  sub)) {
  			rcu_read_unlock();
  			*idx_s = idx - 1;
  			return -EMSGSIZE;
  		}
  	}
  	rcu_read_unlock();
  
  	*idx_s = 0;
  	*sub = 0;
  	return 0;
  }
  
  /**
   * batadv_iv_ogm_orig_dump - Dump the originators into a message
   * @msg: Netlink message to dump into
   * @cb: Control block containing additional options
   * @bat_priv: The bat priv with all the soft interface information
   * @if_outgoing: Limit dump to entries with this outgoing interface
   */
  static void
  batadv_iv_ogm_orig_dump(struct sk_buff *msg, struct netlink_callback *cb,
  			struct batadv_priv *bat_priv,
  			struct batadv_hard_iface *if_outgoing)
  {
  	struct batadv_hashtable *hash = bat_priv->orig_hash;
  	struct hlist_head *head;
  	int bucket = cb->args[0];
  	int idx = cb->args[1];
  	int sub = cb->args[2];
  	int portid = NETLINK_CB(cb->skb).portid;
  
  	while (bucket < hash->size) {
  		head = &hash->table[bucket];
  
  		if (batadv_iv_ogm_orig_dump_bucket(msg, portid,
  						   cb->nlh->nlmsg_seq,
  						   bat_priv, if_outgoing, head,
  						   &idx, &sub))
  			break;
  
  		bucket++;
  	}
  
  	cb->args[0] = bucket;
  	cb->args[1] = idx;
  	cb->args[2] = sub;
  }
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2144
  #ifdef CONFIG_BATMAN_ADV_DEBUGFS
024f99cb4   Matthias Schiffer   batman-adv: add B...
2145
  /**
7587405ab   Marek Lindner   batman-adv: expor...
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
   * batadv_iv_hardif_neigh_print - print a single hop neighbour node
   * @seq: neighbour table seq_file struct
   * @hardif_neigh: hardif neighbour information
   */
  static void
  batadv_iv_hardif_neigh_print(struct seq_file *seq,
  			     struct batadv_hardif_neigh_node *hardif_neigh)
  {
  	int last_secs, last_msecs;
  
  	last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000;
  	last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000;
  
  	seq_printf(seq, "   %10s   %pM %4i.%03is
  ",
  		   hardif_neigh->if_incoming->net_dev->name,
  		   hardif_neigh->addr, last_secs, last_msecs);
  }
  
  /**
   * batadv_iv_ogm_neigh_print - print the single hop neighbour list
   * @bat_priv: the bat priv with all the soft interface information
   * @seq: neighbour table seq_file struct
   */
  static void batadv_iv_neigh_print(struct batadv_priv *bat_priv,
  				  struct seq_file *seq)
  {
  	struct net_device *net_dev = (struct net_device *)seq->private;
  	struct batadv_hardif_neigh_node *hardif_neigh;
  	struct batadv_hard_iface *hard_iface;
  	int batman_count = 0;
925a6f379   Antonio Quartulli   batman-adv: use s...
2177
2178
  	seq_puts(seq, "           IF        Neighbor      last-seen
  ");
7587405ab   Marek Lindner   batman-adv: expor...
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
  		if (hard_iface->soft_iface != net_dev)
  			continue;
  
  		hlist_for_each_entry_rcu(hardif_neigh,
  					 &hard_iface->neigh_list, list) {
  			batadv_iv_hardif_neigh_print(seq, hardif_neigh);
  			batman_count++;
  		}
  	}
  	rcu_read_unlock();
  
  	if (batman_count == 0)
  		seq_puts(seq, "No batman nodes in range ...
  ");
  }
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2197
  #endif
7587405ab   Marek Lindner   batman-adv: expor...
2198
2199
  
  /**
57b125029   Markus Pargmann   batman-adv: iv_og...
2200
   * batadv_iv_ogm_neigh_diff - calculate tq difference of two neighbors
a3285a8f2   Antonio Quartulli   batman-adv: add b...
2201
   * @neigh1: the first neighbor object of the comparison
89652331c   Simon Wunderlich   batman-adv: split...
2202
   * @if_outgoing1: outgoing interface for the first neighbor
a3285a8f2   Antonio Quartulli   batman-adv: add b...
2203
   * @neigh2: the second neighbor object of the comparison
89652331c   Simon Wunderlich   batman-adv: split...
2204
   * @if_outgoing2: outgoing interface for the second neighbor
57b125029   Markus Pargmann   batman-adv: iv_og...
2205
   * @diff: pointer to integer receiving the calculated difference
a3285a8f2   Antonio Quartulli   batman-adv: add b...
2206
   *
57b125029   Markus Pargmann   batman-adv: iv_og...
2207
2208
2209
2210
2211
   * The content of *@diff is only valid when this function returns true.
   * It is less, equal to or greater than 0 if the metric via neigh1 is lower,
   * the same as or higher than the metric via neigh2
   *
   * Return: true when the difference could be calculated, false otherwise
a3285a8f2   Antonio Quartulli   batman-adv: add b...
2212
   */
57b125029   Markus Pargmann   batman-adv: iv_og...
2213
2214
2215
2216
2217
  static bool batadv_iv_ogm_neigh_diff(struct batadv_neigh_node *neigh1,
  				     struct batadv_hard_iface *if_outgoing1,
  				     struct batadv_neigh_node *neigh2,
  				     struct batadv_hard_iface *if_outgoing2,
  				     int *diff)
a3285a8f2   Antonio Quartulli   batman-adv: add b...
2218
  {
89652331c   Simon Wunderlich   batman-adv: split...
2219
  	struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
2220
  	u8 tq1, tq2;
57b125029   Markus Pargmann   batman-adv: iv_og...
2221
  	bool ret = true;
89652331c   Simon Wunderlich   batman-adv: split...
2222
2223
2224
  
  	neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
  	neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
a3285a8f2   Antonio Quartulli   batman-adv: add b...
2225

89652331c   Simon Wunderlich   batman-adv: split...
2226
  	if (!neigh1_ifinfo || !neigh2_ifinfo) {
57b125029   Markus Pargmann   batman-adv: iv_og...
2227
  		ret = false;
89652331c   Simon Wunderlich   batman-adv: split...
2228
2229
  		goto out;
  	}
a3285a8f2   Antonio Quartulli   batman-adv: add b...
2230

89652331c   Simon Wunderlich   batman-adv: split...
2231
2232
  	tq1 = neigh1_ifinfo->bat_iv.tq_avg;
  	tq2 = neigh2_ifinfo->bat_iv.tq_avg;
57b125029   Markus Pargmann   batman-adv: iv_og...
2233
  	*diff = (int)tq1 - (int)tq2;
89652331c   Simon Wunderlich   batman-adv: split...
2234
2235
2236
  
  out:
  	if (neigh1_ifinfo)
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
2237
  		batadv_neigh_ifinfo_put(neigh1_ifinfo);
89652331c   Simon Wunderlich   batman-adv: split...
2238
  	if (neigh2_ifinfo)
044fa3ae1   Sven Eckelmann   batman-adv: Renam...
2239
  		batadv_neigh_ifinfo_put(neigh2_ifinfo);
89652331c   Simon Wunderlich   batman-adv: split...
2240

57b125029   Markus Pargmann   batman-adv: iv_og...
2241
2242
2243
2244
  	return ret;
  }
  
  /**
024f99cb4   Matthias Schiffer   batman-adv: add B...
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
   * batadv_iv_ogm_neigh_dump_neigh - Dump a neighbour into a netlink message
   * @msg: Netlink message to dump into
   * @portid: Port making netlink request
   * @seq: Sequence number of netlink message
   * @hardif_neigh: Neighbour to be dumped
   *
   * Return: Error code, or 0 on success
   */
  static int
  batadv_iv_ogm_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
  			       struct batadv_hardif_neigh_node *hardif_neigh)
  {
  	void *hdr;
  	unsigned int last_seen_msecs;
  
  	last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen);
  
  	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
  			  NLM_F_MULTI, BATADV_CMD_GET_NEIGHBORS);
  	if (!hdr)
  		return -ENOBUFS;
  
  	if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
  		    hardif_neigh->addr) ||
  	    nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
  			hardif_neigh->if_incoming->net_dev->ifindex) ||
  	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
  			last_seen_msecs))
  		goto nla_put_failure;
  
  	genlmsg_end(msg, hdr);
  	return 0;
  
   nla_put_failure:
  	genlmsg_cancel(msg, hdr);
  	return -EMSGSIZE;
  }
  
  /**
   * batadv_iv_ogm_neigh_dump_hardif - Dump the neighbours of a hard interface
   *  into a message
   * @msg: Netlink message to dump into
   * @portid: Port making netlink request
   * @seq: Sequence number of netlink message
   * @bat_priv: The bat priv with all the soft interface information
   * @hard_iface: Hard interface to dump the neighbours for
   * @idx_s: Number of entries to skip
   *
   * This function assumes the caller holds rcu_read_lock().
   *
   * Return: Error code, or 0 on success
   */
  static int
  batadv_iv_ogm_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
  				struct batadv_priv *bat_priv,
  				struct batadv_hard_iface *hard_iface,
  				int *idx_s)
  {
  	struct batadv_hardif_neigh_node *hardif_neigh;
  	int idx = 0;
  
  	hlist_for_each_entry_rcu(hardif_neigh,
  				 &hard_iface->neigh_list, list) {
  		if (idx++ < *idx_s)
  			continue;
  
  		if (batadv_iv_ogm_neigh_dump_neigh(msg, portid, seq,
  						   hardif_neigh)) {
  			*idx_s = idx - 1;
  			return -EMSGSIZE;
  		}
  	}
  
  	*idx_s = 0;
  	return 0;
  }
  
  /**
   * batadv_iv_ogm_neigh_dump - Dump the neighbours into a message
   * @msg: Netlink message to dump into
   * @cb: Control block containing additional options
   * @bat_priv: The bat priv with all the soft interface information
   * @single_hardif: Limit dump to this hard interfaace
   */
  static void
  batadv_iv_ogm_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb,
  			 struct batadv_priv *bat_priv,
  			 struct batadv_hard_iface *single_hardif)
  {
  	struct batadv_hard_iface *hard_iface;
  	int i_hardif = 0;
  	int i_hardif_s = cb->args[0];
  	int idx = cb->args[1];
  	int portid = NETLINK_CB(cb->skb).portid;
  
  	rcu_read_lock();
  	if (single_hardif) {
  		if (i_hardif_s == 0) {
  			if (batadv_iv_ogm_neigh_dump_hardif(msg, portid,
  							    cb->nlh->nlmsg_seq,
  							    bat_priv,
  							    single_hardif,
  							    &idx) == 0)
  				i_hardif++;
  		}
  	} else {
  		list_for_each_entry_rcu(hard_iface, &batadv_hardif_list,
  					list) {
  			if (hard_iface->soft_iface != bat_priv->soft_iface)
  				continue;
  
  			if (i_hardif++ < i_hardif_s)
  				continue;
  
  			if (batadv_iv_ogm_neigh_dump_hardif(msg, portid,
  							    cb->nlh->nlmsg_seq,
  							    bat_priv,
  							    hard_iface, &idx)) {
  				i_hardif--;
  				break;
  			}
  		}
  	}
  	rcu_read_unlock();
  
  	cb->args[0] = i_hardif;
  	cb->args[1] = idx;
  }
  
  /**
57b125029   Markus Pargmann   batman-adv: iv_og...
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
   * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors
   * @neigh1: the first neighbor object of the comparison
   * @if_outgoing1: outgoing interface for the first neighbor
   * @neigh2: the second neighbor object of the comparison
   * @if_outgoing2: outgoing interface for the second neighbor
   *
   * Return: a value less, equal to or greater than 0 if the metric via neigh1 is
   * lower, the same as or higher than the metric via neigh2
   */
  static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
  				   struct batadv_hard_iface *if_outgoing1,
  				   struct batadv_neigh_node *neigh2,
  				   struct batadv_hard_iface *if_outgoing2)
  {
  	bool ret;
  	int diff;
  
  	ret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2,
  				       if_outgoing2, &diff);
  	if (!ret)
  		return 0;
89652331c   Simon Wunderlich   batman-adv: split...
2396
  	return diff;
a3285a8f2   Antonio Quartulli   batman-adv: add b...
2397
  }
c43c981e5   Antonio Quartulli   batman-adv: add b...
2398
  /**
18165f6f6   Simon Wunderlich   batman-adv: renam...
2399
2400
   * batadv_iv_ogm_neigh_is_sob - check if neigh1 is similarly good or better
   *  than neigh2 from the metric prospective
c43c981e5   Antonio Quartulli   batman-adv: add b...
2401
   * @neigh1: the first neighbor object of the comparison
95298a91f   Martin Hundebøll   batman-adv: kerne...
2402
   * @if_outgoing1: outgoing interface for the first neighbor
c43c981e5   Antonio Quartulli   batman-adv: add b...
2403
   * @neigh2: the second neighbor object of the comparison
89652331c   Simon Wunderlich   batman-adv: split...
2404
   * @if_outgoing2: outgoing interface for the second neighbor
95298a91f   Martin Hundebøll   batman-adv: kerne...
2405
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
2406
   * Return: true if the metric via neigh1 is equally good or better than
89652331c   Simon Wunderlich   batman-adv: split...
2407
   * the metric via neigh2, false otherwise.
c43c981e5   Antonio Quartulli   batman-adv: add b...
2408
   */
89652331c   Simon Wunderlich   batman-adv: split...
2409
  static bool
18165f6f6   Simon Wunderlich   batman-adv: renam...
2410
  batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
89652331c   Simon Wunderlich   batman-adv: split...
2411
2412
2413
  			   struct batadv_hard_iface *if_outgoing1,
  			   struct batadv_neigh_node *neigh2,
  			   struct batadv_hard_iface *if_outgoing2)
c43c981e5   Antonio Quartulli   batman-adv: add b...
2414
  {
89652331c   Simon Wunderlich   batman-adv: split...
2415
  	bool ret;
57b125029   Markus Pargmann   batman-adv: iv_og...
2416
  	int diff;
c43c981e5   Antonio Quartulli   batman-adv: add b...
2417

57b125029   Markus Pargmann   batman-adv: iv_og...
2418
2419
2420
2421
  	ret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2,
  				       if_outgoing2, &diff);
  	if (!ret)
  		return false;
89652331c   Simon Wunderlich   batman-adv: split...
2422

57b125029   Markus Pargmann   batman-adv: iv_og...
2423
  	ret = diff > -BATADV_TQ_SIMILARITY_THRESHOLD;
89652331c   Simon Wunderlich   batman-adv: split...
2424
  	return ret;
c43c981e5   Antonio Quartulli   batman-adv: add b...
2425
  }
f0d97253f   Antonio Quartulli   batman-adv: remov...
2426
2427
2428
2429
2430
  static void batadv_iv_iface_activate(struct batadv_hard_iface *hard_iface)
  {
  	/* begin scheduling originator messages on that interface */
  	batadv_iv_ogm_schedule(hard_iface);
  }
1a9070ec9   Sven Eckelmann   batman-adv: Initi...
2431
2432
2433
2434
2435
2436
2437
2438
2439
  /**
   * batadv_iv_init_sel_class - initialize GW selection class
   * @bat_priv: the bat priv with all the soft interface information
   */
  static void batadv_iv_init_sel_class(struct batadv_priv *bat_priv)
  {
  	/* set default TQ difference threshold to 20 */
  	atomic_set(&bat_priv->gw.sel_class, 20);
  }
34d99cfef   Antonio Quartulli   batman-adv: make ...
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
  static struct batadv_gw_node *
  batadv_iv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
  {
  	struct batadv_neigh_node *router;
  	struct batadv_neigh_ifinfo *router_ifinfo;
  	struct batadv_gw_node *gw_node, *curr_gw = NULL;
  	u64 max_gw_factor = 0;
  	u64 tmp_gw_factor = 0;
  	u8 max_tq = 0;
  	u8 tq_avg;
  	struct batadv_orig_node *orig_node;
  
  	rcu_read_lock();
70ea5cee9   Sven Eckelmann   batman-adv: Use p...
2453
  	hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
34d99cfef   Antonio Quartulli   batman-adv: make ...
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
  		orig_node = gw_node->orig_node;
  		router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
  		if (!router)
  			continue;
  
  		router_ifinfo = batadv_neigh_ifinfo_get(router,
  							BATADV_IF_DEFAULT);
  		if (!router_ifinfo)
  			goto next;
  
  		if (!kref_get_unless_zero(&gw_node->refcount))
  			goto next;
  
  		tq_avg = router_ifinfo->bat_iv.tq_avg;
  
  		switch (atomic_read(&bat_priv->gw.sel_class)) {
  		case 1: /* fast connection */
  			tmp_gw_factor = tq_avg * tq_avg;
  			tmp_gw_factor *= gw_node->bandwidth_down;
  			tmp_gw_factor *= 100 * 100;
  			tmp_gw_factor >>= 18;
  
  			if ((tmp_gw_factor > max_gw_factor) ||
  			    ((tmp_gw_factor == max_gw_factor) &&
  			     (tq_avg > max_tq))) {
  				if (curr_gw)
  					batadv_gw_node_put(curr_gw);
  				curr_gw = gw_node;
  				kref_get(&curr_gw->refcount);
  			}
  			break;
  
  		default: /* 2:  stable connection (use best statistic)
  			  * 3:  fast-switch (use best statistic but change as
  			  *     soon as a better gateway appears)
  			  * XX: late-switch (use best statistic but change as
  			  *     soon as a better gateway appears which has
  			  *     $routing_class more tq points)
  			  */
  			if (tq_avg > max_tq) {
  				if (curr_gw)
  					batadv_gw_node_put(curr_gw);
  				curr_gw = gw_node;
  				kref_get(&curr_gw->refcount);
  			}
  			break;
  		}
  
  		if (tq_avg > max_tq)
  			max_tq = tq_avg;
  
  		if (tmp_gw_factor > max_gw_factor)
  			max_gw_factor = tmp_gw_factor;
  
  		batadv_gw_node_put(gw_node);
  
  next:
  		batadv_neigh_node_put(router);
  		if (router_ifinfo)
  			batadv_neigh_ifinfo_put(router_ifinfo);
  	}
  	rcu_read_unlock();
  
  	return curr_gw;
  }
  
  static bool batadv_iv_gw_is_eligible(struct batadv_priv *bat_priv,
  				     struct batadv_orig_node *curr_gw_orig,
  				     struct batadv_orig_node *orig_node)
  {
  	struct batadv_neigh_ifinfo *router_orig_ifinfo = NULL;
  	struct batadv_neigh_ifinfo *router_gw_ifinfo = NULL;
  	struct batadv_neigh_node *router_gw = NULL;
  	struct batadv_neigh_node *router_orig = NULL;
  	u8 gw_tq_avg, orig_tq_avg;
  	bool ret = false;
  
  	/* dynamic re-election is performed only on fast or late switch */
  	if (atomic_read(&bat_priv->gw.sel_class) <= 2)
  		return false;
  
  	router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT);
  	if (!router_gw) {
  		ret = true;
  		goto out;
  	}
  
  	router_gw_ifinfo = batadv_neigh_ifinfo_get(router_gw,
  						   BATADV_IF_DEFAULT);
  	if (!router_gw_ifinfo) {
  		ret = true;
  		goto out;
  	}
  
  	router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
  	if (!router_orig)
  		goto out;
  
  	router_orig_ifinfo = batadv_neigh_ifinfo_get(router_orig,
  						     BATADV_IF_DEFAULT);
  	if (!router_orig_ifinfo)
  		goto out;
  
  	gw_tq_avg = router_gw_ifinfo->bat_iv.tq_avg;
  	orig_tq_avg = router_orig_ifinfo->bat_iv.tq_avg;
  
  	/* the TQ value has to be better */
  	if (orig_tq_avg < gw_tq_avg)
  		goto out;
  
  	/* if the routing class is greater than 3 the value tells us how much
  	 * greater the TQ value of the new gateway must be
  	 */
  	if ((atomic_read(&bat_priv->gw.sel_class) > 3) &&
  	    (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw.sel_class)))
  		goto out;
  
  	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
  		   "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)
  ",
  		   gw_tq_avg, orig_tq_avg);
  
  	ret = true;
  out:
  	if (router_gw_ifinfo)
  		batadv_neigh_ifinfo_put(router_gw_ifinfo);
  	if (router_orig_ifinfo)
  		batadv_neigh_ifinfo_put(router_orig_ifinfo);
  	if (router_gw)
  		batadv_neigh_node_put(router_gw);
  	if (router_orig)
  		batadv_neigh_node_put(router_orig);
  
  	return ret;
  }
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2589
  #ifdef CONFIG_BATMAN_ADV_DEBUGFS
34d99cfef   Antonio Quartulli   batman-adv: make ...
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
  /* fails if orig_node has no router */
  static int batadv_iv_gw_write_buffer_text(struct batadv_priv *bat_priv,
  					  struct seq_file *seq,
  					  const struct batadv_gw_node *gw_node)
  {
  	struct batadv_gw_node *curr_gw;
  	struct batadv_neigh_node *router;
  	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
  	int ret = -1;
  
  	router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
  	if (!router)
  		goto out;
  
  	router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
  	if (!router_ifinfo)
  		goto out;
  
  	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
  
  	seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit
  ",
  		   (curr_gw == gw_node ? "=>" : "  "),
  		   gw_node->orig_node->orig,
  		   router_ifinfo->bat_iv.tq_avg, router->addr,
  		   router->if_incoming->net_dev->name,
  		   gw_node->bandwidth_down / 10,
  		   gw_node->bandwidth_down % 10,
  		   gw_node->bandwidth_up / 10,
  		   gw_node->bandwidth_up % 10);
  	ret = seq_has_overflowed(seq) ? -1 : 0;
  
  	if (curr_gw)
  		batadv_gw_node_put(curr_gw);
  out:
  	if (router_ifinfo)
  		batadv_neigh_ifinfo_put(router_ifinfo);
  	if (router)
  		batadv_neigh_node_put(router);
  	return ret;
  }
  
  static void batadv_iv_gw_print(struct batadv_priv *bat_priv,
  			       struct seq_file *seq)
  {
  	struct batadv_gw_node *gw_node;
  	int gw_count = 0;
  
  	seq_puts(seq,
  		 "      Gateway      (#/255)           Nexthop [outgoingIF]: advertised uplink bandwidth
  ");
  
  	rcu_read_lock();
70ea5cee9   Sven Eckelmann   batman-adv: Use p...
2643
  	hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
34d99cfef   Antonio Quartulli   batman-adv: make ...
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
  		/* fails if orig_node has no router */
  		if (batadv_iv_gw_write_buffer_text(bat_priv, seq, gw_node) < 0)
  			continue;
  
  		gw_count++;
  	}
  	rcu_read_unlock();
  
  	if (gw_count == 0)
  		seq_puts(seq, "No gateways in range ...
  ");
  }
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2656
  #endif
34d99cfef   Antonio Quartulli   batman-adv: make ...
2657

efb766af0   Andrew Lunn   batman-adv: add B...
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
  /**
   * batadv_iv_gw_dump_entry - Dump a gateway into a message
   * @msg: Netlink message to dump into
   * @portid: Port making netlink request
   * @seq: Sequence number of netlink message
   * @bat_priv: The bat priv with all the soft interface information
   * @gw_node: Gateway to be dumped
   *
   * Return: Error code, or 0 on success
   */
  static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
  				   struct batadv_priv *bat_priv,
  				   struct batadv_gw_node *gw_node)
  {
  	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
  	struct batadv_neigh_node *router;
cc210a039   Sven Eckelmann   batman-adv: Fix b...
2674
  	struct batadv_gw_node *curr_gw = NULL;
8b7e379fa   Sven Eckelmann   batman-adv: Ignor...
2675
  	int ret = 0;
efb766af0   Andrew Lunn   batman-adv: add B...
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
  	void *hdr;
  
  	router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
  	if (!router)
  		goto out;
  
  	router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
  	if (!router_ifinfo)
  		goto out;
  
  	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
  
  	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
  			  NLM_F_MULTI, BATADV_CMD_GET_GATEWAYS);
  	if (!hdr) {
  		ret = -ENOBUFS;
  		goto out;
  	}
  
  	ret = -EMSGSIZE;
  
  	if (curr_gw == gw_node)
  		if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) {
  			genlmsg_cancel(msg, hdr);
  			goto out;
  		}
  
  	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
  		    gw_node->orig_node->orig) ||
  	    nla_put_u8(msg, BATADV_ATTR_TQ, router_ifinfo->bat_iv.tq_avg) ||
  	    nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN,
  		    router->addr) ||
  	    nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
  			   router->if_incoming->net_dev->name) ||
  	    nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
  			gw_node->bandwidth_down) ||
  	    nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP,
  			gw_node->bandwidth_up)) {
  		genlmsg_cancel(msg, hdr);
  		goto out;
  	}
  
  	genlmsg_end(msg, hdr);
  	ret = 0;
  
  out:
cc210a039   Sven Eckelmann   batman-adv: Fix b...
2722
2723
  	if (curr_gw)
  		batadv_gw_node_put(curr_gw);
efb766af0   Andrew Lunn   batman-adv: add B...
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
  	if (router_ifinfo)
  		batadv_neigh_ifinfo_put(router_ifinfo);
  	if (router)
  		batadv_neigh_node_put(router);
  	return ret;
  }
  
  /**
   * batadv_iv_gw_dump - Dump gateways into a message
   * @msg: Netlink message to dump into
   * @cb: Control block containing additional options
   * @bat_priv: The bat priv with all the soft interface information
   */
  static void batadv_iv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
  			      struct batadv_priv *bat_priv)
  {
  	int portid = NETLINK_CB(cb->skb).portid;
  	struct batadv_gw_node *gw_node;
  	int idx_skip = cb->args[0];
  	int idx = 0;
  
  	rcu_read_lock();
70ea5cee9   Sven Eckelmann   batman-adv: Use p...
2746
  	hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
efb766af0   Andrew Lunn   batman-adv: add B...
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
  		if (idx++ < idx_skip)
  			continue;
  
  		if (batadv_iv_gw_dump_entry(msg, portid, cb->nlh->nlmsg_seq,
  					    bat_priv, gw_node)) {
  			idx_skip = idx - 1;
  			goto unlock;
  		}
  	}
  
  	idx_skip = idx;
  unlock:
  	rcu_read_unlock();
  
  	cb->args[0] = idx_skip;
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
2763
  static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
519d3497c   Marek Lindner   batman-adv: avoid...
2764
  	.name = "BATMAN_IV",
29824a55c   Antonio Quartulli   batman-adv: split...
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
  	.iface = {
  		.activate = batadv_iv_iface_activate,
  		.enable = batadv_iv_ogm_iface_enable,
  		.disable = batadv_iv_ogm_iface_disable,
  		.update_mac = batadv_iv_ogm_iface_update_mac,
  		.primary_set = batadv_iv_ogm_primary_iface_set,
  	},
  	.neigh = {
  		.cmp = batadv_iv_ogm_neigh_cmp,
  		.is_similar_or_better = batadv_iv_ogm_neigh_is_sob,
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2775
  #ifdef CONFIG_BATMAN_ADV_DEBUGFS
29824a55c   Antonio Quartulli   batman-adv: split...
2776
  		.print = batadv_iv_neigh_print,
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2777
  #endif
024f99cb4   Matthias Schiffer   batman-adv: add B...
2778
  		.dump = batadv_iv_ogm_neigh_dump,
29824a55c   Antonio Quartulli   batman-adv: split...
2779
2780
  	},
  	.orig = {
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2781
  #ifdef CONFIG_BATMAN_ADV_DEBUGFS
29824a55c   Antonio Quartulli   batman-adv: split...
2782
  		.print = batadv_iv_ogm_orig_print,
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2783
  #endif
024f99cb4   Matthias Schiffer   batman-adv: add B...
2784
  		.dump = batadv_iv_ogm_orig_dump,
29824a55c   Antonio Quartulli   batman-adv: split...
2785
2786
2787
2788
  		.free = batadv_iv_ogm_orig_free,
  		.add_if = batadv_iv_ogm_orig_add_if,
  		.del_if = batadv_iv_ogm_orig_del_if,
  	},
34d99cfef   Antonio Quartulli   batman-adv: make ...
2789
  	.gw = {
1a9070ec9   Sven Eckelmann   batman-adv: Initi...
2790
  		.init_sel_class = batadv_iv_init_sel_class,
34d99cfef   Antonio Quartulli   batman-adv: make ...
2791
2792
  		.get_best_gw_node = batadv_iv_gw_get_best_gw_node,
  		.is_eligible = batadv_iv_gw_is_eligible,
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2793
  #ifdef CONFIG_BATMAN_ADV_DEBUGFS
34d99cfef   Antonio Quartulli   batman-adv: make ...
2794
  		.print = batadv_iv_gw_print,
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
2795
  #endif
efb766af0   Andrew Lunn   batman-adv: add B...
2796
  		.dump = batadv_iv_gw_dump,
34d99cfef   Antonio Quartulli   batman-adv: make ...
2797
  	},
1c280471b   Marek Lindner   batman-adv: add i...
2798
  };
81c524f76   Sven Eckelmann   batman-adv: Prefi...
2799
  int __init batadv_iv_init(void)
1c280471b   Marek Lindner   batman-adv: add i...
2800
  {
c3e29312c   Marek Lindner   batman-adv: regis...
2801
2802
2803
  	int ret;
  
  	/* batman originator packet */
acd34afa8   Sven Eckelmann   batman-adv: Prefi...
2804
2805
  	ret = batadv_recv_handler_register(BATADV_IV_OGM,
  					   batadv_iv_ogm_receive);
c3e29312c   Marek Lindner   batman-adv: regis...
2806
2807
  	if (ret < 0)
  		goto out;
fe8bc3969   Sven Eckelmann   batman-adv: Prefi...
2808
  	ret = batadv_algo_register(&batadv_batman_iv);
c3e29312c   Marek Lindner   batman-adv: regis...
2809
2810
2811
2812
2813
2814
  	if (ret < 0)
  		goto handler_unregister;
  
  	goto out;
  
  handler_unregister:
acd34afa8   Sven Eckelmann   batman-adv: Prefi...
2815
  	batadv_recv_handler_unregister(BATADV_IV_OGM);
c3e29312c   Marek Lindner   batman-adv: regis...
2816
2817
  out:
  	return ret;
1c280471b   Marek Lindner   batman-adv: add i...
2818
  }