Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/batman-adv/bat_iv_ogm.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/* Copyright (C) B.A.T.M.A.N. contributors:
3
*
4
* Marek Lindner, Simon Wunderlich
5
*/
6
7
#include "bat_iv_ogm.h"
8
#include "main.h"
9
10
#include <linux/atomic.h>
11
#include <linux/bitmap.h>
12
#include <linux/bitops.h>
13
#include <linux/bug.h>
14
#include <linux/byteorder/generic.h>
15
#include <linux/cache.h>
16
#include <linux/container_of.h>
17
#include <linux/errno.h>
18
#include <linux/etherdevice.h>
19
#include <linux/gfp.h>
20
#include <linux/if_ether.h>
21
#include <linux/init.h>
22
#include <linux/jiffies.h>
23
#include <linux/kref.h>
24
#include <linux/list.h>
25
#include <linux/lockdep.h>
26
#include <linux/minmax.h>
27
#include <linux/mutex.h>
28
#include <linux/netdevice.h>
29
#include <linux/netlink.h>
30
#include <linux/pkt_sched.h>
31
#include <linux/printk.h>
32
#include <linux/random.h>
33
#include <linux/rculist.h>
34
#include <linux/rcupdate.h>
35
#include <linux/skbuff.h>
36
#include <linux/slab.h>
37
#include <linux/spinlock.h>
38
#include <linux/stddef.h>
39
#include <linux/string.h>
40
#include <linux/string_choices.h>
41
#include <linux/types.h>
42
#include <linux/workqueue.h>
43
#include <net/genetlink.h>
44
#include <net/netlink.h>
45
#include <uapi/linux/batadv_packet.h>
46
#include <uapi/linux/batman_adv.h>
47
48
#include "bat_algo.h"
49
#include "bitarray.h"
50
#include "gateway_client.h"
51
#include "hard-interface.h"
52
#include "hash.h"
53
#include "log.h"
54
#include "netlink.h"
55
#include "network-coding.h"
56
#include "originator.h"
57
#include "routing.h"
58
#include "send.h"
59
#include "translation-table.h"
60
#include "tvlv.h"
61
62
static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work);
63
64
/**
65
* enum batadv_dup_status - duplicate status
66
*/
67
enum batadv_dup_status {
68
/** @BATADV_NO_DUP: the packet is no duplicate */
69
BATADV_NO_DUP = 0,
70
71
/**
72
* @BATADV_ORIG_DUP: OGM is a duplicate in the originator (but not for
73
* the neighbor)
74
*/
75
BATADV_ORIG_DUP,
76
77
/** @BATADV_NEIGH_DUP: OGM is a duplicate for the neighbor */
78
BATADV_NEIGH_DUP,
79
80
/**
81
* @BATADV_PROTECTED: originator is currently protected (after reboot)
82
*/
83
BATADV_PROTECTED,
84
};
85
86
/**
87
* batadv_ring_buffer_set() - update the ring buffer with the given value
88
* @lq_recv: pointer to the ring buffer
89
* @lq_index: index to store the value at
90
* @value: value to store in the ring buffer
91
*/
92
static void batadv_ring_buffer_set(u8 lq_recv[], u8 *lq_index, u8 value)
93
{
94
lq_recv[*lq_index] = value;
95
*lq_index = (*lq_index + 1) % BATADV_TQ_GLOBAL_WINDOW_SIZE;
96
}
97
98
/**
99
* batadv_ring_buffer_avg() - compute the average of all non-zero values stored
100
* in the given ring buffer
101
* @lq_recv: pointer to the ring buffer
102
*
103
* Return: computed average value.
104
*/
105
static u8 batadv_ring_buffer_avg(const u8 lq_recv[])
106
{
107
const u8 *ptr;
108
u16 count = 0;
109
u16 i = 0;
110
u16 sum = 0;
111
112
ptr = lq_recv;
113
114
while (i < BATADV_TQ_GLOBAL_WINDOW_SIZE) {
115
if (*ptr != 0) {
116
count++;
117
sum += *ptr;
118
}
119
120
i++;
121
ptr++;
122
}
123
124
if (count == 0)
125
return 0;
126
127
return (u8)(sum / count);
128
}
129
130
/**
131
* batadv_iv_ogm_orig_get() - retrieve or create (if does not exist) an
132
* originator
133
* @bat_priv: the bat priv with all the mesh interface information
134
* @addr: mac address of the originator
135
*
136
* Return: the originator object corresponding to the passed mac address or NULL
137
* on failure.
138
* If the object does not exist, it is created and initialised.
139
*/
140
static struct batadv_orig_node *
141
batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
142
{
143
struct batadv_orig_node *orig_node;
144
int hash_added;
145
146
orig_node = batadv_orig_hash_find(bat_priv, addr);
147
if (orig_node)
148
return orig_node;
149
150
orig_node = batadv_orig_node_new(bat_priv, addr);
151
if (!orig_node)
152
return NULL;
153
154
spin_lock_init(&orig_node->bat_iv.ogm_cnt_lock);
155
156
kref_get(&orig_node->refcount);
157
hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
158
batadv_choose_orig, orig_node,
159
&orig_node->hash_entry);
160
if (hash_added != 0)
161
goto free_orig_node_hash;
162
163
return orig_node;
164
165
free_orig_node_hash:
166
/* reference for batadv_hash_add */
167
batadv_orig_node_put(orig_node);
168
/* reference from batadv_orig_node_new */
169
batadv_orig_node_put(orig_node);
170
171
return NULL;
172
}
173
174
static struct batadv_neigh_node *
175
batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
176
const u8 *neigh_addr,
177
struct batadv_orig_node *orig_node,
178
struct batadv_orig_node *orig_neigh)
179
{
180
struct batadv_neigh_node *neigh_node;
181
182
neigh_node = batadv_neigh_node_get_or_create(orig_node,
183
hard_iface, neigh_addr);
184
if (!neigh_node)
185
goto out;
186
187
neigh_node->orig_node = orig_neigh;
188
189
out:
190
return neigh_node;
191
}
192
193
static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
194
{
195
struct batadv_ogm_packet *batadv_ogm_packet;
196
unsigned char *ogm_buff;
197
u32 random_seqno;
198
199
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
200
201
/* randomize initial seqno to avoid collision */
202
get_random_bytes(&random_seqno, sizeof(random_seqno));
203
atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
204
205
hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN;
206
ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC);
207
if (!ogm_buff) {
208
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
209
return -ENOMEM;
210
}
211
212
hard_iface->bat_iv.ogm_buff = ogm_buff;
213
214
batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
215
batadv_ogm_packet->packet_type = BATADV_IV_OGM;
216
batadv_ogm_packet->version = BATADV_COMPAT_VERSION;
217
batadv_ogm_packet->ttl = 2;
218
batadv_ogm_packet->flags = BATADV_NO_FLAGS;
219
batadv_ogm_packet->reserved = 0;
220
batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE;
221
222
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
223
224
return 0;
225
}
226
227
static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
228
{
229
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
230
231
kfree(hard_iface->bat_iv.ogm_buff);
232
hard_iface->bat_iv.ogm_buff = NULL;
233
234
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
235
}
236
237
static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
238
{
239
struct batadv_ogm_packet *batadv_ogm_packet;
240
void *ogm_buff;
241
242
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
243
244
ogm_buff = hard_iface->bat_iv.ogm_buff;
245
if (!ogm_buff)
246
goto unlock;
247
248
batadv_ogm_packet = ogm_buff;
249
ether_addr_copy(batadv_ogm_packet->orig,
250
hard_iface->net_dev->dev_addr);
251
ether_addr_copy(batadv_ogm_packet->prev_sender,
252
hard_iface->net_dev->dev_addr);
253
254
unlock:
255
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
256
}
257
258
static void
259
batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
260
{
261
struct batadv_ogm_packet *batadv_ogm_packet;
262
void *ogm_buff;
263
264
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
265
266
ogm_buff = hard_iface->bat_iv.ogm_buff;
267
if (!ogm_buff)
268
goto unlock;
269
270
batadv_ogm_packet = ogm_buff;
271
batadv_ogm_packet->ttl = BATADV_TTL;
272
273
unlock:
274
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
275
}
276
277
/* when do we schedule our own ogm to be sent */
278
static unsigned long
279
batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv)
280
{
281
unsigned int msecs;
282
283
msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
284
msecs += get_random_u32_below(2 * BATADV_JITTER);
285
286
return jiffies + msecs_to_jiffies(msecs);
287
}
288
289
/* when do we schedule a ogm packet to be sent */
290
static unsigned long batadv_iv_ogm_fwd_send_time(void)
291
{
292
return jiffies + msecs_to_jiffies(get_random_u32_below(BATADV_JITTER / 2));
293
}
294
295
/* apply hop penalty for a normal link */
296
static u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv)
297
{
298
int hop_penalty = atomic_read(&bat_priv->hop_penalty);
299
int new_tq;
300
301
new_tq = tq * (BATADV_TQ_MAX_VALUE - hop_penalty);
302
new_tq /= BATADV_TQ_MAX_VALUE;
303
304
return new_tq;
305
}
306
307
/**
308
* batadv_iv_ogm_aggr_packet() - checks if there is another OGM attached
309
* @buff_pos: current position in the skb
310
* @packet_len: total length of the skb
311
* @ogm_packet: potential OGM in buffer
312
*
313
* Return: true if there is enough space for another OGM, false otherwise.
314
*/
315
static bool
316
batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
317
const struct batadv_ogm_packet *ogm_packet)
318
{
319
int next_buff_pos = 0;
320
321
/* check if there is enough space for the header */
322
next_buff_pos += buff_pos + sizeof(*ogm_packet);
323
if (next_buff_pos > packet_len)
324
return false;
325
326
/* check if there is enough space for the optional TVLV */
327
next_buff_pos += ntohs(ogm_packet->tvlv_len);
328
329
return next_buff_pos <= packet_len;
330
}
331
332
/* send a batman ogm to a given interface */
333
static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
334
struct batadv_hard_iface *hard_iface)
335
{
336
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
337
const char *fwd_str;
338
u8 packet_num;
339
s16 buff_pos;
340
struct batadv_ogm_packet *batadv_ogm_packet;
341
struct sk_buff *skb;
342
u8 *packet_pos;
343
344
if (hard_iface->if_status != BATADV_IF_ACTIVE)
345
return;
346
347
packet_num = 0;
348
buff_pos = 0;
349
packet_pos = forw_packet->skb->data;
350
batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
351
352
/* adjust all flags and log packets */
353
while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
354
batadv_ogm_packet)) {
355
/* we might have aggregated direct link packets with an
356
* ordinary base packet
357
*/
358
if (test_bit(packet_num, forw_packet->direct_link_flags) &&
359
forw_packet->if_incoming == hard_iface)
360
batadv_ogm_packet->flags |= BATADV_DIRECTLINK;
361
else
362
batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK;
363
364
if (packet_num > 0 || !forw_packet->own)
365
fwd_str = "Forwarding";
366
else
367
fwd_str = "Sending own";
368
369
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
370
"%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s) on interface %s [%pM]\n",
371
fwd_str, (packet_num > 0 ? "aggregated " : ""),
372
batadv_ogm_packet->orig,
373
ntohl(batadv_ogm_packet->seqno),
374
batadv_ogm_packet->tq, batadv_ogm_packet->ttl,
375
str_on_off(batadv_ogm_packet->flags & BATADV_DIRECTLINK),
376
hard_iface->net_dev->name,
377
hard_iface->net_dev->dev_addr);
378
379
buff_pos += BATADV_OGM_HLEN;
380
buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
381
packet_num++;
382
packet_pos = forw_packet->skb->data + buff_pos;
383
batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
384
}
385
386
/* create clone because function is called more than once */
387
skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
388
if (skb) {
389
batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
390
batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
391
skb->len + ETH_HLEN);
392
batadv_send_broadcast_skb(skb, hard_iface);
393
}
394
}
395
396
/* send a batman ogm packet */
397
static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
398
{
399
struct net_device *mesh_iface;
400
401
if (!forw_packet->if_incoming) {
402
pr_err("Error - can't forward packet: incoming iface not specified\n");
403
return;
404
}
405
406
mesh_iface = forw_packet->if_incoming->mesh_iface;
407
408
if (WARN_ON(!forw_packet->if_outgoing))
409
return;
410
411
if (forw_packet->if_outgoing->mesh_iface != mesh_iface) {
412
pr_warn("%s: mesh interface switch for queued OGM\n", __func__);
413
return;
414
}
415
416
if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
417
return;
418
419
/* only for one specific outgoing interface */
420
batadv_iv_ogm_send_to_if(forw_packet, forw_packet->if_outgoing);
421
}
422
423
/**
424
* batadv_iv_ogm_can_aggregate() - find out if an OGM can be aggregated on an
425
* existing forward packet
426
* @new_bat_ogm_packet: OGM packet to be aggregated
427
* @bat_priv: the bat priv with all the mesh interface information
428
* @packet_len: (total) length of the OGM
429
* @send_time: timestamp (jiffies) when the packet is to be sent
430
* @directlink: true if this is a direct link packet
431
* @if_incoming: interface where the packet was received
432
* @if_outgoing: interface for which the retransmission should be considered
433
* @forw_packet: the forwarded packet which should be checked
434
*
435
* Return: true if new_packet can be aggregated with forw_packet
436
*/
437
static bool
438
batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
439
struct batadv_priv *bat_priv,
440
int packet_len, unsigned long send_time,
441
bool directlink,
442
const struct batadv_hard_iface *if_incoming,
443
const struct batadv_hard_iface *if_outgoing,
444
const struct batadv_forw_packet *forw_packet)
445
{
446
struct batadv_ogm_packet *batadv_ogm_packet;
447
unsigned int aggregated_bytes = forw_packet->packet_len + packet_len;
448
struct batadv_hard_iface *primary_if = NULL;
449
u8 packet_num = forw_packet->num_packets;
450
bool res = false;
451
unsigned long aggregation_end_time;
452
unsigned int max_bytes;
453
454
batadv_ogm_packet = (struct batadv_ogm_packet *)forw_packet->skb->data;
455
aggregation_end_time = send_time;
456
aggregation_end_time += msecs_to_jiffies(BATADV_MAX_AGGREGATION_MS);
457
458
max_bytes = min_t(unsigned int, if_outgoing->net_dev->mtu,
459
BATADV_MAX_AGGREGATION_BYTES);
460
461
/* we can aggregate the current packet to this aggregated packet
462
* if:
463
*
464
* - the send time is within our MAX_AGGREGATION_MS time
465
* - the resulting packet won't be bigger than
466
* MAX_AGGREGATION_BYTES and MTU of the outgoing interface
467
* - the number of packets is lower than MAX_AGGREGATION_PACKETS
468
* otherwise aggregation is not possible
469
*/
470
if (!time_before(send_time, forw_packet->send_time) ||
471
!time_after_eq(aggregation_end_time, forw_packet->send_time))
472
return false;
473
474
if (aggregated_bytes > max_bytes)
475
return false;
476
477
if (packet_num >= BATADV_MAX_AGGREGATION_PACKETS)
478
return false;
479
480
/* packet is not leaving on the same interface. */
481
if (forw_packet->if_outgoing != if_outgoing)
482
return false;
483
484
/* check aggregation compatibility
485
* -> direct link packets are broadcasted on
486
* their interface only
487
* -> aggregate packet if the current packet is
488
* a "global" packet as well as the base
489
* packet
490
*/
491
primary_if = batadv_primary_if_get_selected(bat_priv);
492
if (!primary_if)
493
return false;
494
495
/* packets without direct link flag and high TTL
496
* are flooded through the net
497
*/
498
if (!directlink &&
499
!(batadv_ogm_packet->flags & BATADV_DIRECTLINK) &&
500
batadv_ogm_packet->ttl != 1 &&
501
502
/* own packets originating non-primary
503
* interfaces leave only that interface
504
*/
505
(!forw_packet->own ||
506
forw_packet->if_incoming == primary_if)) {
507
res = true;
508
goto out;
509
}
510
511
/* if the incoming packet is sent via this one
512
* interface only - we still can aggregate
513
*/
514
if (directlink &&
515
new_bat_ogm_packet->ttl == 1 &&
516
forw_packet->if_incoming == if_incoming &&
517
518
/* packets from direct neighbors or
519
* own secondary interface packets
520
* (= secondary interface packets in general)
521
*/
522
(batadv_ogm_packet->flags & BATADV_DIRECTLINK ||
523
(forw_packet->own &&
524
forw_packet->if_incoming != primary_if))) {
525
res = true;
526
goto out;
527
}
528
529
out:
530
batadv_hardif_put(primary_if);
531
return res;
532
}
533
534
/**
535
* batadv_iv_ogm_aggregate_new() - create a new aggregated packet and add this
536
* packet to it.
537
* @packet_buff: pointer to the OGM
538
* @packet_len: (total) length of the OGM
539
* @send_time: timestamp (jiffies) when the packet is to be sent
540
* @direct_link: whether this OGM has direct link status
541
* @if_incoming: interface where the packet was received
542
* @if_outgoing: interface for which the retransmission should be considered
543
* @own_packet: true if it is a self-generated ogm
544
*/
545
static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
546
int packet_len, unsigned long send_time,
547
bool direct_link,
548
struct batadv_hard_iface *if_incoming,
549
struct batadv_hard_iface *if_outgoing,
550
int own_packet)
551
{
552
struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
553
struct batadv_forw_packet *forw_packet_aggr;
554
struct sk_buff *skb;
555
unsigned char *skb_buff;
556
unsigned int skb_size;
557
atomic_t *queue_left = own_packet ? NULL : &bat_priv->batman_queue_left;
558
559
if (atomic_read(&bat_priv->aggregated_ogms))
560
skb_size = max_t(unsigned int, BATADV_MAX_AGGREGATION_BYTES,
561
packet_len);
562
else
563
skb_size = packet_len;
564
565
skb_size += ETH_HLEN;
566
567
skb = netdev_alloc_skb_ip_align(NULL, skb_size);
568
if (!skb)
569
return;
570
571
forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing,
572
queue_left, bat_priv, skb);
573
if (!forw_packet_aggr) {
574
kfree_skb(skb);
575
return;
576
}
577
578
forw_packet_aggr->skb->priority = TC_PRIO_CONTROL;
579
skb_reserve(forw_packet_aggr->skb, ETH_HLEN);
580
581
skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
582
forw_packet_aggr->packet_len = packet_len;
583
memcpy(skb_buff, packet_buff, packet_len);
584
585
forw_packet_aggr->own = own_packet;
586
bitmap_zero(forw_packet_aggr->direct_link_flags,
587
BATADV_MAX_AGGREGATION_PACKETS);
588
forw_packet_aggr->send_time = send_time;
589
590
/* save packet direct link flag status */
591
if (direct_link)
592
set_bit(0, forw_packet_aggr->direct_link_flags);
593
594
INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
595
batadv_iv_send_outstanding_bat_ogm_packet);
596
597
batadv_forw_packet_ogmv1_queue(bat_priv, forw_packet_aggr, send_time);
598
}
599
600
/* aggregate a new packet into the existing ogm packet */
601
static void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr,
602
const unsigned char *packet_buff,
603
int packet_len, bool direct_link)
604
{
605
skb_put_data(forw_packet_aggr->skb, packet_buff, packet_len);
606
forw_packet_aggr->packet_len += packet_len;
607
608
/* save packet direct link flag status */
609
if (direct_link)
610
set_bit(forw_packet_aggr->num_packets,
611
forw_packet_aggr->direct_link_flags);
612
613
forw_packet_aggr->num_packets++;
614
}
615
616
/**
617
* batadv_iv_ogm_queue_add() - queue up an OGM for transmission
618
* @bat_priv: the bat priv with all the mesh interface information
619
* @packet_buff: pointer to the OGM
620
* @packet_len: (total) length of the OGM
621
* @if_incoming: interface where the packet was received
622
* @if_outgoing: interface for which the retransmission should be considered
623
* @own_packet: true if it is a self-generated ogm
624
* @send_time: timestamp (jiffies) when the packet is to be sent
625
*/
626
static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
627
unsigned char *packet_buff,
628
int packet_len,
629
struct batadv_hard_iface *if_incoming,
630
struct batadv_hard_iface *if_outgoing,
631
int own_packet, unsigned long send_time)
632
{
633
/* _aggr -> pointer to the packet we want to aggregate with
634
* _pos -> pointer to the position in the queue
635
*/
636
struct batadv_forw_packet *forw_packet_aggr = NULL;
637
struct batadv_forw_packet *forw_packet_pos = NULL;
638
struct batadv_ogm_packet *batadv_ogm_packet;
639
bool direct_link;
640
unsigned long max_aggregation_jiffies;
641
642
batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff;
643
direct_link = !!(batadv_ogm_packet->flags & BATADV_DIRECTLINK);
644
max_aggregation_jiffies = msecs_to_jiffies(BATADV_MAX_AGGREGATION_MS);
645
646
/* find position for the packet in the forward queue */
647
spin_lock_bh(&bat_priv->forw_bat_list_lock);
648
/* own packets are not to be aggregated */
649
if (atomic_read(&bat_priv->aggregated_ogms) && !own_packet) {
650
hlist_for_each_entry(forw_packet_pos,
651
&bat_priv->forw_bat_list, list) {
652
if (batadv_iv_ogm_can_aggregate(batadv_ogm_packet,
653
bat_priv, packet_len,
654
send_time, direct_link,
655
if_incoming,
656
if_outgoing,
657
forw_packet_pos)) {
658
forw_packet_aggr = forw_packet_pos;
659
break;
660
}
661
}
662
}
663
664
/* nothing to aggregate with - either aggregation disabled or no
665
* suitable aggregation packet found
666
*/
667
if (!forw_packet_aggr) {
668
/* the following section can run without the lock */
669
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
670
671
/* if we could not aggregate this packet with one of the others
672
* we hold it back for a while, so that it might be aggregated
673
* later on
674
*/
675
if (!own_packet && atomic_read(&bat_priv->aggregated_ogms))
676
send_time += max_aggregation_jiffies;
677
678
batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
679
send_time, direct_link,
680
if_incoming, if_outgoing,
681
own_packet);
682
} else {
683
batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff,
684
packet_len, direct_link);
685
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
686
}
687
}
688
689
static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
690
const struct ethhdr *ethhdr,
691
struct batadv_ogm_packet *batadv_ogm_packet,
692
bool is_single_hop_neigh,
693
bool is_from_best_next_hop,
694
struct batadv_hard_iface *if_incoming,
695
struct batadv_hard_iface *if_outgoing)
696
{
697
struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
698
u16 tvlv_len;
699
700
if (batadv_ogm_packet->ttl <= 1) {
701
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n");
702
return;
703
}
704
705
if (!is_from_best_next_hop) {
706
/* Mark the forwarded packet when it is not coming from our
707
* best next hop. We still need to forward the packet for our
708
* neighbor link quality detection to work in case the packet
709
* originated from a single hop neighbor. Otherwise we can
710
* simply drop the ogm.
711
*/
712
if (is_single_hop_neigh)
713
batadv_ogm_packet->flags |= BATADV_NOT_BEST_NEXT_HOP;
714
else
715
return;
716
}
717
718
tvlv_len = ntohs(batadv_ogm_packet->tvlv_len);
719
720
batadv_ogm_packet->ttl--;
721
ether_addr_copy(batadv_ogm_packet->prev_sender, ethhdr->h_source);
722
723
/* apply hop penalty */
724
batadv_ogm_packet->tq = batadv_hop_penalty(batadv_ogm_packet->tq,
725
bat_priv);
726
727
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
728
"Forwarding packet: tq: %i, ttl: %i\n",
729
batadv_ogm_packet->tq, batadv_ogm_packet->ttl);
730
731
if (is_single_hop_neigh)
732
batadv_ogm_packet->flags |= BATADV_DIRECTLINK;
733
else
734
batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK;
735
736
batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet,
737
BATADV_OGM_HLEN + tvlv_len,
738
if_incoming, if_outgoing, 0,
739
batadv_iv_ogm_fwd_send_time());
740
}
741
742
/**
743
* batadv_iv_ogm_slide_own_bcast_window() - bitshift own OGM broadcast windows
744
* for the given interface
745
* @hard_iface: the interface for which the windows have to be shifted
746
*/
747
static void
748
batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface)
749
{
750
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
751
struct batadv_hashtable *hash = bat_priv->orig_hash;
752
struct hlist_head *head;
753
struct batadv_orig_node *orig_node;
754
struct batadv_orig_ifinfo *orig_ifinfo;
755
unsigned long *word;
756
u32 i;
757
u8 *w;
758
759
for (i = 0; i < hash->size; i++) {
760
head = &hash->table[i];
761
762
rcu_read_lock();
763
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
764
hlist_for_each_entry_rcu(orig_ifinfo,
765
&orig_node->ifinfo_list,
766
list) {
767
if (orig_ifinfo->if_outgoing != hard_iface)
768
continue;
769
770
spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
771
word = orig_ifinfo->bat_iv.bcast_own;
772
batadv_bit_get_packet(bat_priv, word, 1, 0);
773
w = &orig_ifinfo->bat_iv.bcast_own_sum;
774
*w = bitmap_weight(word,
775
BATADV_TQ_LOCAL_WINDOW_SIZE);
776
spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
777
}
778
}
779
rcu_read_unlock();
780
}
781
}
782
783
/**
784
* batadv_iv_ogm_schedule_buff() - schedule submission of hardif ogm buffer
785
* @hard_iface: interface whose ogm buffer should be transmitted
786
*/
787
static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
788
{
789
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
790
unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
791
struct batadv_ogm_packet *batadv_ogm_packet;
792
struct batadv_hard_iface *primary_if, *tmp_hard_iface;
793
int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len;
794
struct list_head *iter;
795
u32 seqno;
796
u16 tvlv_len = 0;
797
unsigned long send_time;
798
799
lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
800
801
/* interface already disabled by batadv_iv_ogm_iface_disable */
802
if (!*ogm_buff)
803
return;
804
805
/* the interface gets activated here to avoid race conditions between
806
* the moment of activating the interface in
807
* hardif_activate_interface() where the originator mac is set and
808
* outdated packets (especially uninitialized mac addresses) in the
809
* packet queue
810
*/
811
if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
812
hard_iface->if_status = BATADV_IF_ACTIVE;
813
814
primary_if = batadv_primary_if_get_selected(bat_priv);
815
816
if (hard_iface == primary_if) {
817
/* tt changes have to be committed before the tvlv data is
818
* appended as it may alter the tt tvlv container
819
*/
820
batadv_tt_local_commit_changes(bat_priv);
821
tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
822
ogm_buff_len,
823
BATADV_OGM_HLEN);
824
}
825
826
batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff);
827
batadv_ogm_packet->tvlv_len = htons(tvlv_len);
828
829
/* change sequence number to network order */
830
seqno = (u32)atomic_read(&hard_iface->bat_iv.ogm_seqno);
831
batadv_ogm_packet->seqno = htonl(seqno);
832
atomic_inc(&hard_iface->bat_iv.ogm_seqno);
833
834
batadv_iv_ogm_slide_own_bcast_window(hard_iface);
835
836
send_time = batadv_iv_ogm_emit_send_time(bat_priv);
837
838
if (hard_iface != primary_if) {
839
/* OGMs from secondary interfaces are only scheduled on their
840
* respective interfaces.
841
*/
842
batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
843
hard_iface, hard_iface, 1, send_time);
844
goto out;
845
}
846
847
/* OGMs from primary interfaces are scheduled on all
848
* interfaces.
849
*/
850
rcu_read_lock();
851
netdev_for_each_lower_private_rcu(hard_iface->mesh_iface, tmp_hard_iface, iter) {
852
if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
853
continue;
854
855
batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
856
*ogm_buff_len, hard_iface,
857
tmp_hard_iface, 1, send_time);
858
859
batadv_hardif_put(tmp_hard_iface);
860
}
861
rcu_read_unlock();
862
863
out:
864
batadv_hardif_put(primary_if);
865
}
866
867
static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
868
{
869
if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
870
hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
871
return;
872
873
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
874
batadv_iv_ogm_schedule_buff(hard_iface);
875
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
876
}
877
878
/**
879
* batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over interface
880
* @orig_node: originator which reproadcasted the OGMs directly
881
* @if_outgoing: interface which transmitted the original OGM and received the
882
* direct rebroadcast
883
*
884
* Return: Number of replied (rebroadcasted) OGMs which were transmitted by
885
* an originator and directly (without intermediate hop) received by a specific
886
* interface
887
*/
888
static u8 batadv_iv_orig_ifinfo_sum(struct batadv_orig_node *orig_node,
889
struct batadv_hard_iface *if_outgoing)
890
{
891
struct batadv_orig_ifinfo *orig_ifinfo;
892
u8 sum;
893
894
orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing);
895
if (!orig_ifinfo)
896
return 0;
897
898
spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
899
sum = orig_ifinfo->bat_iv.bcast_own_sum;
900
spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
901
902
batadv_orig_ifinfo_put(orig_ifinfo);
903
904
return sum;
905
}
906
907
/**
908
* batadv_iv_ogm_orig_update() - use OGM to update corresponding data in an
909
* originator
910
* @bat_priv: the bat priv with all the mesh interface information
911
* @orig_node: the orig node who originally emitted the ogm packet
912
* @orig_ifinfo: ifinfo for the outgoing interface of the orig_node
913
* @ethhdr: Ethernet header of the OGM
914
* @batadv_ogm_packet: the ogm packet
915
* @if_incoming: interface where the packet was received
916
* @if_outgoing: interface for which the retransmission should be considered
917
* @dup_status: the duplicate status of this ogm packet.
918
*/
919
static void
920
batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
921
struct batadv_orig_node *orig_node,
922
struct batadv_orig_ifinfo *orig_ifinfo,
923
const struct ethhdr *ethhdr,
924
const struct batadv_ogm_packet *batadv_ogm_packet,
925
struct batadv_hard_iface *if_incoming,
926
struct batadv_hard_iface *if_outgoing,
927
enum batadv_dup_status dup_status)
928
{
929
struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
930
struct batadv_neigh_ifinfo *router_ifinfo = NULL;
931
struct batadv_neigh_node *neigh_node = NULL;
932
struct batadv_neigh_node *tmp_neigh_node = NULL;
933
struct batadv_neigh_node *router = NULL;
934
u8 sum_orig, sum_neigh;
935
u8 *neigh_addr;
936
u8 tq_avg;
937
938
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
939
"%s(): Searching and updating originator entry of received packet\n",
940
__func__);
941
942
rcu_read_lock();
943
hlist_for_each_entry_rcu(tmp_neigh_node,
944
&orig_node->neigh_list, list) {
945
neigh_addr = tmp_neigh_node->addr;
946
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
947
tmp_neigh_node->if_incoming == if_incoming &&
948
kref_get_unless_zero(&tmp_neigh_node->refcount)) {
949
if (WARN(neigh_node, "too many matching neigh_nodes"))
950
batadv_neigh_node_put(neigh_node);
951
neigh_node = tmp_neigh_node;
952
continue;
953
}
954
955
if (dup_status != BATADV_NO_DUP)
956
continue;
957
958
/* only update the entry for this outgoing interface */
959
neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node,
960
if_outgoing);
961
if (!neigh_ifinfo)
962
continue;
963
964
spin_lock_bh(&tmp_neigh_node->ifinfo_lock);
965
batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
966
&neigh_ifinfo->bat_iv.tq_index, 0);
967
tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
968
neigh_ifinfo->bat_iv.tq_avg = tq_avg;
969
spin_unlock_bh(&tmp_neigh_node->ifinfo_lock);
970
971
batadv_neigh_ifinfo_put(neigh_ifinfo);
972
neigh_ifinfo = NULL;
973
}
974
975
if (!neigh_node) {
976
struct batadv_orig_node *orig_tmp;
977
978
orig_tmp = batadv_iv_ogm_orig_get(bat_priv, ethhdr->h_source);
979
if (!orig_tmp)
980
goto unlock;
981
982
neigh_node = batadv_iv_ogm_neigh_new(if_incoming,
983
ethhdr->h_source,
984
orig_node, orig_tmp);
985
986
batadv_orig_node_put(orig_tmp);
987
if (!neigh_node)
988
goto unlock;
989
} else {
990
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
991
"Updating existing last-hop neighbor of originator\n");
992
}
993
994
rcu_read_unlock();
995
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
996
if (!neigh_ifinfo)
997
goto out;
998
999
neigh_node->last_seen = jiffies;
1000
1001
spin_lock_bh(&neigh_node->ifinfo_lock);
1002
batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
1003
&neigh_ifinfo->bat_iv.tq_index,
1004
batadv_ogm_packet->tq);
1005
tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
1006
neigh_ifinfo->bat_iv.tq_avg = tq_avg;
1007
spin_unlock_bh(&neigh_node->ifinfo_lock);
1008
1009
if (dup_status == BATADV_NO_DUP) {
1010
orig_ifinfo->last_ttl = batadv_ogm_packet->ttl;
1011
neigh_ifinfo->last_ttl = batadv_ogm_packet->ttl;
1012
}
1013
1014
/* if this neighbor already is our next hop there is nothing
1015
* to change
1016
*/
1017
router = batadv_orig_router_get(orig_node, if_outgoing);
1018
if (router == neigh_node)
1019
goto out;
1020
1021
if (router) {
1022
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
1023
if (!router_ifinfo)
1024
goto out;
1025
1026
/* if this neighbor does not offer a better TQ we won't
1027
* consider it
1028
*/
1029
if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg)
1030
goto out;
1031
}
1032
1033
/* if the TQ is the same and the link not more symmetric we
1034
* won't consider it either
1035
*/
1036
if (router_ifinfo &&
1037
neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg) {
1038
sum_orig = batadv_iv_orig_ifinfo_sum(router->orig_node,
1039
router->if_incoming);
1040
sum_neigh = batadv_iv_orig_ifinfo_sum(neigh_node->orig_node,
1041
neigh_node->if_incoming);
1042
if (sum_orig >= sum_neigh)
1043
goto out;
1044
}
1045
1046
batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
1047
goto out;
1048
1049
unlock:
1050
rcu_read_unlock();
1051
out:
1052
batadv_neigh_node_put(neigh_node);
1053
batadv_neigh_node_put(router);
1054
batadv_neigh_ifinfo_put(neigh_ifinfo);
1055
batadv_neigh_ifinfo_put(router_ifinfo);
1056
}
1057
1058
/**
1059
* batadv_iv_ogm_calc_tq() - calculate tq for current received ogm packet
1060
* @orig_node: the orig node who originally emitted the ogm packet
1061
* @orig_neigh_node: the orig node struct of the neighbor who sent the packet
1062
* @batadv_ogm_packet: the ogm packet
1063
* @if_incoming: interface where the packet was received
1064
* @if_outgoing: interface for which the retransmission should be considered
1065
*
1066
* Return: true if the link can be considered bidirectional, false otherwise
1067
*/
1068
static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
1069
struct batadv_orig_node *orig_neigh_node,
1070
struct batadv_ogm_packet *batadv_ogm_packet,
1071
struct batadv_hard_iface *if_incoming,
1072
struct batadv_hard_iface *if_outgoing)
1073
{
1074
struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
1075
struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node;
1076
struct batadv_neigh_ifinfo *neigh_ifinfo;
1077
u8 total_count;
1078
u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
1079
unsigned int tq_iface_hop_penalty = BATADV_TQ_MAX_VALUE;
1080
unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
1081
unsigned int tq_asym_penalty, inv_asym_penalty;
1082
unsigned int combined_tq;
1083
bool ret = false;
1084
1085
/* find corresponding one hop neighbor */
1086
rcu_read_lock();
1087
hlist_for_each_entry_rcu(tmp_neigh_node,
1088
&orig_neigh_node->neigh_list, list) {
1089
if (!batadv_compare_eth(tmp_neigh_node->addr,
1090
orig_neigh_node->orig))
1091
continue;
1092
1093
if (tmp_neigh_node->if_incoming != if_incoming)
1094
continue;
1095
1096
if (!kref_get_unless_zero(&tmp_neigh_node->refcount))
1097
continue;
1098
1099
neigh_node = tmp_neigh_node;
1100
break;
1101
}
1102
rcu_read_unlock();
1103
1104
if (!neigh_node)
1105
neigh_node = batadv_iv_ogm_neigh_new(if_incoming,
1106
orig_neigh_node->orig,
1107
orig_neigh_node,
1108
orig_neigh_node);
1109
1110
if (!neigh_node)
1111
goto out;
1112
1113
/* if orig_node is direct neighbor update neigh_node last_seen */
1114
if (orig_node == orig_neigh_node)
1115
neigh_node->last_seen = jiffies;
1116
1117
orig_node->last_seen = jiffies;
1118
1119
/* find packet count of corresponding one hop neighbor */
1120
orig_eq_count = batadv_iv_orig_ifinfo_sum(orig_neigh_node, if_incoming);
1121
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
1122
if (neigh_ifinfo) {
1123
neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count;
1124
batadv_neigh_ifinfo_put(neigh_ifinfo);
1125
} else {
1126
neigh_rq_count = 0;
1127
}
1128
1129
/* pay attention to not get a value bigger than 100 % */
1130
if (orig_eq_count > neigh_rq_count)
1131
total_count = neigh_rq_count;
1132
else
1133
total_count = orig_eq_count;
1134
1135
/* if we have too few packets (too less data) we set tq_own to zero
1136
* if we receive too few packets it is not considered bidirectional
1137
*/
1138
if (total_count < BATADV_TQ_LOCAL_BIDRECT_SEND_MINIMUM ||
1139
neigh_rq_count < BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM)
1140
tq_own = 0;
1141
else
1142
/* neigh_node->real_packet_count is never zero as we
1143
* only purge old information when getting new
1144
* information
1145
*/
1146
tq_own = (BATADV_TQ_MAX_VALUE * total_count) / neigh_rq_count;
1147
1148
/* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
1149
* affect the nearly-symmetric links only a little, but
1150
* punishes asymmetric links more. This will give a value
1151
* between 0 and TQ_MAX_VALUE
1152
*/
1153
neigh_rq_inv = BATADV_TQ_LOCAL_WINDOW_SIZE - neigh_rq_count;
1154
neigh_rq_inv_cube = neigh_rq_inv * neigh_rq_inv * neigh_rq_inv;
1155
neigh_rq_max_cube = BATADV_TQ_LOCAL_WINDOW_SIZE *
1156
BATADV_TQ_LOCAL_WINDOW_SIZE *
1157
BATADV_TQ_LOCAL_WINDOW_SIZE;
1158
inv_asym_penalty = BATADV_TQ_MAX_VALUE * neigh_rq_inv_cube;
1159
inv_asym_penalty /= neigh_rq_max_cube;
1160
tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty;
1161
tq_iface_hop_penalty -= atomic_read(&if_incoming->hop_penalty);
1162
1163
/* penalize if the OGM is forwarded on the same interface. WiFi
1164
* interfaces and other half duplex devices suffer from throughput
1165
* drops as they can't send and receive at the same time.
1166
*/
1167
if (if_outgoing && if_incoming == if_outgoing &&
1168
batadv_is_wifi_hardif(if_outgoing))
1169
tq_iface_hop_penalty = batadv_hop_penalty(tq_iface_hop_penalty,
1170
bat_priv);
1171
1172
combined_tq = batadv_ogm_packet->tq *
1173
tq_own *
1174
tq_asym_penalty *
1175
tq_iface_hop_penalty;
1176
combined_tq /= BATADV_TQ_MAX_VALUE *
1177
BATADV_TQ_MAX_VALUE *
1178
BATADV_TQ_MAX_VALUE;
1179
batadv_ogm_packet->tq = combined_tq;
1180
1181
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1182
"bidirectional: orig = %pM neigh = %pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, iface_hop_penalty: %3i, total tq: %3i, if_incoming = %s, if_outgoing = %s\n",
1183
orig_node->orig, orig_neigh_node->orig, total_count,
1184
neigh_rq_count, tq_own, tq_asym_penalty,
1185
tq_iface_hop_penalty, batadv_ogm_packet->tq,
1186
if_incoming->net_dev->name,
1187
if_outgoing ? if_outgoing->net_dev->name : "DEFAULT");
1188
1189
/* if link has the minimum required transmission quality
1190
* consider it bidirectional
1191
*/
1192
if (batadv_ogm_packet->tq >= BATADV_TQ_TOTAL_BIDRECT_LIMIT)
1193
ret = true;
1194
1195
out:
1196
batadv_neigh_node_put(neigh_node);
1197
return ret;
1198
}
1199
1200
/**
1201
* batadv_iv_ogm_update_seqnos() - process a batman packet for all interfaces,
1202
* adjust the sequence number and find out whether it is a duplicate
1203
* @ethhdr: ethernet header of the packet
1204
* @batadv_ogm_packet: OGM packet to be considered
1205
* @if_incoming: interface on which the OGM packet was received
1206
* @if_outgoing: interface for which the retransmission should be considered
1207
*
1208
* Return: duplicate status as enum batadv_dup_status
1209
*/
1210
static enum batadv_dup_status
1211
batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
1212
const struct batadv_ogm_packet *batadv_ogm_packet,
1213
const struct batadv_hard_iface *if_incoming,
1214
struct batadv_hard_iface *if_outgoing)
1215
{
1216
struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
1217
struct batadv_orig_node *orig_node;
1218
struct batadv_orig_ifinfo *orig_ifinfo = NULL;
1219
struct batadv_neigh_node *neigh_node;
1220
struct batadv_neigh_ifinfo *neigh_ifinfo;
1221
bool is_dup;
1222
s32 seq_diff;
1223
bool need_update = false;
1224
int set_mark;
1225
enum batadv_dup_status ret = BATADV_NO_DUP;
1226
u32 seqno = ntohl(batadv_ogm_packet->seqno);
1227
u8 *neigh_addr;
1228
u8 packet_count;
1229
unsigned long *bitmap;
1230
1231
orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig);
1232
if (!orig_node)
1233
return BATADV_NO_DUP;
1234
1235
orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
1236
if (WARN_ON(!orig_ifinfo)) {
1237
batadv_orig_node_put(orig_node);
1238
return 0;
1239
}
1240
1241
spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
1242
seq_diff = seqno - orig_ifinfo->last_real_seqno;
1243
1244
/* signalize caller that the packet is to be dropped. */
1245
if (!hlist_empty(&orig_node->neigh_list) &&
1246
batadv_window_protected(bat_priv, seq_diff,
1247
BATADV_TQ_LOCAL_WINDOW_SIZE,
1248
&orig_ifinfo->batman_seqno_reset, NULL)) {
1249
ret = BATADV_PROTECTED;
1250
goto out;
1251
}
1252
1253
rcu_read_lock();
1254
hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
1255
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node,
1256
if_outgoing);
1257
if (!neigh_ifinfo)
1258
continue;
1259
1260
neigh_addr = neigh_node->addr;
1261
is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits,
1262
orig_ifinfo->last_real_seqno,
1263
seqno);
1264
1265
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
1266
neigh_node->if_incoming == if_incoming) {
1267
set_mark = 1;
1268
if (is_dup)
1269
ret = BATADV_NEIGH_DUP;
1270
} else {
1271
set_mark = 0;
1272
if (is_dup && ret != BATADV_NEIGH_DUP)
1273
ret = BATADV_ORIG_DUP;
1274
}
1275
1276
/* if the window moved, set the update flag. */
1277
bitmap = neigh_ifinfo->bat_iv.real_bits;
1278
need_update |= batadv_bit_get_packet(bat_priv, bitmap,
1279
seq_diff, set_mark);
1280
1281
packet_count = bitmap_weight(bitmap,
1282
BATADV_TQ_LOCAL_WINDOW_SIZE);
1283
neigh_ifinfo->bat_iv.real_packet_count = packet_count;
1284
batadv_neigh_ifinfo_put(neigh_ifinfo);
1285
}
1286
rcu_read_unlock();
1287
1288
if (need_update) {
1289
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1290
"%s updating last_seqno: old %u, new %u\n",
1291
if_outgoing ? if_outgoing->net_dev->name : "DEFAULT",
1292
orig_ifinfo->last_real_seqno, seqno);
1293
orig_ifinfo->last_real_seqno = seqno;
1294
}
1295
1296
out:
1297
spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
1298
batadv_orig_node_put(orig_node);
1299
batadv_orig_ifinfo_put(orig_ifinfo);
1300
return ret;
1301
}
1302
1303
/**
1304
* batadv_iv_ogm_process_per_outif() - process a batman iv OGM for an outgoing
1305
* interface
1306
* @skb: the skb containing the OGM
1307
* @ogm_offset: offset from skb->data to start of ogm header
1308
* @orig_node: the (cached) orig node for the originator of this OGM
1309
* @if_incoming: the interface where this packet was received
1310
* @if_outgoing: the interface for which the packet should be considered
1311
*/
1312
static void
1313
batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
1314
struct batadv_orig_node *orig_node,
1315
struct batadv_hard_iface *if_incoming,
1316
struct batadv_hard_iface *if_outgoing)
1317
{
1318
struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
1319
struct batadv_hardif_neigh_node *hardif_neigh = NULL;
1320
struct batadv_neigh_node *router = NULL;
1321
struct batadv_neigh_node *router_router = NULL;
1322
struct batadv_orig_node *orig_neigh_node;
1323
struct batadv_orig_ifinfo *orig_ifinfo;
1324
struct batadv_neigh_node *orig_neigh_router = NULL;
1325
struct batadv_neigh_ifinfo *router_ifinfo = NULL;
1326
struct batadv_ogm_packet *ogm_packet;
1327
enum batadv_dup_status dup_status;
1328
bool is_from_best_next_hop = false;
1329
bool is_single_hop_neigh = false;
1330
bool sameseq, similar_ttl;
1331
struct sk_buff *skb_priv;
1332
struct ethhdr *ethhdr;
1333
u8 *prev_sender;
1334
bool is_bidirect;
1335
1336
/* create a private copy of the skb, as some functions change tq value
1337
* and/or flags.
1338
*/
1339
skb_priv = skb_copy(skb, GFP_ATOMIC);
1340
if (!skb_priv)
1341
return;
1342
1343
ethhdr = eth_hdr(skb_priv);
1344
ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset);
1345
1346
dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet,
1347
if_incoming, if_outgoing);
1348
if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig))
1349
is_single_hop_neigh = true;
1350
1351
if (dup_status == BATADV_PROTECTED) {
1352
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1353
"Drop packet: packet within seqno protection time (sender: %pM)\n",
1354
ethhdr->h_source);
1355
goto out;
1356
}
1357
1358
if (ogm_packet->tq == 0) {
1359
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1360
"Drop packet: originator packet with tq equal 0\n");
1361
goto out;
1362
}
1363
1364
if (is_single_hop_neigh) {
1365
hardif_neigh = batadv_hardif_neigh_get(if_incoming,
1366
ethhdr->h_source);
1367
if (hardif_neigh)
1368
hardif_neigh->last_seen = jiffies;
1369
}
1370
1371
router = batadv_orig_router_get(orig_node, if_outgoing);
1372
if (router) {
1373
router_router = batadv_orig_router_get(router->orig_node,
1374
if_outgoing);
1375
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
1376
}
1377
1378
if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) &&
1379
(batadv_compare_eth(router->addr, ethhdr->h_source)))
1380
is_from_best_next_hop = true;
1381
1382
prev_sender = ogm_packet->prev_sender;
1383
/* avoid temporary routing loops */
1384
if (router && router_router &&
1385
(batadv_compare_eth(router->addr, prev_sender)) &&
1386
!(batadv_compare_eth(ogm_packet->orig, prev_sender)) &&
1387
(batadv_compare_eth(router->addr, router_router->addr))) {
1388
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1389
"Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
1390
ethhdr->h_source);
1391
goto out;
1392
}
1393
1394
if (if_outgoing == BATADV_IF_DEFAULT)
1395
batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node);
1396
1397
/* if sender is a direct neighbor the sender mac equals
1398
* originator mac
1399
*/
1400
if (is_single_hop_neigh)
1401
orig_neigh_node = orig_node;
1402
else
1403
orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
1404
ethhdr->h_source);
1405
1406
if (!orig_neigh_node)
1407
goto out;
1408
1409
/* Update nc_nodes of the originator */
1410
batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
1411
ogm_packet, is_single_hop_neigh);
1412
1413
orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
1414
if_outgoing);
1415
1416
/* drop packet if sender is not a direct neighbor and if we
1417
* don't route towards it
1418
*/
1419
if (!is_single_hop_neigh && !orig_neigh_router) {
1420
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1421
"Drop packet: OGM via unknown neighbor!\n");
1422
goto out_neigh;
1423
}
1424
1425
is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
1426
ogm_packet, if_incoming,
1427
if_outgoing);
1428
1429
/* update ranking if it is not a duplicate or has the same
1430
* seqno and similar ttl as the non-duplicate
1431
*/
1432
orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
1433
if (!orig_ifinfo)
1434
goto out_neigh;
1435
1436
sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno);
1437
similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->ttl;
1438
1439
if (is_bidirect && (dup_status == BATADV_NO_DUP ||
1440
(sameseq && similar_ttl))) {
1441
batadv_iv_ogm_orig_update(bat_priv, orig_node,
1442
orig_ifinfo, ethhdr,
1443
ogm_packet, if_incoming,
1444
if_outgoing, dup_status);
1445
}
1446
batadv_orig_ifinfo_put(orig_ifinfo);
1447
1448
/* only forward for specific interface, not for the default one. */
1449
if (if_outgoing == BATADV_IF_DEFAULT)
1450
goto out_neigh;
1451
1452
/* is single hop (direct) neighbor */
1453
if (is_single_hop_neigh) {
1454
/* OGMs from secondary interfaces should only scheduled once
1455
* per interface where it has been received, not multiple times
1456
*/
1457
if (ogm_packet->ttl <= 2 &&
1458
if_incoming != if_outgoing) {
1459
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1460
"Drop packet: OGM from secondary interface and wrong outgoing interface\n");
1461
goto out_neigh;
1462
}
1463
/* mark direct link on incoming interface */
1464
batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
1465
is_single_hop_neigh,
1466
is_from_best_next_hop, if_incoming,
1467
if_outgoing);
1468
1469
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1470
"Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
1471
goto out_neigh;
1472
}
1473
1474
/* multihop originator */
1475
if (!is_bidirect) {
1476
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1477
"Drop packet: not received via bidirectional link\n");
1478
goto out_neigh;
1479
}
1480
1481
if (dup_status == BATADV_NEIGH_DUP) {
1482
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1483
"Drop packet: duplicate packet received\n");
1484
goto out_neigh;
1485
}
1486
1487
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1488
"Forwarding packet: rebroadcast originator packet\n");
1489
batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
1490
is_single_hop_neigh, is_from_best_next_hop,
1491
if_incoming, if_outgoing);
1492
1493
out_neigh:
1494
if (orig_neigh_node && !is_single_hop_neigh)
1495
batadv_orig_node_put(orig_neigh_node);
1496
out:
1497
batadv_neigh_ifinfo_put(router_ifinfo);
1498
batadv_neigh_node_put(router);
1499
batadv_neigh_node_put(router_router);
1500
batadv_neigh_node_put(orig_neigh_router);
1501
batadv_hardif_neigh_put(hardif_neigh);
1502
1503
consume_skb(skb_priv);
1504
}
1505
1506
/**
1507
* batadv_iv_ogm_process_reply() - Check OGM for direct reply and process it
1508
* @ogm_packet: rebroadcast OGM packet to process
1509
* @if_incoming: the interface where this packet was received
1510
* @orig_node: originator which reproadcasted the OGMs
1511
* @if_incoming_seqno: OGM sequence number when rebroadcast was received
1512
*/
1513
static void batadv_iv_ogm_process_reply(struct batadv_ogm_packet *ogm_packet,
1514
struct batadv_hard_iface *if_incoming,
1515
struct batadv_orig_node *orig_node,
1516
u32 if_incoming_seqno)
1517
{
1518
struct batadv_orig_ifinfo *orig_ifinfo;
1519
s32 bit_pos;
1520
u8 *weight;
1521
1522
/* neighbor has to indicate direct link and it has to
1523
* come via the corresponding interface
1524
*/
1525
if (!(ogm_packet->flags & BATADV_DIRECTLINK))
1526
return;
1527
1528
if (!batadv_compare_eth(if_incoming->net_dev->dev_addr,
1529
ogm_packet->orig))
1530
return;
1531
1532
orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_incoming);
1533
if (!orig_ifinfo)
1534
return;
1535
1536
/* save packet seqno for bidirectional check */
1537
spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
1538
bit_pos = if_incoming_seqno - 2;
1539
bit_pos -= ntohl(ogm_packet->seqno);
1540
batadv_set_bit(orig_ifinfo->bat_iv.bcast_own, bit_pos);
1541
weight = &orig_ifinfo->bat_iv.bcast_own_sum;
1542
*weight = bitmap_weight(orig_ifinfo->bat_iv.bcast_own,
1543
BATADV_TQ_LOCAL_WINDOW_SIZE);
1544
spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
1545
1546
batadv_orig_ifinfo_put(orig_ifinfo);
1547
}
1548
1549
/**
1550
* batadv_iv_ogm_process() - process an incoming batman iv OGM
1551
* @skb: the skb containing the OGM
1552
* @ogm_offset: offset to the OGM which should be processed (for aggregates)
1553
* @if_incoming: the interface where this packet was received
1554
*/
1555
static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
1556
struct batadv_hard_iface *if_incoming)
1557
{
1558
struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
1559
struct batadv_orig_node *orig_neigh_node, *orig_node;
1560
struct batadv_hard_iface *hard_iface;
1561
struct batadv_ogm_packet *ogm_packet;
1562
u32 if_incoming_seqno;
1563
bool has_directlink_flag;
1564
struct ethhdr *ethhdr;
1565
bool is_my_oldorig = false;
1566
bool is_my_addr = false;
1567
bool is_my_orig = false;
1568
struct list_head *iter;
1569
1570
ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset);
1571
ethhdr = eth_hdr(skb);
1572
1573
/* Silently drop when the batman packet is actually not a
1574
* correct packet.
1575
*
1576
* This might happen if a packet is padded (e.g. Ethernet has a
1577
* minimum frame length of 64 byte) and the aggregation interprets
1578
* it as an additional length.
1579
*
1580
* TODO: A more sane solution would be to have a bit in the
1581
* batadv_ogm_packet to detect whether the packet is the last
1582
* packet in an aggregation. Here we expect that the padding
1583
* is always zero (or not 0x01)
1584
*/
1585
if (ogm_packet->packet_type != BATADV_IV_OGM)
1586
return;
1587
1588
/* could be changed by schedule_own_packet() */
1589
if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
1590
1591
if (ogm_packet->flags & BATADV_DIRECTLINK)
1592
has_directlink_flag = true;
1593
else
1594
has_directlink_flag = false;
1595
1596
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1597
"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)\n",
1598
ethhdr->h_source, if_incoming->net_dev->name,
1599
if_incoming->net_dev->dev_addr, ogm_packet->orig,
1600
ogm_packet->prev_sender, ntohl(ogm_packet->seqno),
1601
ogm_packet->tq, ogm_packet->ttl,
1602
ogm_packet->version, has_directlink_flag);
1603
1604
rcu_read_lock();
1605
1606
netdev_for_each_lower_private_rcu(if_incoming->mesh_iface, hard_iface, iter) {
1607
if (hard_iface->if_status != BATADV_IF_ACTIVE)
1608
continue;
1609
1610
if (batadv_compare_eth(ethhdr->h_source,
1611
hard_iface->net_dev->dev_addr))
1612
is_my_addr = true;
1613
1614
if (batadv_compare_eth(ogm_packet->orig,
1615
hard_iface->net_dev->dev_addr))
1616
is_my_orig = true;
1617
1618
if (batadv_compare_eth(ogm_packet->prev_sender,
1619
hard_iface->net_dev->dev_addr))
1620
is_my_oldorig = true;
1621
}
1622
rcu_read_unlock();
1623
1624
if (is_my_addr) {
1625
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1626
"Drop packet: received my own broadcast (sender: %pM)\n",
1627
ethhdr->h_source);
1628
return;
1629
}
1630
1631
if (is_my_orig) {
1632
orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
1633
ethhdr->h_source);
1634
if (!orig_neigh_node)
1635
return;
1636
1637
batadv_iv_ogm_process_reply(ogm_packet, if_incoming,
1638
orig_neigh_node, if_incoming_seqno);
1639
1640
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1641
"Drop packet: originator packet from myself (via neighbor)\n");
1642
batadv_orig_node_put(orig_neigh_node);
1643
return;
1644
}
1645
1646
if (is_my_oldorig) {
1647
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1648
"Drop packet: ignoring all rebroadcast echos (sender: %pM)\n",
1649
ethhdr->h_source);
1650
return;
1651
}
1652
1653
if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
1654
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1655
"Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n",
1656
ethhdr->h_source);
1657
return;
1658
}
1659
1660
orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig);
1661
if (!orig_node)
1662
return;
1663
1664
batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
1665
if_incoming, BATADV_IF_DEFAULT);
1666
1667
rcu_read_lock();
1668
netdev_for_each_lower_private_rcu(bat_priv->mesh_iface, hard_iface, iter) {
1669
if (hard_iface->if_status != BATADV_IF_ACTIVE)
1670
continue;
1671
1672
if (!kref_get_unless_zero(&hard_iface->refcount))
1673
continue;
1674
1675
batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
1676
if_incoming, hard_iface);
1677
1678
batadv_hardif_put(hard_iface);
1679
}
1680
rcu_read_unlock();
1681
1682
batadv_orig_node_put(orig_node);
1683
}
1684
1685
static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
1686
{
1687
struct delayed_work *delayed_work;
1688
struct batadv_forw_packet *forw_packet;
1689
struct batadv_priv *bat_priv;
1690
bool dropped = false;
1691
1692
delayed_work = to_delayed_work(work);
1693
forw_packet = container_of(delayed_work, struct batadv_forw_packet,
1694
delayed_work);
1695
bat_priv = netdev_priv(forw_packet->if_incoming->mesh_iface);
1696
1697
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
1698
dropped = true;
1699
goto out;
1700
}
1701
1702
batadv_iv_ogm_emit(forw_packet);
1703
1704
/* we have to have at least one packet in the queue to determine the
1705
* queues wake up time unless we are shutting down.
1706
*
1707
* only re-schedule if this is the "original" copy, e.g. the OGM of the
1708
* primary interface should only be rescheduled once per period, but
1709
* this function will be called for the forw_packet instances of the
1710
* other secondary interfaces as well.
1711
*/
1712
if (forw_packet->own &&
1713
forw_packet->if_incoming == forw_packet->if_outgoing)
1714
batadv_iv_ogm_schedule(forw_packet->if_incoming);
1715
1716
out:
1717
/* do we get something for free()? */
1718
if (batadv_forw_packet_steal(forw_packet,
1719
&bat_priv->forw_bat_list_lock))
1720
batadv_forw_packet_free(forw_packet, dropped);
1721
}
1722
1723
static int batadv_iv_ogm_receive(struct sk_buff *skb,
1724
struct batadv_hard_iface *if_incoming)
1725
{
1726
struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
1727
struct batadv_ogm_packet *ogm_packet;
1728
u8 *packet_pos;
1729
int ogm_offset;
1730
bool res;
1731
int ret = NET_RX_DROP;
1732
1733
res = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN);
1734
if (!res)
1735
goto free_skb;
1736
1737
/* did we receive a B.A.T.M.A.N. IV OGM packet on an interface
1738
* that does not have B.A.T.M.A.N. IV enabled ?
1739
*/
1740
if (bat_priv->algo_ops->iface.enable != batadv_iv_ogm_iface_enable)
1741
goto free_skb;
1742
1743
batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
1744
batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
1745
skb->len + ETH_HLEN);
1746
1747
ogm_offset = 0;
1748
ogm_packet = (struct batadv_ogm_packet *)skb->data;
1749
1750
/* unpack the aggregated packets and process them one by one */
1751
while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
1752
ogm_packet)) {
1753
batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
1754
1755
ogm_offset += BATADV_OGM_HLEN;
1756
ogm_offset += ntohs(ogm_packet->tvlv_len);
1757
1758
packet_pos = skb->data + ogm_offset;
1759
ogm_packet = (struct batadv_ogm_packet *)packet_pos;
1760
}
1761
1762
ret = NET_RX_SUCCESS;
1763
1764
free_skb:
1765
if (ret == NET_RX_SUCCESS)
1766
consume_skb(skb);
1767
else
1768
kfree_skb(skb);
1769
1770
return ret;
1771
}
1772
1773
/**
1774
* batadv_iv_ogm_neigh_get_tq_avg() - Get the TQ average for a neighbour on a
1775
* given outgoing interface.
1776
* @neigh_node: Neighbour of interest
1777
* @if_outgoing: Outgoing interface of interest
1778
* @tq_avg: Pointer of where to store the TQ average
1779
*
1780
* Return: False if no average TQ available, otherwise true.
1781
*/
1782
static bool
1783
batadv_iv_ogm_neigh_get_tq_avg(struct batadv_neigh_node *neigh_node,
1784
struct batadv_hard_iface *if_outgoing,
1785
u8 *tq_avg)
1786
{
1787
struct batadv_neigh_ifinfo *n_ifinfo;
1788
1789
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
1790
if (!n_ifinfo)
1791
return false;
1792
1793
*tq_avg = n_ifinfo->bat_iv.tq_avg;
1794
batadv_neigh_ifinfo_put(n_ifinfo);
1795
1796
return true;
1797
}
1798
1799
/**
1800
* batadv_iv_ogm_orig_dump_subentry() - Dump an originator subentry into a
1801
* message
1802
* @msg: Netlink message to dump into
1803
* @portid: Port making netlink request
1804
* @seq: Sequence number of netlink message
1805
* @bat_priv: The bat priv with all the mesh interface information
1806
* @if_outgoing: Limit dump to entries with this outgoing interface
1807
* @orig_node: Originator to dump
1808
* @neigh_node: Single hops neighbour
1809
* @best: Is the best originator
1810
*
1811
* Return: Error code, or 0 on success
1812
*/
1813
static int
1814
batadv_iv_ogm_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
1815
struct batadv_priv *bat_priv,
1816
struct batadv_hard_iface *if_outgoing,
1817
struct batadv_orig_node *orig_node,
1818
struct batadv_neigh_node *neigh_node,
1819
bool best)
1820
{
1821
void *hdr;
1822
u8 tq_avg;
1823
unsigned int last_seen_msecs;
1824
1825
last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen);
1826
1827
if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node, if_outgoing, &tq_avg))
1828
return 0;
1829
1830
if (if_outgoing != BATADV_IF_DEFAULT &&
1831
if_outgoing != neigh_node->if_incoming)
1832
return 0;
1833
1834
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
1835
NLM_F_MULTI, BATADV_CMD_GET_ORIGINATORS);
1836
if (!hdr)
1837
return -ENOBUFS;
1838
1839
if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
1840
orig_node->orig) ||
1841
nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
1842
neigh_node->addr) ||
1843
nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
1844
neigh_node->if_incoming->net_dev->name) ||
1845
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
1846
neigh_node->if_incoming->net_dev->ifindex) ||
1847
nla_put_u8(msg, BATADV_ATTR_TQ, tq_avg) ||
1848
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
1849
last_seen_msecs))
1850
goto nla_put_failure;
1851
1852
if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
1853
goto nla_put_failure;
1854
1855
genlmsg_end(msg, hdr);
1856
return 0;
1857
1858
nla_put_failure:
1859
genlmsg_cancel(msg, hdr);
1860
return -EMSGSIZE;
1861
}
1862
1863
/**
1864
* batadv_iv_ogm_orig_dump_entry() - Dump an originator entry into a message
1865
* @msg: Netlink message to dump into
1866
* @portid: Port making netlink request
1867
* @seq: Sequence number of netlink message
1868
* @bat_priv: The bat priv with all the mesh interface information
1869
* @if_outgoing: Limit dump to entries with this outgoing interface
1870
* @orig_node: Originator to dump
1871
* @sub_s: Number of sub entries to skip
1872
*
1873
* This function assumes the caller holds rcu_read_lock().
1874
*
1875
* Return: Error code, or 0 on success
1876
*/
1877
static int
1878
batadv_iv_ogm_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
1879
struct batadv_priv *bat_priv,
1880
struct batadv_hard_iface *if_outgoing,
1881
struct batadv_orig_node *orig_node, int *sub_s)
1882
{
1883
struct batadv_neigh_node *neigh_node_best;
1884
struct batadv_neigh_node *neigh_node;
1885
int sub = 0;
1886
bool best;
1887
u8 tq_avg_best;
1888
1889
neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing);
1890
if (!neigh_node_best)
1891
goto out;
1892
1893
if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node_best, if_outgoing,
1894
&tq_avg_best))
1895
goto out;
1896
1897
if (tq_avg_best == 0)
1898
goto out;
1899
1900
hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
1901
if (sub++ < *sub_s)
1902
continue;
1903
1904
best = (neigh_node == neigh_node_best);
1905
1906
if (batadv_iv_ogm_orig_dump_subentry(msg, portid, seq,
1907
bat_priv, if_outgoing,
1908
orig_node, neigh_node,
1909
best)) {
1910
batadv_neigh_node_put(neigh_node_best);
1911
1912
*sub_s = sub - 1;
1913
return -EMSGSIZE;
1914
}
1915
}
1916
1917
out:
1918
batadv_neigh_node_put(neigh_node_best);
1919
1920
*sub_s = 0;
1921
return 0;
1922
}
1923
1924
/**
1925
* batadv_iv_ogm_orig_dump_bucket() - Dump an originator bucket into a
1926
* message
1927
* @msg: Netlink message to dump into
1928
* @portid: Port making netlink request
1929
* @seq: Sequence number of netlink message
1930
* @bat_priv: The bat priv with all the mesh interface information
1931
* @if_outgoing: Limit dump to entries with this outgoing interface
1932
* @head: Bucket to be dumped
1933
* @idx_s: Number of entries to be skipped
1934
* @sub: Number of sub entries to be skipped
1935
*
1936
* Return: Error code, or 0 on success
1937
*/
1938
static int
1939
batadv_iv_ogm_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
1940
struct batadv_priv *bat_priv,
1941
struct batadv_hard_iface *if_outgoing,
1942
struct hlist_head *head, int *idx_s, int *sub)
1943
{
1944
struct batadv_orig_node *orig_node;
1945
int idx = 0;
1946
1947
rcu_read_lock();
1948
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
1949
if (idx++ < *idx_s)
1950
continue;
1951
1952
if (batadv_iv_ogm_orig_dump_entry(msg, portid, seq, bat_priv,
1953
if_outgoing, orig_node,
1954
sub)) {
1955
rcu_read_unlock();
1956
*idx_s = idx - 1;
1957
return -EMSGSIZE;
1958
}
1959
}
1960
rcu_read_unlock();
1961
1962
*idx_s = 0;
1963
*sub = 0;
1964
return 0;
1965
}
1966
1967
/**
1968
* batadv_iv_ogm_orig_dump() - Dump the originators into a message
1969
* @msg: Netlink message to dump into
1970
* @cb: Control block containing additional options
1971
* @bat_priv: The bat priv with all the mesh interface information
1972
* @if_outgoing: Limit dump to entries with this outgoing interface
1973
*/
1974
static void
1975
batadv_iv_ogm_orig_dump(struct sk_buff *msg, struct netlink_callback *cb,
1976
struct batadv_priv *bat_priv,
1977
struct batadv_hard_iface *if_outgoing)
1978
{
1979
struct batadv_hashtable *hash = bat_priv->orig_hash;
1980
struct hlist_head *head;
1981
int bucket = cb->args[0];
1982
int idx = cb->args[1];
1983
int sub = cb->args[2];
1984
int portid = NETLINK_CB(cb->skb).portid;
1985
1986
while (bucket < hash->size) {
1987
head = &hash->table[bucket];
1988
1989
if (batadv_iv_ogm_orig_dump_bucket(msg, portid,
1990
cb->nlh->nlmsg_seq,
1991
bat_priv, if_outgoing, head,
1992
&idx, &sub))
1993
break;
1994
1995
bucket++;
1996
}
1997
1998
cb->args[0] = bucket;
1999
cb->args[1] = idx;
2000
cb->args[2] = sub;
2001
}
2002
2003
/**
2004
* batadv_iv_ogm_neigh_diff() - calculate tq difference of two neighbors
2005
* @neigh1: the first neighbor object of the comparison
2006
* @if_outgoing1: outgoing interface for the first neighbor
2007
* @neigh2: the second neighbor object of the comparison
2008
* @if_outgoing2: outgoing interface for the second neighbor
2009
* @diff: pointer to integer receiving the calculated difference
2010
*
2011
* The content of *@diff is only valid when this function returns true.
2012
* It is less, equal to or greater than 0 if the metric via neigh1 is lower,
2013
* the same as or higher than the metric via neigh2
2014
*
2015
* Return: true when the difference could be calculated, false otherwise
2016
*/
2017
static bool batadv_iv_ogm_neigh_diff(struct batadv_neigh_node *neigh1,
2018
struct batadv_hard_iface *if_outgoing1,
2019
struct batadv_neigh_node *neigh2,
2020
struct batadv_hard_iface *if_outgoing2,
2021
int *diff)
2022
{
2023
struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo;
2024
u8 tq1, tq2;
2025
bool ret = true;
2026
2027
neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
2028
neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
2029
2030
if (!neigh1_ifinfo || !neigh2_ifinfo) {
2031
ret = false;
2032
goto out;
2033
}
2034
2035
tq1 = neigh1_ifinfo->bat_iv.tq_avg;
2036
tq2 = neigh2_ifinfo->bat_iv.tq_avg;
2037
*diff = (int)tq1 - (int)tq2;
2038
2039
out:
2040
batadv_neigh_ifinfo_put(neigh1_ifinfo);
2041
batadv_neigh_ifinfo_put(neigh2_ifinfo);
2042
2043
return ret;
2044
}
2045
2046
/**
2047
* batadv_iv_ogm_neigh_dump_neigh() - Dump a neighbour into a netlink message
2048
* @msg: Netlink message to dump into
2049
* @portid: Port making netlink request
2050
* @seq: Sequence number of netlink message
2051
* @hardif_neigh: Neighbour to be dumped
2052
*
2053
* Return: Error code, or 0 on success
2054
*/
2055
static int
2056
batadv_iv_ogm_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
2057
struct batadv_hardif_neigh_node *hardif_neigh)
2058
{
2059
void *hdr;
2060
unsigned int last_seen_msecs;
2061
2062
last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen);
2063
2064
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
2065
NLM_F_MULTI, BATADV_CMD_GET_NEIGHBORS);
2066
if (!hdr)
2067
return -ENOBUFS;
2068
2069
if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
2070
hardif_neigh->addr) ||
2071
nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
2072
hardif_neigh->if_incoming->net_dev->name) ||
2073
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
2074
hardif_neigh->if_incoming->net_dev->ifindex) ||
2075
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
2076
last_seen_msecs))
2077
goto nla_put_failure;
2078
2079
genlmsg_end(msg, hdr);
2080
return 0;
2081
2082
nla_put_failure:
2083
genlmsg_cancel(msg, hdr);
2084
return -EMSGSIZE;
2085
}
2086
2087
/**
2088
* batadv_iv_ogm_neigh_dump_hardif() - Dump the neighbours of a hard interface
2089
* into a message
2090
* @msg: Netlink message to dump into
2091
* @portid: Port making netlink request
2092
* @seq: Sequence number of netlink message
2093
* @bat_priv: The bat priv with all the mesh interface information
2094
* @hard_iface: Hard interface to dump the neighbours for
2095
* @idx_s: Number of entries to skip
2096
*
2097
* This function assumes the caller holds rcu_read_lock().
2098
*
2099
* Return: Error code, or 0 on success
2100
*/
2101
static int
2102
batadv_iv_ogm_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
2103
struct batadv_priv *bat_priv,
2104
struct batadv_hard_iface *hard_iface,
2105
int *idx_s)
2106
{
2107
struct batadv_hardif_neigh_node *hardif_neigh;
2108
int idx = 0;
2109
2110
hlist_for_each_entry_rcu(hardif_neigh,
2111
&hard_iface->neigh_list, list) {
2112
if (idx++ < *idx_s)
2113
continue;
2114
2115
if (batadv_iv_ogm_neigh_dump_neigh(msg, portid, seq,
2116
hardif_neigh)) {
2117
*idx_s = idx - 1;
2118
return -EMSGSIZE;
2119
}
2120
}
2121
2122
*idx_s = 0;
2123
return 0;
2124
}
2125
2126
/**
2127
* batadv_iv_ogm_neigh_dump() - Dump the neighbours into a message
2128
* @msg: Netlink message to dump into
2129
* @cb: Control block containing additional options
2130
* @bat_priv: The bat priv with all the mesh interface information
2131
* @single_hardif: Limit dump to this hard interface
2132
*/
2133
static void
2134
batadv_iv_ogm_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb,
2135
struct batadv_priv *bat_priv,
2136
struct batadv_hard_iface *single_hardif)
2137
{
2138
struct batadv_hard_iface *hard_iface;
2139
struct list_head *iter;
2140
int i_hardif = 0;
2141
int i_hardif_s = cb->args[0];
2142
int idx = cb->args[1];
2143
int portid = NETLINK_CB(cb->skb).portid;
2144
2145
rcu_read_lock();
2146
if (single_hardif) {
2147
if (i_hardif_s == 0) {
2148
if (batadv_iv_ogm_neigh_dump_hardif(msg, portid,
2149
cb->nlh->nlmsg_seq,
2150
bat_priv,
2151
single_hardif,
2152
&idx) == 0)
2153
i_hardif++;
2154
}
2155
} else {
2156
netdev_for_each_lower_private_rcu(bat_priv->mesh_iface, hard_iface, iter) {
2157
if (i_hardif++ < i_hardif_s)
2158
continue;
2159
2160
if (batadv_iv_ogm_neigh_dump_hardif(msg, portid,
2161
cb->nlh->nlmsg_seq,
2162
bat_priv,
2163
hard_iface, &idx)) {
2164
i_hardif--;
2165
break;
2166
}
2167
}
2168
}
2169
rcu_read_unlock();
2170
2171
cb->args[0] = i_hardif;
2172
cb->args[1] = idx;
2173
}
2174
2175
/**
2176
* batadv_iv_ogm_neigh_cmp() - compare the metrics of two neighbors
2177
* @neigh1: the first neighbor object of the comparison
2178
* @if_outgoing1: outgoing interface for the first neighbor
2179
* @neigh2: the second neighbor object of the comparison
2180
* @if_outgoing2: outgoing interface for the second neighbor
2181
*
2182
* Return: a value less, equal to or greater than 0 if the metric via neigh1 is
2183
* lower, the same as or higher than the metric via neigh2
2184
*/
2185
static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
2186
struct batadv_hard_iface *if_outgoing1,
2187
struct batadv_neigh_node *neigh2,
2188
struct batadv_hard_iface *if_outgoing2)
2189
{
2190
bool ret;
2191
int diff;
2192
2193
ret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2,
2194
if_outgoing2, &diff);
2195
if (!ret)
2196
return 0;
2197
2198
return diff;
2199
}
2200
2201
/**
2202
* batadv_iv_ogm_neigh_is_sob() - check if neigh1 is similarly good or better
2203
* than neigh2 from the metric prospective
2204
* @neigh1: the first neighbor object of the comparison
2205
* @if_outgoing1: outgoing interface for the first neighbor
2206
* @neigh2: the second neighbor object of the comparison
2207
* @if_outgoing2: outgoing interface for the second neighbor
2208
*
2209
* Return: true if the metric via neigh1 is equally good or better than
2210
* the metric via neigh2, false otherwise.
2211
*/
2212
static bool
2213
batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
2214
struct batadv_hard_iface *if_outgoing1,
2215
struct batadv_neigh_node *neigh2,
2216
struct batadv_hard_iface *if_outgoing2)
2217
{
2218
bool ret;
2219
int diff;
2220
2221
ret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2,
2222
if_outgoing2, &diff);
2223
if (!ret)
2224
return false;
2225
2226
ret = diff > -BATADV_TQ_SIMILARITY_THRESHOLD;
2227
return ret;
2228
}
2229
2230
static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface)
2231
{
2232
/* begin scheduling originator messages on that interface */
2233
batadv_iv_ogm_schedule(hard_iface);
2234
}
2235
2236
/**
2237
* batadv_iv_init_sel_class() - initialize GW selection class
2238
* @bat_priv: the bat priv with all the mesh interface information
2239
*/
2240
static void batadv_iv_init_sel_class(struct batadv_priv *bat_priv)
2241
{
2242
/* set default TQ difference threshold to 20 */
2243
atomic_set(&bat_priv->gw.sel_class, 20);
2244
}
2245
2246
static struct batadv_gw_node *
2247
batadv_iv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
2248
{
2249
struct batadv_neigh_node *router;
2250
struct batadv_neigh_ifinfo *router_ifinfo;
2251
struct batadv_gw_node *gw_node, *curr_gw = NULL;
2252
u64 max_gw_factor = 0;
2253
u64 tmp_gw_factor = 0;
2254
u8 max_tq = 0;
2255
u8 tq_avg;
2256
struct batadv_orig_node *orig_node;
2257
2258
rcu_read_lock();
2259
hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
2260
orig_node = gw_node->orig_node;
2261
router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
2262
if (!router)
2263
continue;
2264
2265
router_ifinfo = batadv_neigh_ifinfo_get(router,
2266
BATADV_IF_DEFAULT);
2267
if (!router_ifinfo)
2268
goto next;
2269
2270
if (!kref_get_unless_zero(&gw_node->refcount))
2271
goto next;
2272
2273
tq_avg = router_ifinfo->bat_iv.tq_avg;
2274
2275
switch (atomic_read(&bat_priv->gw.sel_class)) {
2276
case 1: /* fast connection */
2277
tmp_gw_factor = tq_avg * tq_avg;
2278
tmp_gw_factor *= gw_node->bandwidth_down;
2279
tmp_gw_factor *= 100 * 100;
2280
tmp_gw_factor >>= 18;
2281
2282
if (tmp_gw_factor > max_gw_factor ||
2283
(tmp_gw_factor == max_gw_factor &&
2284
tq_avg > max_tq)) {
2285
batadv_gw_node_put(curr_gw);
2286
curr_gw = gw_node;
2287
kref_get(&curr_gw->refcount);
2288
}
2289
break;
2290
2291
default: /* 2: stable connection (use best statistic)
2292
* 3: fast-switch (use best statistic but change as
2293
* soon as a better gateway appears)
2294
* XX: late-switch (use best statistic but change as
2295
* soon as a better gateway appears which has
2296
* $routing_class more tq points)
2297
*/
2298
if (tq_avg > max_tq) {
2299
batadv_gw_node_put(curr_gw);
2300
curr_gw = gw_node;
2301
kref_get(&curr_gw->refcount);
2302
}
2303
break;
2304
}
2305
2306
if (tq_avg > max_tq)
2307
max_tq = tq_avg;
2308
2309
if (tmp_gw_factor > max_gw_factor)
2310
max_gw_factor = tmp_gw_factor;
2311
2312
batadv_gw_node_put(gw_node);
2313
2314
next:
2315
batadv_neigh_node_put(router);
2316
batadv_neigh_ifinfo_put(router_ifinfo);
2317
}
2318
rcu_read_unlock();
2319
2320
return curr_gw;
2321
}
2322
2323
static bool batadv_iv_gw_is_eligible(struct batadv_priv *bat_priv,
2324
struct batadv_orig_node *curr_gw_orig,
2325
struct batadv_orig_node *orig_node)
2326
{
2327
struct batadv_neigh_ifinfo *router_orig_ifinfo = NULL;
2328
struct batadv_neigh_ifinfo *router_gw_ifinfo = NULL;
2329
struct batadv_neigh_node *router_gw = NULL;
2330
struct batadv_neigh_node *router_orig = NULL;
2331
u8 gw_tq_avg, orig_tq_avg;
2332
bool ret = false;
2333
2334
/* dynamic re-election is performed only on fast or late switch */
2335
if (atomic_read(&bat_priv->gw.sel_class) <= 2)
2336
return false;
2337
2338
router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT);
2339
if (!router_gw) {
2340
ret = true;
2341
goto out;
2342
}
2343
2344
router_gw_ifinfo = batadv_neigh_ifinfo_get(router_gw,
2345
BATADV_IF_DEFAULT);
2346
if (!router_gw_ifinfo) {
2347
ret = true;
2348
goto out;
2349
}
2350
2351
router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
2352
if (!router_orig)
2353
goto out;
2354
2355
router_orig_ifinfo = batadv_neigh_ifinfo_get(router_orig,
2356
BATADV_IF_DEFAULT);
2357
if (!router_orig_ifinfo)
2358
goto out;
2359
2360
gw_tq_avg = router_gw_ifinfo->bat_iv.tq_avg;
2361
orig_tq_avg = router_orig_ifinfo->bat_iv.tq_avg;
2362
2363
/* the TQ value has to be better */
2364
if (orig_tq_avg < gw_tq_avg)
2365
goto out;
2366
2367
/* if the routing class is greater than 3 the value tells us how much
2368
* greater the TQ value of the new gateway must be
2369
*/
2370
if ((atomic_read(&bat_priv->gw.sel_class) > 3) &&
2371
(orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw.sel_class)))
2372
goto out;
2373
2374
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
2375
"Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n",
2376
gw_tq_avg, orig_tq_avg);
2377
2378
ret = true;
2379
out:
2380
batadv_neigh_ifinfo_put(router_gw_ifinfo);
2381
batadv_neigh_ifinfo_put(router_orig_ifinfo);
2382
batadv_neigh_node_put(router_gw);
2383
batadv_neigh_node_put(router_orig);
2384
2385
return ret;
2386
}
2387
2388
/**
2389
* batadv_iv_gw_dump_entry() - Dump a gateway into a message
2390
* @msg: Netlink message to dump into
2391
* @portid: Port making netlink request
2392
* @cb: Control block containing additional options
2393
* @bat_priv: The bat priv with all the mesh interface information
2394
* @gw_node: Gateway to be dumped
2395
*
2396
* Return: Error code, or 0 on success
2397
*/
2398
static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid,
2399
struct netlink_callback *cb,
2400
struct batadv_priv *bat_priv,
2401
struct batadv_gw_node *gw_node)
2402
{
2403
struct batadv_neigh_ifinfo *router_ifinfo = NULL;
2404
struct batadv_neigh_node *router;
2405
struct batadv_gw_node *curr_gw = NULL;
2406
int ret = 0;
2407
void *hdr;
2408
2409
router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
2410
if (!router)
2411
goto out;
2412
2413
router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
2414
if (!router_ifinfo)
2415
goto out;
2416
2417
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
2418
2419
hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
2420
&batadv_netlink_family, NLM_F_MULTI,
2421
BATADV_CMD_GET_GATEWAYS);
2422
if (!hdr) {
2423
ret = -ENOBUFS;
2424
goto out;
2425
}
2426
2427
genl_dump_check_consistent(cb, hdr);
2428
2429
ret = -EMSGSIZE;
2430
2431
if (curr_gw == gw_node)
2432
if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) {
2433
genlmsg_cancel(msg, hdr);
2434
goto out;
2435
}
2436
2437
if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
2438
gw_node->orig_node->orig) ||
2439
nla_put_u8(msg, BATADV_ATTR_TQ, router_ifinfo->bat_iv.tq_avg) ||
2440
nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN,
2441
router->addr) ||
2442
nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
2443
router->if_incoming->net_dev->name) ||
2444
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
2445
router->if_incoming->net_dev->ifindex) ||
2446
nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
2447
gw_node->bandwidth_down) ||
2448
nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP,
2449
gw_node->bandwidth_up)) {
2450
genlmsg_cancel(msg, hdr);
2451
goto out;
2452
}
2453
2454
genlmsg_end(msg, hdr);
2455
ret = 0;
2456
2457
out:
2458
batadv_gw_node_put(curr_gw);
2459
batadv_neigh_ifinfo_put(router_ifinfo);
2460
batadv_neigh_node_put(router);
2461
return ret;
2462
}
2463
2464
/**
2465
* batadv_iv_gw_dump() - Dump gateways into a message
2466
* @msg: Netlink message to dump into
2467
* @cb: Control block containing additional options
2468
* @bat_priv: The bat priv with all the mesh interface information
2469
*/
2470
static void batadv_iv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
2471
struct batadv_priv *bat_priv)
2472
{
2473
int portid = NETLINK_CB(cb->skb).portid;
2474
struct batadv_gw_node *gw_node;
2475
int idx_skip = cb->args[0];
2476
int idx = 0;
2477
2478
spin_lock_bh(&bat_priv->gw.list_lock);
2479
cb->seq = bat_priv->gw.generation << 1 | 1;
2480
2481
hlist_for_each_entry(gw_node, &bat_priv->gw.gateway_list, list) {
2482
if (idx++ < idx_skip)
2483
continue;
2484
2485
if (batadv_iv_gw_dump_entry(msg, portid, cb, bat_priv,
2486
gw_node)) {
2487
idx_skip = idx - 1;
2488
goto unlock;
2489
}
2490
}
2491
2492
idx_skip = idx;
2493
unlock:
2494
spin_unlock_bh(&bat_priv->gw.list_lock);
2495
2496
cb->args[0] = idx_skip;
2497
}
2498
2499
static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
2500
.name = "BATMAN_IV",
2501
.iface = {
2502
.enable = batadv_iv_ogm_iface_enable,
2503
.enabled = batadv_iv_iface_enabled,
2504
.disable = batadv_iv_ogm_iface_disable,
2505
.update_mac = batadv_iv_ogm_iface_update_mac,
2506
.primary_set = batadv_iv_ogm_primary_iface_set,
2507
},
2508
.neigh = {
2509
.cmp = batadv_iv_ogm_neigh_cmp,
2510
.is_similar_or_better = batadv_iv_ogm_neigh_is_sob,
2511
.dump = batadv_iv_ogm_neigh_dump,
2512
},
2513
.orig = {
2514
.dump = batadv_iv_ogm_orig_dump,
2515
},
2516
.gw = {
2517
.init_sel_class = batadv_iv_init_sel_class,
2518
.sel_class_max = BATADV_TQ_MAX_VALUE,
2519
.get_best_gw_node = batadv_iv_gw_get_best_gw_node,
2520
.is_eligible = batadv_iv_gw_is_eligible,
2521
.dump = batadv_iv_gw_dump,
2522
},
2523
};
2524
2525
/**
2526
* batadv_iv_init() - B.A.T.M.A.N. IV initialization function
2527
*
2528
* Return: 0 on success or negative error number in case of failure
2529
*/
2530
int __init batadv_iv_init(void)
2531
{
2532
int ret;
2533
2534
/* batman originator packet */
2535
ret = batadv_recv_handler_register(BATADV_IV_OGM,
2536
batadv_iv_ogm_receive);
2537
if (ret < 0)
2538
goto out;
2539
2540
ret = batadv_algo_register(&batadv_batman_iv);
2541
if (ret < 0)
2542
goto handler_unregister;
2543
2544
goto out;
2545
2546
handler_unregister:
2547
batadv_recv_handler_unregister(BATADV_IV_OGM);
2548
out:
2549
return ret;
2550
}
2551
2552