batman-adv: add infrastructure to change routing algorithm at runtime
[deliverable/linux.git] / net / batman-adv / bat_iv_ogm.c
CommitLineData
fc957275
ML
1/*
2 * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "bat_ogm.h"
24#include "translation-table.h"
25#include "ring_buffer.h"
26#include "originator.h"
27#include "routing.h"
28#include "gateway_common.h"
29#include "gateway_client.h"
30#include "hard-interface.h"
31#include "send.h"
1c280471 32#include "bat_algo.h"
fc957275 33
d0b9fd89
ML
34void bat_ogm_init(struct hard_iface *hard_iface)
35{
36 struct batman_ogm_packet *batman_ogm_packet;
37
38 hard_iface->packet_len = BATMAN_OGM_LEN;
39 hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC);
40
41 batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
76543d14
SE
42 batman_ogm_packet->header.packet_type = BAT_OGM;
43 batman_ogm_packet->header.version = COMPAT_VERSION;
44 batman_ogm_packet->header.ttl = 2;
d0b9fd89 45 batman_ogm_packet->flags = NO_FLAGS;
d0b9fd89
ML
46 batman_ogm_packet->tq = TQ_MAX_VALUE;
47 batman_ogm_packet->tt_num_changes = 0;
48 batman_ogm_packet->ttvn = 0;
49}
50
51void bat_ogm_init_primary(struct hard_iface *hard_iface)
52{
53 struct batman_ogm_packet *batman_ogm_packet;
54
55 batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
56 batman_ogm_packet->flags = PRIMARIES_FIRST_HOP;
76543d14 57 batman_ogm_packet->header.ttl = TTL;
d0b9fd89
ML
58}
59
60void bat_ogm_update_mac(struct hard_iface *hard_iface)
61{
62 struct batman_ogm_packet *batman_ogm_packet;
63
64 batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
65 memcpy(batman_ogm_packet->orig,
66 hard_iface->net_dev->dev_addr, ETH_ALEN);
67 memcpy(batman_ogm_packet->prev_sender,
68 hard_iface->net_dev->dev_addr, ETH_ALEN);
69}
70
b9dacc52
ML
71/* when do we schedule our own ogm to be sent */
72static unsigned long bat_ogm_emit_send_time(const struct bat_priv *bat_priv)
73{
74 return jiffies + msecs_to_jiffies(
75 atomic_read(&bat_priv->orig_interval) -
76 JITTER + (random32() % 2*JITTER));
77}
78
79/* when do we schedule a ogm packet to be sent */
80static unsigned long bat_ogm_fwd_send_time(void)
81{
82 return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
83}
84
85/* apply hop penalty for a normal link */
86static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)
87{
88 int hop_penalty = atomic_read(&bat_priv->hop_penalty);
89 return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);
90}
91
fc957275
ML
92/* is there another aggregated packet here? */
93static int bat_ogm_aggr_packet(int buff_pos, int packet_len,
94 int tt_num_changes)
95{
96 int next_buff_pos = buff_pos + BATMAN_OGM_LEN + tt_len(tt_num_changes);
97
98 return (next_buff_pos <= packet_len) &&
99 (next_buff_pos <= MAX_AGGREGATION_BYTES);
100}
101
b9dacc52
ML
102/* send a batman ogm to a given interface */
103static void bat_ogm_send_to_if(struct forw_packet *forw_packet,
104 struct hard_iface *hard_iface)
105{
106 struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
107 char *fwd_str;
108 uint8_t packet_num;
109 int16_t buff_pos;
110 struct batman_ogm_packet *batman_ogm_packet;
111 struct sk_buff *skb;
112
113 if (hard_iface->if_status != IF_ACTIVE)
114 return;
115
116 packet_num = 0;
117 buff_pos = 0;
118 batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data;
119
120 /* adjust all flags and log packets */
121 while (bat_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
122 batman_ogm_packet->tt_num_changes)) {
123
124 /* we might have aggregated direct link packets with an
125 * ordinary base packet */
126 if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
127 (forw_packet->if_incoming == hard_iface))
128 batman_ogm_packet->flags |= DIRECTLINK;
129 else
130 batman_ogm_packet->flags &= ~DIRECTLINK;
131
132 fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
133 "Sending own" :
134 "Forwarding"));
135 bat_dbg(DBG_BATMAN, bat_priv,
136 "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
137 " IDF %s, ttvn %d) on interface %s [%pM]\n",
138 fwd_str, (packet_num > 0 ? "aggregated " : ""),
139 batman_ogm_packet->orig,
140 ntohl(batman_ogm_packet->seqno),
76543d14 141 batman_ogm_packet->tq, batman_ogm_packet->header.ttl,
b9dacc52
ML
142 (batman_ogm_packet->flags & DIRECTLINK ?
143 "on" : "off"),
144 batman_ogm_packet->ttvn, hard_iface->net_dev->name,
145 hard_iface->net_dev->dev_addr);
146
147 buff_pos += BATMAN_OGM_LEN +
148 tt_len(batman_ogm_packet->tt_num_changes);
149 packet_num++;
150 batman_ogm_packet = (struct batman_ogm_packet *)
151 (forw_packet->skb->data + buff_pos);
152 }
153
154 /* create clone because function is called more than once */
155 skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
156 if (skb)
157 send_skb_packet(skb, hard_iface, broadcast_addr);
158}
159
160/* send a batman ogm packet */
161void bat_ogm_emit(struct forw_packet *forw_packet)
162{
163 struct hard_iface *hard_iface;
164 struct net_device *soft_iface;
165 struct bat_priv *bat_priv;
166 struct hard_iface *primary_if = NULL;
167 struct batman_ogm_packet *batman_ogm_packet;
168 unsigned char directlink;
169
170 batman_ogm_packet = (struct batman_ogm_packet *)
171 (forw_packet->skb->data);
172 directlink = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);
173
174 if (!forw_packet->if_incoming) {
175 pr_err("Error - can't forward packet: incoming iface not "
176 "specified\n");
177 goto out;
178 }
179
180 soft_iface = forw_packet->if_incoming->soft_iface;
181 bat_priv = netdev_priv(soft_iface);
182
183 if (forw_packet->if_incoming->if_status != IF_ACTIVE)
184 goto out;
185
186 primary_if = primary_if_get_selected(bat_priv);
187 if (!primary_if)
188 goto out;
189
190 /* multihomed peer assumed */
191 /* non-primary OGMs are only broadcasted on their interface */
76543d14 192 if ((directlink && (batman_ogm_packet->header.ttl == 1)) ||
b9dacc52
ML
193 (forw_packet->own && (forw_packet->if_incoming != primary_if))) {
194
195 /* FIXME: what about aggregated packets ? */
196 bat_dbg(DBG_BATMAN, bat_priv,
197 "%s packet (originator %pM, seqno %d, TTL %d) "
198 "on interface %s [%pM]\n",
199 (forw_packet->own ? "Sending own" : "Forwarding"),
200 batman_ogm_packet->orig,
201 ntohl(batman_ogm_packet->seqno),
76543d14 202 batman_ogm_packet->header.ttl,
b9dacc52
ML
203 forw_packet->if_incoming->net_dev->name,
204 forw_packet->if_incoming->net_dev->dev_addr);
205
206 /* skb is only used once and than forw_packet is free'd */
207 send_skb_packet(forw_packet->skb, forw_packet->if_incoming,
208 broadcast_addr);
209 forw_packet->skb = NULL;
210
211 goto out;
212 }
213
214 /* broadcast on every interface */
215 rcu_read_lock();
216 list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
217 if (hard_iface->soft_iface != soft_iface)
218 continue;
219
220 bat_ogm_send_to_if(forw_packet, hard_iface);
221 }
222 rcu_read_unlock();
223
224out:
225 if (primary_if)
226 hardif_free_ref(primary_if);
227}
228
229/* return true if new_packet can be aggregated with forw_packet */
230static bool bat_ogm_can_aggregate(const struct batman_ogm_packet
231 *new_batman_ogm_packet,
232 struct bat_priv *bat_priv,
233 int packet_len, unsigned long send_time,
234 bool directlink,
235 const struct hard_iface *if_incoming,
236 const struct forw_packet *forw_packet)
237{
238 struct batman_ogm_packet *batman_ogm_packet;
239 int aggregated_bytes = forw_packet->packet_len + packet_len;
240 struct hard_iface *primary_if = NULL;
241 bool res = false;
242
243 batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data;
244
245 /**
246 * we can aggregate the current packet to this aggregated packet
247 * if:
248 *
249 * - the send time is within our MAX_AGGREGATION_MS time
250 * - the resulting packet wont be bigger than
251 * MAX_AGGREGATION_BYTES
252 */
253
254 if (time_before(send_time, forw_packet->send_time) &&
255 time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
256 forw_packet->send_time) &&
257 (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
258
259 /**
260 * check aggregation compatibility
261 * -> direct link packets are broadcasted on
262 * their interface only
263 * -> aggregate packet if the current packet is
264 * a "global" packet as well as the base
265 * packet
266 */
267
268 primary_if = primary_if_get_selected(bat_priv);
269 if (!primary_if)
270 goto out;
271
272 /* packets without direct link flag and high TTL
273 * are flooded through the net */
274 if ((!directlink) &&
275 (!(batman_ogm_packet->flags & DIRECTLINK)) &&
76543d14 276 (batman_ogm_packet->header.ttl != 1) &&
b9dacc52
ML
277
278 /* own packets originating non-primary
279 * interfaces leave only that interface */
280 ((!forw_packet->own) ||
281 (forw_packet->if_incoming == primary_if))) {
282 res = true;
283 goto out;
284 }
285
286 /* if the incoming packet is sent via this one
287 * interface only - we still can aggregate */
288 if ((directlink) &&
76543d14 289 (new_batman_ogm_packet->header.ttl == 1) &&
b9dacc52
ML
290 (forw_packet->if_incoming == if_incoming) &&
291
292 /* packets from direct neighbors or
293 * own secondary interface packets
294 * (= secondary interface packets in general) */
295 (batman_ogm_packet->flags & DIRECTLINK ||
296 (forw_packet->own &&
297 forw_packet->if_incoming != primary_if))) {
298 res = true;
299 goto out;
300 }
301 }
302
303out:
304 if (primary_if)
305 hardif_free_ref(primary_if);
306 return res;
307}
308
309/* create a new aggregated packet and add this packet to it */
310static void bat_ogm_aggregate_new(const unsigned char *packet_buff,
311 int packet_len, unsigned long send_time,
312 bool direct_link,
313 struct hard_iface *if_incoming,
314 int own_packet)
315{
316 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
317 struct forw_packet *forw_packet_aggr;
318 unsigned char *skb_buff;
319
320 if (!atomic_inc_not_zero(&if_incoming->refcount))
321 return;
322
323 /* own packet should always be scheduled */
324 if (!own_packet) {
325 if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
326 bat_dbg(DBG_BATMAN, bat_priv,
327 "batman packet queue full\n");
328 goto out;
329 }
330 }
331
332 forw_packet_aggr = kmalloc(sizeof(*forw_packet_aggr), GFP_ATOMIC);
333 if (!forw_packet_aggr) {
334 if (!own_packet)
335 atomic_inc(&bat_priv->batman_queue_left);
336 goto out;
337 }
338
339 if ((atomic_read(&bat_priv->aggregated_ogms)) &&
340 (packet_len < MAX_AGGREGATION_BYTES))
341 forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
342 sizeof(struct ethhdr));
343 else
344 forw_packet_aggr->skb = dev_alloc_skb(packet_len +
345 sizeof(struct ethhdr));
346
347 if (!forw_packet_aggr->skb) {
348 if (!own_packet)
349 atomic_inc(&bat_priv->batman_queue_left);
350 kfree(forw_packet_aggr);
351 goto out;
352 }
353 skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
354
355 INIT_HLIST_NODE(&forw_packet_aggr->list);
356
357 skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
358 forw_packet_aggr->packet_len = packet_len;
359 memcpy(skb_buff, packet_buff, packet_len);
360
361 forw_packet_aggr->own = own_packet;
362 forw_packet_aggr->if_incoming = if_incoming;
363 forw_packet_aggr->num_packets = 0;
364 forw_packet_aggr->direct_link_flags = NO_FLAGS;
365 forw_packet_aggr->send_time = send_time;
366
367 /* save packet direct link flag status */
368 if (direct_link)
369 forw_packet_aggr->direct_link_flags |= 1;
370
371 /* add new packet to packet list */
372 spin_lock_bh(&bat_priv->forw_bat_list_lock);
373 hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
374 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
375
376 /* start timer for this packet */
377 INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
378 send_outstanding_bat_ogm_packet);
379 queue_delayed_work(bat_event_workqueue,
380 &forw_packet_aggr->delayed_work,
381 send_time - jiffies);
382
383 return;
384out:
385 hardif_free_ref(if_incoming);
386}
387
388/* aggregate a new packet into the existing ogm packet */
389static void bat_ogm_aggregate(struct forw_packet *forw_packet_aggr,
390 const unsigned char *packet_buff,
391 int packet_len, bool direct_link)
392{
393 unsigned char *skb_buff;
394
395 skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
396 memcpy(skb_buff, packet_buff, packet_len);
397 forw_packet_aggr->packet_len += packet_len;
398 forw_packet_aggr->num_packets++;
399
400 /* save packet direct link flag status */
401 if (direct_link)
402 forw_packet_aggr->direct_link_flags |=
403 (1 << forw_packet_aggr->num_packets);
404}
405
406static void bat_ogm_queue_add(struct bat_priv *bat_priv,
407 unsigned char *packet_buff,
408 int packet_len, struct hard_iface *if_incoming,
409 int own_packet, unsigned long send_time)
410{
411 /**
412 * _aggr -> pointer to the packet we want to aggregate with
413 * _pos -> pointer to the position in the queue
414 */
415 struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
416 struct hlist_node *tmp_node;
417 struct batman_ogm_packet *batman_ogm_packet;
418 bool direct_link;
419
420 batman_ogm_packet = (struct batman_ogm_packet *)packet_buff;
421 direct_link = batman_ogm_packet->flags & DIRECTLINK ? 1 : 0;
422
423 /* find position for the packet in the forward queue */
424 spin_lock_bh(&bat_priv->forw_bat_list_lock);
425 /* own packets are not to be aggregated */
426 if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
427 hlist_for_each_entry(forw_packet_pos, tmp_node,
428 &bat_priv->forw_bat_list, list) {
429 if (bat_ogm_can_aggregate(batman_ogm_packet,
430 bat_priv, packet_len,
431 send_time, direct_link,
432 if_incoming,
433 forw_packet_pos)) {
434 forw_packet_aggr = forw_packet_pos;
435 break;
436 }
437 }
438 }
439
440 /* nothing to aggregate with - either aggregation disabled or no
441 * suitable aggregation packet found */
442 if (!forw_packet_aggr) {
443 /* the following section can run without the lock */
444 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
445
446 /**
447 * if we could not aggregate this packet with one of the others
448 * we hold it back for a while, so that it might be aggregated
449 * later on
450 */
451 if ((!own_packet) &&
452 (atomic_read(&bat_priv->aggregated_ogms)))
453 send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
454
455 bat_ogm_aggregate_new(packet_buff, packet_len,
456 send_time, direct_link,
457 if_incoming, own_packet);
458 } else {
459 bat_ogm_aggregate(forw_packet_aggr, packet_buff, packet_len,
460 direct_link);
461 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
462 }
463}
464
465static void bat_ogm_forward(struct orig_node *orig_node,
466 const struct ethhdr *ethhdr,
467 struct batman_ogm_packet *batman_ogm_packet,
468 int directlink, struct hard_iface *if_incoming)
469{
470 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
471 struct neigh_node *router;
472 uint8_t in_tq, in_ttl, tq_avg = 0;
473 uint8_t tt_num_changes;
474
76543d14 475 if (batman_ogm_packet->header.ttl <= 1) {
b9dacc52
ML
476 bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
477 return;
478 }
479
480 router = orig_node_get_router(orig_node);
481
482 in_tq = batman_ogm_packet->tq;
76543d14 483 in_ttl = batman_ogm_packet->header.ttl;
b9dacc52
ML
484 tt_num_changes = batman_ogm_packet->tt_num_changes;
485
76543d14 486 batman_ogm_packet->header.ttl--;
b9dacc52
ML
487 memcpy(batman_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
488
489 /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
490 * of our best tq value */
491 if (router && router->tq_avg != 0) {
492
493 /* rebroadcast ogm of best ranking neighbor as is */
494 if (!compare_eth(router->addr, ethhdr->h_source)) {
495 batman_ogm_packet->tq = router->tq_avg;
496
497 if (router->last_ttl)
76543d14
SE
498 batman_ogm_packet->header.ttl =
499 router->last_ttl - 1;
b9dacc52
ML
500 }
501
502 tq_avg = router->tq_avg;
503 }
504
505 if (router)
506 neigh_node_free_ref(router);
507
508 /* apply hop penalty */
509 batman_ogm_packet->tq = hop_penalty(batman_ogm_packet->tq, bat_priv);
510
511 bat_dbg(DBG_BATMAN, bat_priv,
512 "Forwarding packet: tq_orig: %i, tq_avg: %i, "
513 "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",
514 in_tq, tq_avg, batman_ogm_packet->tq, in_ttl - 1,
76543d14 515 batman_ogm_packet->header.ttl);
b9dacc52
ML
516
517 batman_ogm_packet->seqno = htonl(batman_ogm_packet->seqno);
518 batman_ogm_packet->tt_crc = htons(batman_ogm_packet->tt_crc);
519
520 /* switch of primaries first hop flag when forwarding */
521 batman_ogm_packet->flags &= ~PRIMARIES_FIRST_HOP;
522 if (directlink)
523 batman_ogm_packet->flags |= DIRECTLINK;
524 else
525 batman_ogm_packet->flags &= ~DIRECTLINK;
526
527 bat_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet,
528 BATMAN_OGM_LEN + tt_len(tt_num_changes),
529 if_incoming, 0, bat_ogm_fwd_send_time());
530}
531
532void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes)
533{
534 struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
535 struct batman_ogm_packet *batman_ogm_packet;
536 struct hard_iface *primary_if;
537 int vis_server;
538
539 vis_server = atomic_read(&bat_priv->vis_mode);
540 primary_if = primary_if_get_selected(bat_priv);
541
542 batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
543
544 /* change sequence number to network order */
545 batman_ogm_packet->seqno =
546 htonl((uint32_t)atomic_read(&hard_iface->seqno));
547
548 batman_ogm_packet->ttvn = atomic_read(&bat_priv->ttvn);
549 batman_ogm_packet->tt_crc = htons((uint16_t)
550 atomic_read(&bat_priv->tt_crc));
551 if (tt_num_changes >= 0)
552 batman_ogm_packet->tt_num_changes = tt_num_changes;
553
554 if (vis_server == VIS_TYPE_SERVER_SYNC)
555 batman_ogm_packet->flags |= VIS_SERVER;
556 else
557 batman_ogm_packet->flags &= ~VIS_SERVER;
558
559 if ((hard_iface == primary_if) &&
560 (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))
561 batman_ogm_packet->gw_flags =
562 (uint8_t)atomic_read(&bat_priv->gw_bandwidth);
563 else
564 batman_ogm_packet->gw_flags = NO_FLAGS;
565
566 atomic_inc(&hard_iface->seqno);
567
568 slide_own_bcast_window(hard_iface);
569 bat_ogm_queue_add(bat_priv, hard_iface->packet_buff,
570 hard_iface->packet_len, hard_iface, 1,
571 bat_ogm_emit_send_time(bat_priv));
572
573 if (primary_if)
574 hardif_free_ref(primary_if);
575}
576
fc957275
ML
577static void bat_ogm_orig_update(struct bat_priv *bat_priv,
578 struct orig_node *orig_node,
579 const struct ethhdr *ethhdr,
580 const struct batman_ogm_packet
581 *batman_ogm_packet,
582 struct hard_iface *if_incoming,
583 const unsigned char *tt_buff, int is_duplicate)
584{
585 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
586 struct neigh_node *router = NULL;
587 struct orig_node *orig_node_tmp;
588 struct hlist_node *node;
589 uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
590
591 bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
592 "Searching and updating originator entry of received packet\n");
593
594 rcu_read_lock();
595 hlist_for_each_entry_rcu(tmp_neigh_node, node,
596 &orig_node->neigh_list, list) {
597 if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
598 (tmp_neigh_node->if_incoming == if_incoming) &&
599 atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
600 if (neigh_node)
601 neigh_node_free_ref(neigh_node);
602 neigh_node = tmp_neigh_node;
603 continue;
604 }
605
606 if (is_duplicate)
607 continue;
608
609 spin_lock_bh(&tmp_neigh_node->tq_lock);
610 ring_buffer_set(tmp_neigh_node->tq_recv,
611 &tmp_neigh_node->tq_index, 0);
612 tmp_neigh_node->tq_avg =
613 ring_buffer_avg(tmp_neigh_node->tq_recv);
614 spin_unlock_bh(&tmp_neigh_node->tq_lock);
615 }
616
617 if (!neigh_node) {
618 struct orig_node *orig_tmp;
619
620 orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
621 if (!orig_tmp)
622 goto unlock;
623
624 neigh_node = create_neighbor(orig_node, orig_tmp,
625 ethhdr->h_source, if_incoming);
626
627 orig_node_free_ref(orig_tmp);
628 if (!neigh_node)
629 goto unlock;
630 } else
631 bat_dbg(DBG_BATMAN, bat_priv,
632 "Updating existing last-hop neighbor of originator\n");
633
634 rcu_read_unlock();
635
636 orig_node->flags = batman_ogm_packet->flags;
637 neigh_node->last_valid = jiffies;
638
639 spin_lock_bh(&neigh_node->tq_lock);
640 ring_buffer_set(neigh_node->tq_recv,
641 &neigh_node->tq_index,
642 batman_ogm_packet->tq);
643 neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
644 spin_unlock_bh(&neigh_node->tq_lock);
645
646 if (!is_duplicate) {
76543d14
SE
647 orig_node->last_ttl = batman_ogm_packet->header.ttl;
648 neigh_node->last_ttl = batman_ogm_packet->header.ttl;
fc957275
ML
649 }
650
651 bonding_candidate_add(orig_node, neigh_node);
652
653 /* if this neighbor already is our next hop there is nothing
654 * to change */
655 router = orig_node_get_router(orig_node);
656 if (router == neigh_node)
657 goto update_tt;
658
659 /* if this neighbor does not offer a better TQ we won't consider it */
660 if (router && (router->tq_avg > neigh_node->tq_avg))
661 goto update_tt;
662
663 /* if the TQ is the same and the link not more symmetric we
664 * won't consider it either */
665 if (router && (neigh_node->tq_avg == router->tq_avg)) {
666 orig_node_tmp = router->orig_node;
667 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
668 bcast_own_sum_orig =
669 orig_node_tmp->bcast_own_sum[if_incoming->if_num];
670 spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
671
672 orig_node_tmp = neigh_node->orig_node;
673 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
674 bcast_own_sum_neigh =
675 orig_node_tmp->bcast_own_sum[if_incoming->if_num];
676 spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
677
678 if (bcast_own_sum_orig >= bcast_own_sum_neigh)
679 goto update_tt;
680 }
681
682 update_route(bat_priv, orig_node, neigh_node);
683
684update_tt:
685 /* I have to check for transtable changes only if the OGM has been
686 * sent through a primary interface */
687 if (((batman_ogm_packet->orig != ethhdr->h_source) &&
76543d14 688 (batman_ogm_packet->header.ttl > 2)) ||
fc957275
ML
689 (batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
690 tt_update_orig(bat_priv, orig_node, tt_buff,
691 batman_ogm_packet->tt_num_changes,
692 batman_ogm_packet->ttvn,
693 batman_ogm_packet->tt_crc);
694
695 if (orig_node->gw_flags != batman_ogm_packet->gw_flags)
696 gw_node_update(bat_priv, orig_node,
697 batman_ogm_packet->gw_flags);
698
699 orig_node->gw_flags = batman_ogm_packet->gw_flags;
700
701 /* restart gateway selection if fast or late switching was enabled */
702 if ((orig_node->gw_flags) &&
703 (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&
704 (atomic_read(&bat_priv->gw_sel_class) > 2))
705 gw_check_election(bat_priv, orig_node);
706
707 goto out;
708
709unlock:
710 rcu_read_unlock();
711out:
712 if (neigh_node)
713 neigh_node_free_ref(neigh_node);
714 if (router)
715 neigh_node_free_ref(router);
716}
717
718static int bat_ogm_calc_tq(struct orig_node *orig_node,
719 struct orig_node *orig_neigh_node,
720 struct batman_ogm_packet *batman_ogm_packet,
721 struct hard_iface *if_incoming)
722{
723 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
724 struct neigh_node *neigh_node = NULL, *tmp_neigh_node;
725 struct hlist_node *node;
726 uint8_t total_count;
727 uint8_t orig_eq_count, neigh_rq_count, tq_own;
728 int tq_asym_penalty, ret = 0;
729
730 /* find corresponding one hop neighbor */
731 rcu_read_lock();
732 hlist_for_each_entry_rcu(tmp_neigh_node, node,
733 &orig_neigh_node->neigh_list, list) {
734
735 if (!compare_eth(tmp_neigh_node->addr, orig_neigh_node->orig))
736 continue;
737
738 if (tmp_neigh_node->if_incoming != if_incoming)
739 continue;
740
741 if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
742 continue;
743
744 neigh_node = tmp_neigh_node;
745 break;
746 }
747 rcu_read_unlock();
748
749 if (!neigh_node)
750 neigh_node = create_neighbor(orig_neigh_node,
751 orig_neigh_node,
752 orig_neigh_node->orig,
753 if_incoming);
754
755 if (!neigh_node)
756 goto out;
757
758 /* if orig_node is direct neighbor update neigh_node last_valid */
759 if (orig_node == orig_neigh_node)
760 neigh_node->last_valid = jiffies;
761
762 orig_node->last_valid = jiffies;
763
764 /* find packet count of corresponding one hop neighbor */
765 spin_lock_bh(&orig_node->ogm_cnt_lock);
766 orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num];
767 neigh_rq_count = neigh_node->real_packet_count;
768 spin_unlock_bh(&orig_node->ogm_cnt_lock);
769
770 /* pay attention to not get a value bigger than 100 % */
771 total_count = (orig_eq_count > neigh_rq_count ?
772 neigh_rq_count : orig_eq_count);
773
774 /* if we have too few packets (too less data) we set tq_own to zero */
775 /* if we receive too few packets it is not considered bidirectional */
776 if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
777 (neigh_rq_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
778 tq_own = 0;
779 else
780 /* neigh_node->real_packet_count is never zero as we
781 * only purge old information when getting new
782 * information */
783 tq_own = (TQ_MAX_VALUE * total_count) / neigh_rq_count;
784
785 /*
786 * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
787 * affect the nearly-symmetric links only a little, but
788 * punishes asymmetric links more. This will give a value
789 * between 0 and TQ_MAX_VALUE
790 */
791 tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
792 (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
793 (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
794 (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count)) /
795 (TQ_LOCAL_WINDOW_SIZE *
796 TQ_LOCAL_WINDOW_SIZE *
797 TQ_LOCAL_WINDOW_SIZE);
798
799 batman_ogm_packet->tq = ((batman_ogm_packet->tq * tq_own
800 * tq_asym_penalty) /
801 (TQ_MAX_VALUE * TQ_MAX_VALUE));
802
803 bat_dbg(DBG_BATMAN, bat_priv,
804 "bidirectional: "
805 "orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
806 "real recv = %2i, local tq: %3i, asym_penalty: %3i, "
807 "total tq: %3i\n",
808 orig_node->orig, orig_neigh_node->orig, total_count,
809 neigh_rq_count, tq_own, tq_asym_penalty, batman_ogm_packet->tq);
810
811 /* if link has the minimum required transmission quality
812 * consider it bidirectional */
813 if (batman_ogm_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
814 ret = 1;
815
816out:
817 if (neigh_node)
818 neigh_node_free_ref(neigh_node);
819 return ret;
820}
821
822/* processes a batman packet for all interfaces, adjusts the sequence number and
823 * finds out whether it is a duplicate.
824 * returns:
825 * 1 the packet is a duplicate
826 * 0 the packet has not yet been received
827 * -1 the packet is old and has been received while the seqno window
828 * was protected. Caller should drop it.
829 */
830static int bat_ogm_update_seqnos(const struct ethhdr *ethhdr,
831 const struct batman_ogm_packet
832 *batman_ogm_packet,
833 const struct hard_iface *if_incoming)
834{
835 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
836 struct orig_node *orig_node;
837 struct neigh_node *tmp_neigh_node;
838 struct hlist_node *node;
839 int is_duplicate = 0;
840 int32_t seq_diff;
841 int need_update = 0;
842 int set_mark, ret = -1;
843
844 orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
845 if (!orig_node)
846 return 0;
847
848 spin_lock_bh(&orig_node->ogm_cnt_lock);
849 seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;
850
851 /* signalize caller that the packet is to be dropped. */
852 if (window_protected(bat_priv, seq_diff,
853 &orig_node->batman_seqno_reset))
854 goto out;
855
856 rcu_read_lock();
857 hlist_for_each_entry_rcu(tmp_neigh_node, node,
858 &orig_node->neigh_list, list) {
859
860 is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
861 orig_node->last_real_seqno,
862 batman_ogm_packet->seqno);
863
864 if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
865 (tmp_neigh_node->if_incoming == if_incoming))
866 set_mark = 1;
867 else
868 set_mark = 0;
869
870 /* if the window moved, set the update flag. */
871 need_update |= bit_get_packet(bat_priv,
872 tmp_neigh_node->real_bits,
873 seq_diff, set_mark);
874
875 tmp_neigh_node->real_packet_count =
876 bit_packet_count(tmp_neigh_node->real_bits);
877 }
878 rcu_read_unlock();
879
880 if (need_update) {
881 bat_dbg(DBG_BATMAN, bat_priv,
882 "updating last_seqno: old %d, new %d\n",
883 orig_node->last_real_seqno, batman_ogm_packet->seqno);
884 orig_node->last_real_seqno = batman_ogm_packet->seqno;
885 }
886
887 ret = is_duplicate;
888
889out:
890 spin_unlock_bh(&orig_node->ogm_cnt_lock);
891 orig_node_free_ref(orig_node);
892 return ret;
893}
894
895static void bat_ogm_process(const struct ethhdr *ethhdr,
896 struct batman_ogm_packet *batman_ogm_packet,
897 const unsigned char *tt_buff,
898 struct hard_iface *if_incoming)
899{
900 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
901 struct hard_iface *hard_iface;
902 struct orig_node *orig_neigh_node, *orig_node;
903 struct neigh_node *router = NULL, *router_router = NULL;
904 struct neigh_node *orig_neigh_router = NULL;
905 int has_directlink_flag;
906 int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
907 int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
908 int is_duplicate;
909 uint32_t if_incoming_seqno;
910
911 /* Silently drop when the batman packet is actually not a
912 * correct packet.
913 *
914 * This might happen if a packet is padded (e.g. Ethernet has a
915 * minimum frame length of 64 byte) and the aggregation interprets
916 * it as an additional length.
917 *
918 * TODO: A more sane solution would be to have a bit in the
919 * batman_ogm_packet to detect whether the packet is the last
920 * packet in an aggregation. Here we expect that the padding
921 * is always zero (or not 0x01)
922 */
76543d14 923 if (batman_ogm_packet->header.packet_type != BAT_OGM)
fc957275
ML
924 return;
925
926 /* could be changed by schedule_own_packet() */
927 if_incoming_seqno = atomic_read(&if_incoming->seqno);
928
929 has_directlink_flag = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);
930
931 is_single_hop_neigh = (compare_eth(ethhdr->h_source,
932 batman_ogm_packet->orig) ? 1 : 0);
933
934 bat_dbg(DBG_BATMAN, bat_priv,
935 "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
936 "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, "
937 "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
938 ethhdr->h_source, if_incoming->net_dev->name,
939 if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
940 batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,
941 batman_ogm_packet->ttvn, batman_ogm_packet->tt_crc,
942 batman_ogm_packet->tt_num_changes, batman_ogm_packet->tq,
76543d14
SE
943 batman_ogm_packet->header.ttl,
944 batman_ogm_packet->header.version, has_directlink_flag);
fc957275
ML
945
946 rcu_read_lock();
947 list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
948 if (hard_iface->if_status != IF_ACTIVE)
949 continue;
950
951 if (hard_iface->soft_iface != if_incoming->soft_iface)
952 continue;
953
954 if (compare_eth(ethhdr->h_source,
955 hard_iface->net_dev->dev_addr))
956 is_my_addr = 1;
957
958 if (compare_eth(batman_ogm_packet->orig,
959 hard_iface->net_dev->dev_addr))
960 is_my_orig = 1;
961
962 if (compare_eth(batman_ogm_packet->prev_sender,
963 hard_iface->net_dev->dev_addr))
964 is_my_oldorig = 1;
965
966 if (is_broadcast_ether_addr(ethhdr->h_source))
967 is_broadcast = 1;
968 }
969 rcu_read_unlock();
970
76543d14 971 if (batman_ogm_packet->header.version != COMPAT_VERSION) {
fc957275
ML
972 bat_dbg(DBG_BATMAN, bat_priv,
973 "Drop packet: incompatible batman version (%i)\n",
76543d14 974 batman_ogm_packet->header.version);
fc957275
ML
975 return;
976 }
977
978 if (is_my_addr) {
979 bat_dbg(DBG_BATMAN, bat_priv,
980 "Drop packet: received my own broadcast (sender: %pM"
981 ")\n",
982 ethhdr->h_source);
983 return;
984 }
985
986 if (is_broadcast) {
987 bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
988 "ignoring all packets with broadcast source addr (sender: %pM"
989 ")\n", ethhdr->h_source);
990 return;
991 }
992
993 if (is_my_orig) {
994 unsigned long *word;
995 int offset;
996
997 orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
998 if (!orig_neigh_node)
999 return;
1000
1001 /* neighbor has to indicate direct link and it has to
1002 * come via the corresponding interface */
1003 /* save packet seqno for bidirectional check */
1004 if (has_directlink_flag &&
1005 compare_eth(if_incoming->net_dev->dev_addr,
1006 batman_ogm_packet->orig)) {
1007 offset = if_incoming->if_num * NUM_WORDS;
1008
1009 spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
1010 word = &(orig_neigh_node->bcast_own[offset]);
1011 bit_mark(word,
1012 if_incoming_seqno -
1013 batman_ogm_packet->seqno - 2);
1014 orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
1015 bit_packet_count(word);
1016 spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
1017 }
1018
1019 bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
1020 "originator packet from myself (via neighbor)\n");
1021 orig_node_free_ref(orig_neigh_node);
1022 return;
1023 }
1024
1025 if (is_my_oldorig) {
1026 bat_dbg(DBG_BATMAN, bat_priv,
1027 "Drop packet: ignoring all rebroadcast echos (sender: "
1028 "%pM)\n", ethhdr->h_source);
1029 return;
1030 }
1031
1032 orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
1033 if (!orig_node)
1034 return;
1035
1036 is_duplicate = bat_ogm_update_seqnos(ethhdr, batman_ogm_packet,
1037 if_incoming);
1038
1039 if (is_duplicate == -1) {
1040 bat_dbg(DBG_BATMAN, bat_priv,
1041 "Drop packet: packet within seqno protection time "
1042 "(sender: %pM)\n", ethhdr->h_source);
1043 goto out;
1044 }
1045
1046 if (batman_ogm_packet->tq == 0) {
1047 bat_dbg(DBG_BATMAN, bat_priv,
1048 "Drop packet: originator packet with tq equal 0\n");
1049 goto out;
1050 }
1051
1052 router = orig_node_get_router(orig_node);
1053 if (router)
1054 router_router = orig_node_get_router(router->orig_node);
1055
1056 /* avoid temporary routing loops */
1057 if (router && router_router &&
1058 (compare_eth(router->addr, batman_ogm_packet->prev_sender)) &&
1059 !(compare_eth(batman_ogm_packet->orig,
1060 batman_ogm_packet->prev_sender)) &&
1061 (compare_eth(router->addr, router_router->addr))) {
1062 bat_dbg(DBG_BATMAN, bat_priv,
1063 "Drop packet: ignoring all rebroadcast packets that "
1064 "may make me loop (sender: %pM)\n", ethhdr->h_source);
1065 goto out;
1066 }
1067
1068 /* if sender is a direct neighbor the sender mac equals
1069 * originator mac */
1070 orig_neigh_node = (is_single_hop_neigh ?
1071 orig_node :
1072 get_orig_node(bat_priv, ethhdr->h_source));
1073 if (!orig_neigh_node)
1074 goto out;
1075
1076 orig_neigh_router = orig_node_get_router(orig_neigh_node);
1077
1078 /* drop packet if sender is not a direct neighbor and if we
1079 * don't route towards it */
1080 if (!is_single_hop_neigh && (!orig_neigh_router)) {
1081 bat_dbg(DBG_BATMAN, bat_priv,
1082 "Drop packet: OGM via unknown neighbor!\n");
1083 goto out_neigh;
1084 }
1085
1086 is_bidirectional = bat_ogm_calc_tq(orig_node, orig_neigh_node,
1087 batman_ogm_packet, if_incoming);
1088
1089 bonding_save_primary(orig_node, orig_neigh_node, batman_ogm_packet);
1090
1091 /* update ranking if it is not a duplicate or has the same
1092 * seqno and similar ttl as the non-duplicate */
1093 if (is_bidirectional &&
1094 (!is_duplicate ||
1095 ((orig_node->last_real_seqno == batman_ogm_packet->seqno) &&
76543d14 1096 (orig_node->last_ttl - 3 <= batman_ogm_packet->header.ttl))))
fc957275
ML
1097 bat_ogm_orig_update(bat_priv, orig_node, ethhdr,
1098 batman_ogm_packet, if_incoming,
1099 tt_buff, is_duplicate);
1100
1101 /* is single hop (direct) neighbor */
1102 if (is_single_hop_neigh) {
1103
1104 /* mark direct link on incoming interface */
b9dacc52
ML
1105 bat_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
1106 1, if_incoming);
fc957275
ML
1107
1108 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
1109 "rebroadcast neighbor packet with direct link flag\n");
1110 goto out_neigh;
1111 }
1112
1113 /* multihop originator */
1114 if (!is_bidirectional) {
1115 bat_dbg(DBG_BATMAN, bat_priv,
1116 "Drop packet: not received via bidirectional link\n");
1117 goto out_neigh;
1118 }
1119
1120 if (is_duplicate) {
1121 bat_dbg(DBG_BATMAN, bat_priv,
1122 "Drop packet: duplicate packet received\n");
1123 goto out_neigh;
1124 }
1125
1126 bat_dbg(DBG_BATMAN, bat_priv,
1127 "Forwarding packet: rebroadcast originator packet\n");
b9dacc52 1128 bat_ogm_forward(orig_node, ethhdr, batman_ogm_packet, 0, if_incoming);
fc957275
ML
1129
1130out_neigh:
1131 if ((orig_neigh_node) && (!is_single_hop_neigh))
1132 orig_node_free_ref(orig_neigh_node);
1133out:
1134 if (router)
1135 neigh_node_free_ref(router);
1136 if (router_router)
1137 neigh_node_free_ref(router_router);
1138 if (orig_neigh_router)
1139 neigh_node_free_ref(orig_neigh_router);
1140
1141 orig_node_free_ref(orig_node);
1142}
1143
8780dad9 1144void bat_ogm_receive(struct hard_iface *if_incoming, struct sk_buff *skb)
fc957275
ML
1145{
1146 struct batman_ogm_packet *batman_ogm_packet;
8780dad9
ML
1147 struct ethhdr *ethhdr;
1148 int buff_pos = 0, packet_len;
1149 unsigned char *tt_buff, *packet_buff;
fc957275 1150
8780dad9
ML
1151 packet_len = skb_headlen(skb);
1152 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1153 packet_buff = skb->data;
fc957275
ML
1154 batman_ogm_packet = (struct batman_ogm_packet *)packet_buff;
1155
1156 /* unpack the aggregated packets and process them one by one */
1157 do {
1158 /* network to host order for our 32bit seqno and the
1159 orig_interval */
1160 batman_ogm_packet->seqno = ntohl(batman_ogm_packet->seqno);
1161 batman_ogm_packet->tt_crc = ntohs(batman_ogm_packet->tt_crc);
1162
1163 tt_buff = packet_buff + buff_pos + BATMAN_OGM_LEN;
1164
1165 bat_ogm_process(ethhdr, batman_ogm_packet,
1166 tt_buff, if_incoming);
1167
1168 buff_pos += BATMAN_OGM_LEN +
1169 tt_len(batman_ogm_packet->tt_num_changes);
1170
1171 batman_ogm_packet = (struct batman_ogm_packet *)
1172 (packet_buff + buff_pos);
1173 } while (bat_ogm_aggr_packet(buff_pos, packet_len,
1174 batman_ogm_packet->tt_num_changes));
1175}
1c280471
ML
1176
1177static struct bat_algo_ops batman_iv __read_mostly = {
1178 .name = "BATMAN IV",
1179};
1180
1181int __init bat_iv_init(void)
1182{
1183 return bat_algo_register(&batman_iv);
1184}
This page took 0.087974 seconds and 5 git commands to generate.