1
2
3
4
5
6
7#include "bat_v.h"
8#include "main.h"
9
10#include <linux/atomic.h>
11#include <linux/cache.h>
12#include <linux/errno.h>
13#include <linux/if_ether.h>
14#include <linux/init.h>
15#include <linux/jiffies.h>
16#include <linux/kref.h>
17#include <linux/list.h>
18#include <linux/minmax.h>
19#include <linux/netdevice.h>
20#include <linux/netlink.h>
21#include <linux/rculist.h>
22#include <linux/rcupdate.h>
23#include <linux/skbuff.h>
24#include <linux/spinlock.h>
25#include <linux/stddef.h>
26#include <linux/types.h>
27#include <linux/workqueue.h>
28#include <net/genetlink.h>
29#include <net/netlink.h>
30#include <uapi/linux/batadv_packet.h>
31#include <uapi/linux/batman_adv.h>
32
33#include "bat_algo.h"
34#include "bat_v_elp.h"
35#include "bat_v_ogm.h"
36#include "gateway_client.h"
37#include "gateway_common.h"
38#include "hard-interface.h"
39#include "hash.h"
40#include "log.h"
41#include "netlink.h"
42#include "originator.h"
43
44static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
45{
46 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
47 struct batadv_hard_iface *primary_if;
48
49 primary_if = batadv_primary_if_get_selected(bat_priv);
50
51 if (primary_if) {
52 batadv_v_elp_iface_activate(primary_if, hard_iface);
53 batadv_hardif_put(primary_if);
54 }
55
56
57
58
59
60 if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
61 hard_iface->if_status = BATADV_IF_ACTIVE;
62}
63
64static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
65{
66 int ret;
67
68 ret = batadv_v_elp_iface_enable(hard_iface);
69 if (ret < 0)
70 return ret;
71
72 ret = batadv_v_ogm_iface_enable(hard_iface);
73 if (ret < 0)
74 batadv_v_elp_iface_disable(hard_iface);
75
76 return ret;
77}
78
79static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
80{
81 batadv_v_ogm_iface_disable(hard_iface);
82 batadv_v_elp_iface_disable(hard_iface);
83}
84
85static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
86{
87 batadv_v_elp_primary_iface_set(hard_iface);
88 batadv_v_ogm_primary_iface_set(hard_iface);
89}
90
91
92
93
94
95
96
97
98static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
99{
100 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
101 struct batadv_hard_iface *primary_if;
102
103 primary_if = batadv_primary_if_get_selected(bat_priv);
104 if (primary_if != hard_iface)
105 goto out;
106
107 batadv_v_primary_iface_set(hard_iface);
108out:
109 if (primary_if)
110 batadv_hardif_put(primary_if);
111}
112
113static void
114batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
115{
116 ewma_throughput_init(&hardif_neigh->bat_v.throughput);
117 INIT_WORK(&hardif_neigh->bat_v.metric_work,
118 batadv_v_elp_throughput_metric_update);
119}
120
121
122
123
124
125
126
127
128
129
130static int
131batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
132 struct batadv_hardif_neigh_node *hardif_neigh)
133{
134 void *hdr;
135 unsigned int last_seen_msecs;
136 u32 throughput;
137
138 last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen);
139 throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
140 throughput = throughput * 100;
141
142 hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
143 BATADV_CMD_GET_NEIGHBORS);
144 if (!hdr)
145 return -ENOBUFS;
146
147 if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
148 hardif_neigh->addr) ||
149 nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
150 hardif_neigh->if_incoming->net_dev->name) ||
151 nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
152 hardif_neigh->if_incoming->net_dev->ifindex) ||
153 nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
154 last_seen_msecs) ||
155 nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput))
156 goto nla_put_failure;
157
158 genlmsg_end(msg, hdr);
159 return 0;
160
161 nla_put_failure:
162 genlmsg_cancel(msg, hdr);
163 return -EMSGSIZE;
164}
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180static int
181batadv_v_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
182 struct batadv_priv *bat_priv,
183 struct batadv_hard_iface *hard_iface,
184 int *idx_s)
185{
186 struct batadv_hardif_neigh_node *hardif_neigh;
187 int idx = 0;
188
189 hlist_for_each_entry_rcu(hardif_neigh,
190 &hard_iface->neigh_list, list) {
191 if (idx++ < *idx_s)
192 continue;
193
194 if (batadv_v_neigh_dump_neigh(msg, portid, seq, hardif_neigh)) {
195 *idx_s = idx - 1;
196 return -EMSGSIZE;
197 }
198 }
199
200 *idx_s = 0;
201 return 0;
202}
203
204
205
206
207
208
209
210
211
212static void
213batadv_v_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb,
214 struct batadv_priv *bat_priv,
215 struct batadv_hard_iface *single_hardif)
216{
217 struct batadv_hard_iface *hard_iface;
218 int i_hardif = 0;
219 int i_hardif_s = cb->args[0];
220 int idx = cb->args[1];
221 int portid = NETLINK_CB(cb->skb).portid;
222
223 rcu_read_lock();
224 if (single_hardif) {
225 if (i_hardif_s == 0) {
226 if (batadv_v_neigh_dump_hardif(msg, portid,
227 cb->nlh->nlmsg_seq,
228 bat_priv, single_hardif,
229 &idx) == 0)
230 i_hardif++;
231 }
232 } else {
233 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
234 if (hard_iface->soft_iface != bat_priv->soft_iface)
235 continue;
236
237 if (i_hardif++ < i_hardif_s)
238 continue;
239
240 if (batadv_v_neigh_dump_hardif(msg, portid,
241 cb->nlh->nlmsg_seq,
242 bat_priv, hard_iface,
243 &idx)) {
244 i_hardif--;
245 break;
246 }
247 }
248 }
249 rcu_read_unlock();
250
251 cb->args[0] = i_hardif;
252 cb->args[1] = idx;
253}
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268static int
269batadv_v_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
270 struct batadv_priv *bat_priv,
271 struct batadv_hard_iface *if_outgoing,
272 struct batadv_orig_node *orig_node,
273 struct batadv_neigh_node *neigh_node,
274 bool best)
275{
276 struct batadv_neigh_ifinfo *n_ifinfo;
277 unsigned int last_seen_msecs;
278 u32 throughput;
279 void *hdr;
280
281 n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
282 if (!n_ifinfo)
283 return 0;
284
285 throughput = n_ifinfo->bat_v.throughput * 100;
286
287 batadv_neigh_ifinfo_put(n_ifinfo);
288
289 last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen);
290
291 if (if_outgoing != BATADV_IF_DEFAULT &&
292 if_outgoing != neigh_node->if_incoming)
293 return 0;
294
295 hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
296 BATADV_CMD_GET_ORIGINATORS);
297 if (!hdr)
298 return -ENOBUFS;
299
300 if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) ||
301 nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
302 neigh_node->addr) ||
303 nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
304 neigh_node->if_incoming->net_dev->name) ||
305 nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
306 neigh_node->if_incoming->net_dev->ifindex) ||
307 nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput) ||
308 nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
309 last_seen_msecs))
310 goto nla_put_failure;
311
312 if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
313 goto nla_put_failure;
314
315 genlmsg_end(msg, hdr);
316 return 0;
317
318 nla_put_failure:
319 genlmsg_cancel(msg, hdr);
320 return -EMSGSIZE;
321}
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337static int
338batadv_v_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
339 struct batadv_priv *bat_priv,
340 struct batadv_hard_iface *if_outgoing,
341 struct batadv_orig_node *orig_node, int *sub_s)
342{
343 struct batadv_neigh_node *neigh_node_best;
344 struct batadv_neigh_node *neigh_node;
345 int sub = 0;
346 bool best;
347
348 neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing);
349 if (!neigh_node_best)
350 goto out;
351
352 hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
353 if (sub++ < *sub_s)
354 continue;
355
356 best = (neigh_node == neigh_node_best);
357
358 if (batadv_v_orig_dump_subentry(msg, portid, seq, bat_priv,
359 if_outgoing, orig_node,
360 neigh_node, best)) {
361 batadv_neigh_node_put(neigh_node_best);
362
363 *sub_s = sub - 1;
364 return -EMSGSIZE;
365 }
366 }
367
368 out:
369 if (neigh_node_best)
370 batadv_neigh_node_put(neigh_node_best);
371
372 *sub_s = 0;
373 return 0;
374}
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389static int
390batadv_v_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
391 struct batadv_priv *bat_priv,
392 struct batadv_hard_iface *if_outgoing,
393 struct hlist_head *head, int *idx_s, int *sub)
394{
395 struct batadv_orig_node *orig_node;
396 int idx = 0;
397
398 rcu_read_lock();
399 hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
400 if (idx++ < *idx_s)
401 continue;
402
403 if (batadv_v_orig_dump_entry(msg, portid, seq, bat_priv,
404 if_outgoing, orig_node, sub)) {
405 rcu_read_unlock();
406 *idx_s = idx - 1;
407 return -EMSGSIZE;
408 }
409 }
410 rcu_read_unlock();
411
412 *idx_s = 0;
413 *sub = 0;
414 return 0;
415}
416
417
418
419
420
421
422
423
424static void
425batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb,
426 struct batadv_priv *bat_priv,
427 struct batadv_hard_iface *if_outgoing)
428{
429 struct batadv_hashtable *hash = bat_priv->orig_hash;
430 struct hlist_head *head;
431 int bucket = cb->args[0];
432 int idx = cb->args[1];
433 int sub = cb->args[2];
434 int portid = NETLINK_CB(cb->skb).portid;
435
436 while (bucket < hash->size) {
437 head = &hash->table[bucket];
438
439 if (batadv_v_orig_dump_bucket(msg, portid,
440 cb->nlh->nlmsg_seq,
441 bat_priv, if_outgoing, head, &idx,
442 &sub))
443 break;
444
445 bucket++;
446 }
447
448 cb->args[0] = bucket;
449 cb->args[1] = idx;
450 cb->args[2] = sub;
451}
452
453static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
454 struct batadv_hard_iface *if_outgoing1,
455 struct batadv_neigh_node *neigh2,
456 struct batadv_hard_iface *if_outgoing2)
457{
458 struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
459 int ret = 0;
460
461 ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
462 if (!ifinfo1)
463 goto err_ifinfo1;
464
465 ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
466 if (!ifinfo2)
467 goto err_ifinfo2;
468
469 ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
470
471 batadv_neigh_ifinfo_put(ifinfo2);
472err_ifinfo2:
473 batadv_neigh_ifinfo_put(ifinfo1);
474err_ifinfo1:
475 return ret;
476}
477
478static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
479 struct batadv_hard_iface *if_outgoing1,
480 struct batadv_neigh_node *neigh2,
481 struct batadv_hard_iface *if_outgoing2)
482{
483 struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
484 u32 threshold;
485 bool ret = false;
486
487 ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
488 if (!ifinfo1)
489 goto err_ifinfo1;
490
491 ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
492 if (!ifinfo2)
493 goto err_ifinfo2;
494
495 threshold = ifinfo1->bat_v.throughput / 4;
496 threshold = ifinfo1->bat_v.throughput - threshold;
497
498 ret = ifinfo2->bat_v.throughput > threshold;
499
500 batadv_neigh_ifinfo_put(ifinfo2);
501err_ifinfo2:
502 batadv_neigh_ifinfo_put(ifinfo1);
503err_ifinfo1:
504 return ret;
505}
506
507
508
509
510
511static void batadv_v_init_sel_class(struct batadv_priv *bat_priv)
512{
513
514 atomic_set(&bat_priv->gw.sel_class, 50);
515}
516
517static ssize_t batadv_v_store_sel_class(struct batadv_priv *bat_priv,
518 char *buff, size_t count)
519{
520 u32 old_class, class;
521
522 if (!batadv_parse_throughput(bat_priv->soft_iface, buff,
523 "B.A.T.M.A.N. V GW selection class",
524 &class))
525 return -EINVAL;
526
527 old_class = atomic_read(&bat_priv->gw.sel_class);
528 atomic_set(&bat_priv->gw.sel_class, class);
529
530 if (old_class != class)
531 batadv_gw_reselect(bat_priv);
532
533 return count;
534}
535
536
537
538
539
540
541
542
543
544
545static int batadv_v_gw_throughput_get(struct batadv_gw_node *gw_node, u32 *bw)
546{
547 struct batadv_neigh_ifinfo *router_ifinfo = NULL;
548 struct batadv_orig_node *orig_node;
549 struct batadv_neigh_node *router;
550 int ret = -1;
551
552 orig_node = gw_node->orig_node;
553 router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
554 if (!router)
555 goto out;
556
557 router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
558 if (!router_ifinfo)
559 goto out;
560
561
562
563
564
565
566 *bw = router_ifinfo->bat_v.throughput;
567 *bw = min_t(u32, *bw, gw_node->bandwidth_down);
568
569 ret = 0;
570out:
571 if (router)
572 batadv_neigh_node_put(router);
573 if (router_ifinfo)
574 batadv_neigh_ifinfo_put(router_ifinfo);
575
576 return ret;
577}
578
579
580
581
582
583
584
585static struct batadv_gw_node *
586batadv_v_gw_get_best_gw_node(struct batadv_priv *bat_priv)
587{
588 struct batadv_gw_node *gw_node, *curr_gw = NULL;
589 u32 max_bw = 0, bw;
590
591 rcu_read_lock();
592 hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
593 if (!kref_get_unless_zero(&gw_node->refcount))
594 continue;
595
596 if (batadv_v_gw_throughput_get(gw_node, &bw) < 0)
597 goto next;
598
599 if (curr_gw && bw <= max_bw)
600 goto next;
601
602 if (curr_gw)
603 batadv_gw_node_put(curr_gw);
604
605 curr_gw = gw_node;
606 kref_get(&curr_gw->refcount);
607 max_bw = bw;
608
609next:
610 batadv_gw_node_put(gw_node);
611 }
612 rcu_read_unlock();
613
614 return curr_gw;
615}
616
617
618
619
620
621
622
623
624
625static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv,
626 struct batadv_orig_node *curr_gw_orig,
627 struct batadv_orig_node *orig_node)
628{
629 struct batadv_gw_node *curr_gw, *orig_gw = NULL;
630 u32 gw_throughput, orig_throughput, threshold;
631 bool ret = false;
632
633 threshold = atomic_read(&bat_priv->gw.sel_class);
634
635 curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig);
636 if (!curr_gw) {
637 ret = true;
638 goto out;
639 }
640
641 if (batadv_v_gw_throughput_get(curr_gw, &gw_throughput) < 0) {
642 ret = true;
643 goto out;
644 }
645
646 orig_gw = batadv_gw_node_get(bat_priv, orig_node);
647 if (!orig_gw)
648 goto out;
649
650 if (batadv_v_gw_throughput_get(orig_gw, &orig_throughput) < 0)
651 goto out;
652
653 if (orig_throughput < gw_throughput)
654 goto out;
655
656 if ((orig_throughput - gw_throughput) < threshold)
657 goto out;
658
659 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
660 "Restarting gateway selection: better gateway found (throughput curr: %u, throughput new: %u)\n",
661 gw_throughput, orig_throughput);
662
663 ret = true;
664out:
665 if (curr_gw)
666 batadv_gw_node_put(curr_gw);
667 if (orig_gw)
668 batadv_gw_node_put(orig_gw);
669
670 return ret;
671}
672
673
674
675
676
677
678
679
680
681
682
683static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid,
684 struct netlink_callback *cb,
685 struct batadv_priv *bat_priv,
686 struct batadv_gw_node *gw_node)
687{
688 struct batadv_neigh_ifinfo *router_ifinfo = NULL;
689 struct batadv_neigh_node *router;
690 struct batadv_gw_node *curr_gw = NULL;
691 int ret = 0;
692 void *hdr;
693
694 router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
695 if (!router)
696 goto out;
697
698 router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
699 if (!router_ifinfo)
700 goto out;
701
702 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
703
704 hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
705 &batadv_netlink_family, NLM_F_MULTI,
706 BATADV_CMD_GET_GATEWAYS);
707 if (!hdr) {
708 ret = -ENOBUFS;
709 goto out;
710 }
711
712 genl_dump_check_consistent(cb, hdr);
713
714 ret = -EMSGSIZE;
715
716 if (curr_gw == gw_node) {
717 if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) {
718 genlmsg_cancel(msg, hdr);
719 goto out;
720 }
721 }
722
723 if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
724 gw_node->orig_node->orig)) {
725 genlmsg_cancel(msg, hdr);
726 goto out;
727 }
728
729 if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT,
730 router_ifinfo->bat_v.throughput)) {
731 genlmsg_cancel(msg, hdr);
732 goto out;
733 }
734
735 if (nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN, router->addr)) {
736 genlmsg_cancel(msg, hdr);
737 goto out;
738 }
739
740 if (nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
741 router->if_incoming->net_dev->name)) {
742 genlmsg_cancel(msg, hdr);
743 goto out;
744 }
745
746 if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
747 router->if_incoming->net_dev->ifindex)) {
748 genlmsg_cancel(msg, hdr);
749 goto out;
750 }
751
752 if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
753 gw_node->bandwidth_down)) {
754 genlmsg_cancel(msg, hdr);
755 goto out;
756 }
757
758 if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP, gw_node->bandwidth_up)) {
759 genlmsg_cancel(msg, hdr);
760 goto out;
761 }
762
763 genlmsg_end(msg, hdr);
764 ret = 0;
765
766out:
767 if (curr_gw)
768 batadv_gw_node_put(curr_gw);
769 if (router_ifinfo)
770 batadv_neigh_ifinfo_put(router_ifinfo);
771 if (router)
772 batadv_neigh_node_put(router);
773 return ret;
774}
775
776
777
778
779
780
781
782static void batadv_v_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
783 struct batadv_priv *bat_priv)
784{
785 int portid = NETLINK_CB(cb->skb).portid;
786 struct batadv_gw_node *gw_node;
787 int idx_skip = cb->args[0];
788 int idx = 0;
789
790 spin_lock_bh(&bat_priv->gw.list_lock);
791 cb->seq = bat_priv->gw.generation << 1 | 1;
792
793 hlist_for_each_entry(gw_node, &bat_priv->gw.gateway_list, list) {
794 if (idx++ < idx_skip)
795 continue;
796
797 if (batadv_v_gw_dump_entry(msg, portid, cb, bat_priv,
798 gw_node)) {
799 idx_skip = idx - 1;
800 goto unlock;
801 }
802 }
803
804 idx_skip = idx;
805unlock:
806 spin_unlock_bh(&bat_priv->gw.list_lock);
807
808 cb->args[0] = idx_skip;
809}
810
811static struct batadv_algo_ops batadv_batman_v __read_mostly = {
812 .name = "BATMAN_V",
813 .iface = {
814 .activate = batadv_v_iface_activate,
815 .enable = batadv_v_iface_enable,
816 .disable = batadv_v_iface_disable,
817 .update_mac = batadv_v_iface_update_mac,
818 .primary_set = batadv_v_primary_iface_set,
819 },
820 .neigh = {
821 .hardif_init = batadv_v_hardif_neigh_init,
822 .cmp = batadv_v_neigh_cmp,
823 .is_similar_or_better = batadv_v_neigh_is_sob,
824 .dump = batadv_v_neigh_dump,
825 },
826 .orig = {
827 .dump = batadv_v_orig_dump,
828 },
829 .gw = {
830 .init_sel_class = batadv_v_init_sel_class,
831 .store_sel_class = batadv_v_store_sel_class,
832 .get_best_gw_node = batadv_v_gw_get_best_gw_node,
833 .is_eligible = batadv_v_gw_is_eligible,
834 .dump = batadv_v_gw_dump,
835 },
836};
837
838
839
840
841
842
843void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface)
844{
845
846
847
848 atomic_set(&hard_iface->bat_v.throughput_override, 0);
849 atomic_set(&hard_iface->bat_v.elp_interval, 500);
850
851 hard_iface->bat_v.aggr_len = 0;
852 skb_queue_head_init(&hard_iface->bat_v.aggr_list);
853 INIT_DELAYED_WORK(&hard_iface->bat_v.aggr_wq,
854 batadv_v_ogm_aggr_work);
855}
856
857
858
859
860
861
862
863
864int batadv_v_mesh_init(struct batadv_priv *bat_priv)
865{
866 int ret = 0;
867
868 ret = batadv_v_ogm_init(bat_priv);
869 if (ret < 0)
870 return ret;
871
872 return 0;
873}
874
875
876
877
878
879void batadv_v_mesh_free(struct batadv_priv *bat_priv)
880{
881 batadv_v_ogm_free(bat_priv);
882}
883
884
885
886
887
888
889
890
891
892int __init batadv_v_init(void)
893{
894 int ret;
895
896
897 ret = batadv_recv_handler_register(BATADV_ELP,
898 batadv_v_elp_packet_recv);
899 if (ret < 0)
900 return ret;
901
902 ret = batadv_recv_handler_register(BATADV_OGM2,
903 batadv_v_ogm_packet_recv);
904 if (ret < 0)
905 goto elp_unregister;
906
907 ret = batadv_algo_register(&batadv_batman_v);
908 if (ret < 0)
909 goto ogm_unregister;
910
911 return ret;
912
913ogm_unregister:
914 batadv_recv_handler_unregister(BATADV_OGM2);
915
916elp_unregister:
917 batadv_recv_handler_unregister(BATADV_ELP);
918
919 return ret;
920}
921