batman-adv: add B.A.T.M.A.N. IV bat_{orig, neigh}_dump implementations
[deliverable/linux.git] / net / batman-adv / bat_v.c
CommitLineData
d6f94d91
LL
1/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
2 *
3 * Linus Lüssing, Marek Lindner
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public
7 * License as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
a2d08166 18#include "bat_v.h"
d6f94d91
LL
19#include "main.h"
20
0b5ecc68 21#include <linux/atomic.h>
97869060 22#include <linux/bug.h>
d6f94d91 23#include <linux/cache.h>
08686943 24#include <linux/errno.h>
d6f94d91 25#include <linux/init.h>
261e264d 26#include <linux/jiffies.h>
08686943 27#include <linux/kernel.h>
50164d8f 28#include <linux/kref.h>
261e264d
AQ
29#include <linux/netdevice.h>
30#include <linux/rculist.h>
31#include <linux/rcupdate.h>
32#include <linux/seq_file.h>
a45e932a 33#include <linux/stddef.h>
97869060 34#include <linux/types.h>
c833484e 35#include <linux/workqueue.h>
d6f94d91 36
a2d08166 37#include "bat_algo.h"
d6f94d91 38#include "bat_v_elp.h"
0da00359 39#include "bat_v_ogm.h"
08686943
AQ
40#include "gateway_client.h"
41#include "gateway_common.h"
b6cf5d49 42#include "hard-interface.h"
261e264d 43#include "hash.h"
50164d8f 44#include "log.h"
97869060 45#include "originator.h"
162bd64c 46#include "packet.h"
d6f94d91 47
b6cf5d49
AQ
48static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
49{
ebe24cea
ML
50 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
51 struct batadv_hard_iface *primary_if;
52
53 primary_if = batadv_primary_if_get_selected(bat_priv);
54
55 if (primary_if) {
56 batadv_v_elp_iface_activate(primary_if, hard_iface);
57 batadv_hardif_put(primary_if);
58 }
59
b6cf5d49
AQ
60 /* B.A.T.M.A.N. V does not use any queuing mechanism, therefore it can
61 * set the interface as ACTIVE right away, without any risk of race
62 * condition
63 */
64 if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
65 hard_iface->if_status = BATADV_IF_ACTIVE;
66}
67
d6f94d91
LL
68static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
69{
0da00359
AQ
70 int ret;
71
72 ret = batadv_v_elp_iface_enable(hard_iface);
73 if (ret < 0)
74 return ret;
75
76 ret = batadv_v_ogm_iface_enable(hard_iface);
77 if (ret < 0)
78 batadv_v_elp_iface_disable(hard_iface);
79
80 return ret;
d6f94d91
LL
81}
82
83static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
84{
85 batadv_v_elp_iface_disable(hard_iface);
86}
87
d6f94d91
LL
88static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
89{
90 batadv_v_elp_primary_iface_set(hard_iface);
0da00359 91 batadv_v_ogm_primary_iface_set(hard_iface);
d6f94d91
LL
92}
93
1653f61d
AQ
94/**
95 * batadv_v_iface_update_mac - react to hard-interface MAC address change
96 * @hard_iface: the modified interface
97 *
98 * If the modified interface is the primary one, update the originator
99 * address in the ELP and OGM messages to reflect the new MAC address.
100 */
101static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
102{
103 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
104 struct batadv_hard_iface *primary_if;
105
106 primary_if = batadv_primary_if_get_selected(bat_priv);
107 if (primary_if != hard_iface)
108 goto out;
109
110 batadv_v_primary_iface_set(hard_iface);
111out:
112 if (primary_if)
113 batadv_hardif_put(primary_if);
114}
115
162bd64c
LL
116static void
117batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
118{
119 ewma_throughput_init(&hardif_neigh->bat_v.throughput);
c833484e
AQ
120 INIT_WORK(&hardif_neigh->bat_v.metric_work,
121 batadv_v_elp_throughput_metric_update);
162bd64c
LL
122}
123
261e264d
AQ
124/**
125 * batadv_v_orig_print_neigh - print neighbors for the originator table
126 * @orig_node: the orig_node for which the neighbors are printed
127 * @if_outgoing: outgoing interface for these entries
128 * @seq: debugfs table seq_file struct
129 *
130 * Must be called while holding an rcu lock.
131 */
132static void
133batadv_v_orig_print_neigh(struct batadv_orig_node *orig_node,
134 struct batadv_hard_iface *if_outgoing,
135 struct seq_file *seq)
136{
137 struct batadv_neigh_node *neigh_node;
138 struct batadv_neigh_ifinfo *n_ifinfo;
139
140 hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
141 n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
142 if (!n_ifinfo)
143 continue;
144
145 seq_printf(seq, " %pM (%9u.%1u)",
146 neigh_node->addr,
147 n_ifinfo->bat_v.throughput / 10,
148 n_ifinfo->bat_v.throughput % 10);
149
150 batadv_neigh_ifinfo_put(n_ifinfo);
151 }
152}
153
626d23e8
LL
154/**
155 * batadv_v_hardif_neigh_print - print a single ELP neighbour node
156 * @seq: neighbour table seq_file struct
157 * @hardif_neigh: hardif neighbour information
158 */
159static void
160batadv_v_hardif_neigh_print(struct seq_file *seq,
161 struct batadv_hardif_neigh_node *hardif_neigh)
162{
163 int last_secs, last_msecs;
164 u32 throughput;
165
166 last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000;
167 last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000;
168 throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
169
170 seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n",
171 hardif_neigh->addr, last_secs, last_msecs, throughput / 10,
172 throughput % 10, hardif_neigh->if_incoming->net_dev->name);
173}
174
175/**
176 * batadv_v_neigh_print - print the single hop neighbour list
177 * @bat_priv: the bat priv with all the soft interface information
178 * @seq: neighbour table seq_file struct
179 */
180static void batadv_v_neigh_print(struct batadv_priv *bat_priv,
181 struct seq_file *seq)
182{
183 struct net_device *net_dev = (struct net_device *)seq->private;
184 struct batadv_hardif_neigh_node *hardif_neigh;
185 struct batadv_hard_iface *hard_iface;
186 int batman_count = 0;
187
925a6f37
AQ
188 seq_puts(seq,
189 " Neighbor last-seen ( throughput) [ IF]\n");
626d23e8
LL
190
191 rcu_read_lock();
192 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
193 if (hard_iface->soft_iface != net_dev)
194 continue;
195
196 hlist_for_each_entry_rcu(hardif_neigh,
197 &hard_iface->neigh_list, list) {
198 batadv_v_hardif_neigh_print(seq, hardif_neigh);
199 batman_count++;
200 }
201 }
202 rcu_read_unlock();
203
204 if (batman_count == 0)
205 seq_puts(seq, "No batman nodes in range ...\n");
206}
207
261e264d
AQ
208/**
209 * batadv_v_orig_print - print the originator table
210 * @bat_priv: the bat priv with all the soft interface information
211 * @seq: debugfs table seq_file struct
212 * @if_outgoing: the outgoing interface for which this should be printed
213 */
214static void batadv_v_orig_print(struct batadv_priv *bat_priv,
215 struct seq_file *seq,
216 struct batadv_hard_iface *if_outgoing)
217{
218 struct batadv_neigh_node *neigh_node;
219 struct batadv_hashtable *hash = bat_priv->orig_hash;
220 int last_seen_msecs, last_seen_secs;
221 struct batadv_orig_node *orig_node;
222 struct batadv_neigh_ifinfo *n_ifinfo;
223 unsigned long last_seen_jiffies;
224 struct hlist_head *head;
225 int batman_count = 0;
226 u32 i;
227
925a6f37
AQ
228 seq_puts(seq,
229 " Originator last-seen ( throughput) Nexthop [outgoingIF]: Potential nexthops ...\n");
261e264d
AQ
230
231 for (i = 0; i < hash->size; i++) {
232 head = &hash->table[i];
233
234 rcu_read_lock();
235 hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
236 neigh_node = batadv_orig_router_get(orig_node,
237 if_outgoing);
238 if (!neigh_node)
239 continue;
240
241 n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
242 if_outgoing);
243 if (!n_ifinfo)
244 goto next;
245
246 last_seen_jiffies = jiffies - orig_node->last_seen;
247 last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
248 last_seen_secs = last_seen_msecs / 1000;
249 last_seen_msecs = last_seen_msecs % 1000;
250
251 seq_printf(seq, "%pM %4i.%03is (%9u.%1u) %pM [%10s]:",
252 orig_node->orig, last_seen_secs,
253 last_seen_msecs,
254 n_ifinfo->bat_v.throughput / 10,
255 n_ifinfo->bat_v.throughput % 10,
256 neigh_node->addr,
257 neigh_node->if_incoming->net_dev->name);
258
259 batadv_v_orig_print_neigh(orig_node, if_outgoing, seq);
260 seq_puts(seq, "\n");
261 batman_count++;
262
263next:
264 batadv_neigh_node_put(neigh_node);
265 if (n_ifinfo)
266 batadv_neigh_ifinfo_put(n_ifinfo);
267 }
268 rcu_read_unlock();
269 }
270
271 if (batman_count == 0)
272 seq_puts(seq, "No batman nodes in range ...\n");
273}
274
97869060
AQ
275static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
276 struct batadv_hard_iface *if_outgoing1,
277 struct batadv_neigh_node *neigh2,
278 struct batadv_hard_iface *if_outgoing2)
279{
280 struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
71f9d27d 281 int ret = 0;
97869060
AQ
282
283 ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
71f9d27d
SE
284 if (WARN_ON(!ifinfo1))
285 goto err_ifinfo1;
286
97869060 287 ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
71f9d27d
SE
288 if (WARN_ON(!ifinfo2))
289 goto err_ifinfo2;
97869060 290
71f9d27d 291 ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
97869060 292
71f9d27d
SE
293 batadv_neigh_ifinfo_put(ifinfo2);
294err_ifinfo2:
295 batadv_neigh_ifinfo_put(ifinfo1);
296err_ifinfo1:
297 return ret;
97869060
AQ
298}
299
300static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
301 struct batadv_hard_iface *if_outgoing1,
302 struct batadv_neigh_node *neigh2,
303 struct batadv_hard_iface *if_outgoing2)
304{
305 struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
306 u32 threshold;
71f9d27d 307 bool ret = false;
97869060
AQ
308
309 ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
71f9d27d
SE
310 if (WARN_ON(!ifinfo1))
311 goto err_ifinfo1;
97869060 312
71f9d27d
SE
313 ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
314 if (WARN_ON(!ifinfo2))
315 goto err_ifinfo2;
a45e932a 316
97869060
AQ
317 threshold = ifinfo1->bat_v.throughput / 4;
318 threshold = ifinfo1->bat_v.throughput - threshold;
319
71f9d27d
SE
320 ret = ifinfo2->bat_v.throughput > threshold;
321
322 batadv_neigh_ifinfo_put(ifinfo2);
323err_ifinfo2:
324 batadv_neigh_ifinfo_put(ifinfo1);
325err_ifinfo1:
326 return ret;
97869060
AQ
327}
328
08686943
AQ
329static ssize_t batadv_v_store_sel_class(struct batadv_priv *bat_priv,
330 char *buff, size_t count)
331{
332 u32 old_class, class;
333
334 if (!batadv_parse_throughput(bat_priv->soft_iface, buff,
335 "B.A.T.M.A.N. V GW selection class",
336 &class))
337 return -EINVAL;
338
339 old_class = atomic_read(&bat_priv->gw.sel_class);
340 atomic_set(&bat_priv->gw.sel_class, class);
341
342 if (old_class != class)
343 batadv_gw_reselect(bat_priv);
344
345 return count;
346}
347
348static ssize_t batadv_v_show_sel_class(struct batadv_priv *bat_priv, char *buff)
349{
350 u32 class = atomic_read(&bat_priv->gw.sel_class);
351
352 return sprintf(buff, "%u.%u MBit\n", class / 10, class % 10);
353}
354
50164d8f
AQ
355/**
356 * batadv_v_gw_throughput_get - retrieve the GW-bandwidth for a given GW
357 * @gw_node: the GW to retrieve the metric for
358 * @bw: the pointer where the metric will be stored. The metric is computed as
359 * the minimum between the GW advertised throughput and the path throughput to
360 * it in the mesh
361 *
362 * Return: 0 on success, -1 on failure
363 */
364static int batadv_v_gw_throughput_get(struct batadv_gw_node *gw_node, u32 *bw)
365{
366 struct batadv_neigh_ifinfo *router_ifinfo = NULL;
367 struct batadv_orig_node *orig_node;
368 struct batadv_neigh_node *router;
369 int ret = -1;
370
371 orig_node = gw_node->orig_node;
372 router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
373 if (!router)
374 goto out;
375
376 router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
377 if (!router_ifinfo)
378 goto out;
379
380 /* the GW metric is computed as the minimum between the path throughput
381 * to reach the GW itself and the advertised bandwidth.
382 * This gives us an approximation of the effective throughput that the
383 * client can expect via this particular GW node
384 */
385 *bw = router_ifinfo->bat_v.throughput;
386 *bw = min_t(u32, *bw, gw_node->bandwidth_down);
387
388 ret = 0;
389out:
390 if (router)
391 batadv_neigh_node_put(router);
392 if (router_ifinfo)
393 batadv_neigh_ifinfo_put(router_ifinfo);
394
395 return ret;
396}
397
398/**
399 * batadv_v_gw_get_best_gw_node - retrieve the best GW node
400 * @bat_priv: the bat priv with all the soft interface information
401 *
402 * Return: the GW node having the best GW-metric, NULL if no GW is known
403 */
404static struct batadv_gw_node *
405batadv_v_gw_get_best_gw_node(struct batadv_priv *bat_priv)
406{
407 struct batadv_gw_node *gw_node, *curr_gw = NULL;
408 u32 max_bw = 0, bw;
409
410 rcu_read_lock();
411 hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
412 if (!kref_get_unless_zero(&gw_node->refcount))
413 continue;
414
415 if (batadv_v_gw_throughput_get(gw_node, &bw) < 0)
416 goto next;
417
418 if (curr_gw && (bw <= max_bw))
419 goto next;
420
421 if (curr_gw)
422 batadv_gw_node_put(curr_gw);
423
424 curr_gw = gw_node;
425 kref_get(&curr_gw->refcount);
426 max_bw = bw;
427
428next:
429 batadv_gw_node_put(gw_node);
430 }
431 rcu_read_unlock();
432
433 return curr_gw;
434}
435
436/**
437 * batadv_v_gw_is_eligible - check if a originator would be selected as GW
438 * @bat_priv: the bat priv with all the soft interface information
439 * @curr_gw_orig: originator representing the currently selected GW
440 * @orig_node: the originator representing the new candidate
441 *
442 * Return: true if orig_node can be selected as current GW, false otherwise
443 */
444static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv,
445 struct batadv_orig_node *curr_gw_orig,
446 struct batadv_orig_node *orig_node)
447{
448 struct batadv_gw_node *curr_gw = NULL, *orig_gw = NULL;
449 u32 gw_throughput, orig_throughput, threshold;
450 bool ret = false;
451
452 threshold = atomic_read(&bat_priv->gw.sel_class);
453
454 curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig);
455 if (!curr_gw) {
456 ret = true;
457 goto out;
458 }
459
460 if (batadv_v_gw_throughput_get(curr_gw, &gw_throughput) < 0) {
461 ret = true;
462 goto out;
463 }
464
465 orig_gw = batadv_gw_node_get(bat_priv, orig_node);
466 if (!orig_node)
467 goto out;
468
469 if (batadv_v_gw_throughput_get(orig_gw, &orig_throughput) < 0)
470 goto out;
471
472 if (orig_throughput < gw_throughput)
473 goto out;
474
475 if ((orig_throughput - gw_throughput) < threshold)
476 goto out;
477
478 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
479 "Restarting gateway selection: better gateway found (throughput curr: %u, throughput new: %u)\n",
480 gw_throughput, orig_throughput);
481
482 ret = true;
483out:
484 if (curr_gw)
485 batadv_gw_node_put(curr_gw);
486 if (orig_gw)
487 batadv_gw_node_put(orig_gw);
488
489 return ret;
490}
491
492/* fails if orig_node has no router */
493static int batadv_v_gw_write_buffer_text(struct batadv_priv *bat_priv,
494 struct seq_file *seq,
495 const struct batadv_gw_node *gw_node)
496{
497 struct batadv_gw_node *curr_gw;
498 struct batadv_neigh_node *router;
499 struct batadv_neigh_ifinfo *router_ifinfo = NULL;
500 int ret = -1;
501
502 router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
503 if (!router)
504 goto out;
505
506 router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
507 if (!router_ifinfo)
508 goto out;
509
510 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
511
512 seq_printf(seq, "%s %pM (%9u.%1u) %pM [%10s]: %u.%u/%u.%u MBit\n",
513 (curr_gw == gw_node ? "=>" : " "),
514 gw_node->orig_node->orig,
515 router_ifinfo->bat_v.throughput / 10,
516 router_ifinfo->bat_v.throughput % 10, router->addr,
517 router->if_incoming->net_dev->name,
518 gw_node->bandwidth_down / 10,
519 gw_node->bandwidth_down % 10,
520 gw_node->bandwidth_up / 10,
521 gw_node->bandwidth_up % 10);
522 ret = seq_has_overflowed(seq) ? -1 : 0;
523
524 if (curr_gw)
525 batadv_gw_node_put(curr_gw);
526out:
527 if (router_ifinfo)
528 batadv_neigh_ifinfo_put(router_ifinfo);
529 if (router)
530 batadv_neigh_node_put(router);
531 return ret;
532}
533
534/**
535 * batadv_v_gw_print - print the gateway list
536 * @bat_priv: the bat priv with all the soft interface information
537 * @seq: gateway table seq_file struct
538 */
539static void batadv_v_gw_print(struct batadv_priv *bat_priv,
540 struct seq_file *seq)
541{
542 struct batadv_gw_node *gw_node;
543 int gw_count = 0;
544
545 seq_puts(seq,
546 " Gateway ( throughput) Nexthop [outgoingIF]: advertised uplink bandwidth\n");
547
548 rcu_read_lock();
549 hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
550 /* fails if orig_node has no router */
551 if (batadv_v_gw_write_buffer_text(bat_priv, seq, gw_node) < 0)
552 continue;
553
554 gw_count++;
555 }
556 rcu_read_unlock();
557
558 if (gw_count == 0)
559 seq_puts(seq, "No gateways in range ...\n");
560}
561
d6f94d91
LL
562static struct batadv_algo_ops batadv_batman_v __read_mostly = {
563 .name = "BATMAN_V",
29824a55
AQ
564 .iface = {
565 .activate = batadv_v_iface_activate,
566 .enable = batadv_v_iface_enable,
567 .disable = batadv_v_iface_disable,
568 .update_mac = batadv_v_iface_update_mac,
569 .primary_set = batadv_v_primary_iface_set,
570 },
571 .neigh = {
572 .hardif_init = batadv_v_hardif_neigh_init,
573 .cmp = batadv_v_neigh_cmp,
574 .is_similar_or_better = batadv_v_neigh_is_sob,
575 .print = batadv_v_neigh_print,
576 },
577 .orig = {
578 .print = batadv_v_orig_print,
579 },
08686943
AQ
580 .gw = {
581 .store_sel_class = batadv_v_store_sel_class,
582 .show_sel_class = batadv_v_show_sel_class,
50164d8f
AQ
583 .get_best_gw_node = batadv_v_gw_get_best_gw_node,
584 .is_eligible = batadv_v_gw_is_eligible,
585 .print = batadv_v_gw_print,
08686943 586 },
d6f94d91
LL
587};
588
7db682d1
ML
589/**
590 * batadv_v_hardif_init - initialize the algorithm specific fields in the
591 * hard-interface object
592 * @hard_iface: the hard-interface to initialize
593 */
594void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface)
595{
596 /* enable link throughput auto-detection by setting the throughput
597 * override to zero
598 */
599 atomic_set(&hard_iface->bat_v.throughput_override, 0);
600 atomic_set(&hard_iface->bat_v.elp_interval, 500);
601}
602
0da00359
AQ
603/**
604 * batadv_v_mesh_init - initialize the B.A.T.M.A.N. V private resources for a
605 * mesh
606 * @bat_priv: the object representing the mesh interface to initialise
607 *
608 * Return: 0 on success or a negative error code otherwise
609 */
610int batadv_v_mesh_init(struct batadv_priv *bat_priv)
611{
50164d8f
AQ
612 int ret = 0;
613
614 ret = batadv_v_ogm_init(bat_priv);
615 if (ret < 0)
616 return ret;
617
618 /* set default throughput difference threshold to 5Mbps */
619 atomic_set(&bat_priv->gw.sel_class, 50);
620
621 return 0;
0da00359
AQ
622}
623
624/**
625 * batadv_v_mesh_free - free the B.A.T.M.A.N. V private resources for a mesh
626 * @bat_priv: the object representing the mesh interface to free
627 */
628void batadv_v_mesh_free(struct batadv_priv *bat_priv)
629{
630 batadv_v_ogm_free(bat_priv);
631}
632
d6f94d91
LL
633/**
634 * batadv_v_init - B.A.T.M.A.N. V initialization function
635 *
636 * Description: Takes care of initializing all the subcomponents.
637 * It is invoked upon module load only.
638 *
639 * Return: 0 on success or a negative error code otherwise
640 */
641int __init batadv_v_init(void)
642{
162bd64c
LL
643 int ret;
644
645 /* B.A.T.M.A.N. V echo location protocol packet */
646 ret = batadv_recv_handler_register(BATADV_ELP,
647 batadv_v_elp_packet_recv);
648 if (ret < 0)
649 return ret;
650
0da00359
AQ
651 ret = batadv_recv_handler_register(BATADV_OGM2,
652 batadv_v_ogm_packet_recv);
653 if (ret < 0)
654 goto elp_unregister;
162bd64c 655
0da00359 656 ret = batadv_algo_register(&batadv_batman_v);
162bd64c 657 if (ret < 0)
0da00359
AQ
658 goto ogm_unregister;
659
660 return ret;
661
662ogm_unregister:
663 batadv_recv_handler_unregister(BATADV_OGM2);
664
665elp_unregister:
666 batadv_recv_handler_unregister(BATADV_ELP);
162bd64c
LL
667
668 return ret;
d6f94d91 669}
This page took 0.076306 seconds and 5 git commands to generate.