0001
0002
0003
0004
0005
0006
0007 #include "bat_v.h"
0008 #include "main.h"
0009
0010 #include <linux/atomic.h>
0011 #include <linux/cache.h>
0012 #include <linux/errno.h>
0013 #include <linux/if_ether.h>
0014 #include <linux/init.h>
0015 #include <linux/jiffies.h>
0016 #include <linux/kref.h>
0017 #include <linux/list.h>
0018 #include <linux/minmax.h>
0019 #include <linux/netdevice.h>
0020 #include <linux/netlink.h>
0021 #include <linux/rculist.h>
0022 #include <linux/rcupdate.h>
0023 #include <linux/skbuff.h>
0024 #include <linux/spinlock.h>
0025 #include <linux/stddef.h>
0026 #include <linux/types.h>
0027 #include <linux/workqueue.h>
0028 #include <net/genetlink.h>
0029 #include <net/netlink.h>
0030 #include <uapi/linux/batadv_packet.h>
0031 #include <uapi/linux/batman_adv.h>
0032
0033 #include "bat_algo.h"
0034 #include "bat_v_elp.h"
0035 #include "bat_v_ogm.h"
0036 #include "gateway_client.h"
0037 #include "gateway_common.h"
0038 #include "hard-interface.h"
0039 #include "hash.h"
0040 #include "log.h"
0041 #include "netlink.h"
0042 #include "originator.h"
0043
0044 static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
0045 {
0046 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
0047 struct batadv_hard_iface *primary_if;
0048
0049 primary_if = batadv_primary_if_get_selected(bat_priv);
0050
0051 if (primary_if) {
0052 batadv_v_elp_iface_activate(primary_if, hard_iface);
0053 batadv_hardif_put(primary_if);
0054 }
0055
0056
0057
0058
0059
0060 if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
0061 hard_iface->if_status = BATADV_IF_ACTIVE;
0062 }
0063
0064 static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
0065 {
0066 int ret;
0067
0068 ret = batadv_v_elp_iface_enable(hard_iface);
0069 if (ret < 0)
0070 return ret;
0071
0072 ret = batadv_v_ogm_iface_enable(hard_iface);
0073 if (ret < 0)
0074 batadv_v_elp_iface_disable(hard_iface);
0075
0076 return ret;
0077 }
0078
0079 static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
0080 {
0081 batadv_v_ogm_iface_disable(hard_iface);
0082 batadv_v_elp_iface_disable(hard_iface);
0083 }
0084
0085 static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
0086 {
0087 batadv_v_elp_primary_iface_set(hard_iface);
0088 batadv_v_ogm_primary_iface_set(hard_iface);
0089 }
0090
0091
0092
0093
0094
0095
0096
0097
0098 static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
0099 {
0100 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
0101 struct batadv_hard_iface *primary_if;
0102
0103 primary_if = batadv_primary_if_get_selected(bat_priv);
0104 if (primary_if != hard_iface)
0105 goto out;
0106
0107 batadv_v_primary_iface_set(hard_iface);
0108 out:
0109 batadv_hardif_put(primary_if);
0110 }
0111
0112 static void
0113 batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
0114 {
0115 ewma_throughput_init(&hardif_neigh->bat_v.throughput);
0116 INIT_WORK(&hardif_neigh->bat_v.metric_work,
0117 batadv_v_elp_throughput_metric_update);
0118 }
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129 static int
0130 batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
0131 struct batadv_hardif_neigh_node *hardif_neigh)
0132 {
0133 void *hdr;
0134 unsigned int last_seen_msecs;
0135 u32 throughput;
0136
0137 last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen);
0138 throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
0139 throughput = throughput * 100;
0140
0141 hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
0142 BATADV_CMD_GET_NEIGHBORS);
0143 if (!hdr)
0144 return -ENOBUFS;
0145
0146 if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
0147 hardif_neigh->addr) ||
0148 nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
0149 hardif_neigh->if_incoming->net_dev->name) ||
0150 nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
0151 hardif_neigh->if_incoming->net_dev->ifindex) ||
0152 nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
0153 last_seen_msecs) ||
0154 nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput))
0155 goto nla_put_failure;
0156
0157 genlmsg_end(msg, hdr);
0158 return 0;
0159
0160 nla_put_failure:
0161 genlmsg_cancel(msg, hdr);
0162 return -EMSGSIZE;
0163 }
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179 static int
0180 batadv_v_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
0181 struct batadv_priv *bat_priv,
0182 struct batadv_hard_iface *hard_iface,
0183 int *idx_s)
0184 {
0185 struct batadv_hardif_neigh_node *hardif_neigh;
0186 int idx = 0;
0187
0188 hlist_for_each_entry_rcu(hardif_neigh,
0189 &hard_iface->neigh_list, list) {
0190 if (idx++ < *idx_s)
0191 continue;
0192
0193 if (batadv_v_neigh_dump_neigh(msg, portid, seq, hardif_neigh)) {
0194 *idx_s = idx - 1;
0195 return -EMSGSIZE;
0196 }
0197 }
0198
0199 *idx_s = 0;
0200 return 0;
0201 }
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211 static void
0212 batadv_v_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb,
0213 struct batadv_priv *bat_priv,
0214 struct batadv_hard_iface *single_hardif)
0215 {
0216 struct batadv_hard_iface *hard_iface;
0217 int i_hardif = 0;
0218 int i_hardif_s = cb->args[0];
0219 int idx = cb->args[1];
0220 int portid = NETLINK_CB(cb->skb).portid;
0221
0222 rcu_read_lock();
0223 if (single_hardif) {
0224 if (i_hardif_s == 0) {
0225 if (batadv_v_neigh_dump_hardif(msg, portid,
0226 cb->nlh->nlmsg_seq,
0227 bat_priv, single_hardif,
0228 &idx) == 0)
0229 i_hardif++;
0230 }
0231 } else {
0232 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
0233 if (hard_iface->soft_iface != bat_priv->soft_iface)
0234 continue;
0235
0236 if (i_hardif++ < i_hardif_s)
0237 continue;
0238
0239 if (batadv_v_neigh_dump_hardif(msg, portid,
0240 cb->nlh->nlmsg_seq,
0241 bat_priv, hard_iface,
0242 &idx)) {
0243 i_hardif--;
0244 break;
0245 }
0246 }
0247 }
0248 rcu_read_unlock();
0249
0250 cb->args[0] = i_hardif;
0251 cb->args[1] = idx;
0252 }
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 static int
0268 batadv_v_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
0269 struct batadv_priv *bat_priv,
0270 struct batadv_hard_iface *if_outgoing,
0271 struct batadv_orig_node *orig_node,
0272 struct batadv_neigh_node *neigh_node,
0273 bool best)
0274 {
0275 struct batadv_neigh_ifinfo *n_ifinfo;
0276 unsigned int last_seen_msecs;
0277 u32 throughput;
0278 void *hdr;
0279
0280 n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
0281 if (!n_ifinfo)
0282 return 0;
0283
0284 throughput = n_ifinfo->bat_v.throughput * 100;
0285
0286 batadv_neigh_ifinfo_put(n_ifinfo);
0287
0288 last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen);
0289
0290 if (if_outgoing != BATADV_IF_DEFAULT &&
0291 if_outgoing != neigh_node->if_incoming)
0292 return 0;
0293
0294 hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
0295 BATADV_CMD_GET_ORIGINATORS);
0296 if (!hdr)
0297 return -ENOBUFS;
0298
0299 if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) ||
0300 nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
0301 neigh_node->addr) ||
0302 nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
0303 neigh_node->if_incoming->net_dev->name) ||
0304 nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
0305 neigh_node->if_incoming->net_dev->ifindex) ||
0306 nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput) ||
0307 nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
0308 last_seen_msecs))
0309 goto nla_put_failure;
0310
0311 if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
0312 goto nla_put_failure;
0313
0314 genlmsg_end(msg, hdr);
0315 return 0;
0316
0317 nla_put_failure:
0318 genlmsg_cancel(msg, hdr);
0319 return -EMSGSIZE;
0320 }
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336 static int
0337 batadv_v_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
0338 struct batadv_priv *bat_priv,
0339 struct batadv_hard_iface *if_outgoing,
0340 struct batadv_orig_node *orig_node, int *sub_s)
0341 {
0342 struct batadv_neigh_node *neigh_node_best;
0343 struct batadv_neigh_node *neigh_node;
0344 int sub = 0;
0345 bool best;
0346
0347 neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing);
0348 if (!neigh_node_best)
0349 goto out;
0350
0351 hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
0352 if (sub++ < *sub_s)
0353 continue;
0354
0355 best = (neigh_node == neigh_node_best);
0356
0357 if (batadv_v_orig_dump_subentry(msg, portid, seq, bat_priv,
0358 if_outgoing, orig_node,
0359 neigh_node, best)) {
0360 batadv_neigh_node_put(neigh_node_best);
0361
0362 *sub_s = sub - 1;
0363 return -EMSGSIZE;
0364 }
0365 }
0366
0367 out:
0368 batadv_neigh_node_put(neigh_node_best);
0369
0370 *sub_s = 0;
0371 return 0;
0372 }
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387 static int
0388 batadv_v_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
0389 struct batadv_priv *bat_priv,
0390 struct batadv_hard_iface *if_outgoing,
0391 struct hlist_head *head, int *idx_s, int *sub)
0392 {
0393 struct batadv_orig_node *orig_node;
0394 int idx = 0;
0395
0396 rcu_read_lock();
0397 hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
0398 if (idx++ < *idx_s)
0399 continue;
0400
0401 if (batadv_v_orig_dump_entry(msg, portid, seq, bat_priv,
0402 if_outgoing, orig_node, sub)) {
0403 rcu_read_unlock();
0404 *idx_s = idx - 1;
0405 return -EMSGSIZE;
0406 }
0407 }
0408 rcu_read_unlock();
0409
0410 *idx_s = 0;
0411 *sub = 0;
0412 return 0;
0413 }
0414
0415
0416
0417
0418
0419
0420
0421
0422 static void
0423 batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb,
0424 struct batadv_priv *bat_priv,
0425 struct batadv_hard_iface *if_outgoing)
0426 {
0427 struct batadv_hashtable *hash = bat_priv->orig_hash;
0428 struct hlist_head *head;
0429 int bucket = cb->args[0];
0430 int idx = cb->args[1];
0431 int sub = cb->args[2];
0432 int portid = NETLINK_CB(cb->skb).portid;
0433
0434 while (bucket < hash->size) {
0435 head = &hash->table[bucket];
0436
0437 if (batadv_v_orig_dump_bucket(msg, portid,
0438 cb->nlh->nlmsg_seq,
0439 bat_priv, if_outgoing, head, &idx,
0440 &sub))
0441 break;
0442
0443 bucket++;
0444 }
0445
0446 cb->args[0] = bucket;
0447 cb->args[1] = idx;
0448 cb->args[2] = sub;
0449 }
0450
0451 static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
0452 struct batadv_hard_iface *if_outgoing1,
0453 struct batadv_neigh_node *neigh2,
0454 struct batadv_hard_iface *if_outgoing2)
0455 {
0456 struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
0457 int ret = 0;
0458
0459 ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
0460 if (!ifinfo1)
0461 goto err_ifinfo1;
0462
0463 ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
0464 if (!ifinfo2)
0465 goto err_ifinfo2;
0466
0467 ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
0468
0469 batadv_neigh_ifinfo_put(ifinfo2);
0470 err_ifinfo2:
0471 batadv_neigh_ifinfo_put(ifinfo1);
0472 err_ifinfo1:
0473 return ret;
0474 }
0475
0476 static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
0477 struct batadv_hard_iface *if_outgoing1,
0478 struct batadv_neigh_node *neigh2,
0479 struct batadv_hard_iface *if_outgoing2)
0480 {
0481 struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
0482 u32 threshold;
0483 bool ret = false;
0484
0485 ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
0486 if (!ifinfo1)
0487 goto err_ifinfo1;
0488
0489 ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
0490 if (!ifinfo2)
0491 goto err_ifinfo2;
0492
0493 threshold = ifinfo1->bat_v.throughput / 4;
0494 threshold = ifinfo1->bat_v.throughput - threshold;
0495
0496 ret = ifinfo2->bat_v.throughput > threshold;
0497
0498 batadv_neigh_ifinfo_put(ifinfo2);
0499 err_ifinfo2:
0500 batadv_neigh_ifinfo_put(ifinfo1);
0501 err_ifinfo1:
0502 return ret;
0503 }
0504
0505
0506
0507
0508
0509 static void batadv_v_init_sel_class(struct batadv_priv *bat_priv)
0510 {
0511
0512 atomic_set(&bat_priv->gw.sel_class, 50);
0513 }
0514
0515 static ssize_t batadv_v_store_sel_class(struct batadv_priv *bat_priv,
0516 char *buff, size_t count)
0517 {
0518 u32 old_class, class;
0519
0520 if (!batadv_parse_throughput(bat_priv->soft_iface, buff,
0521 "B.A.T.M.A.N. V GW selection class",
0522 &class))
0523 return -EINVAL;
0524
0525 old_class = atomic_read(&bat_priv->gw.sel_class);
0526 atomic_set(&bat_priv->gw.sel_class, class);
0527
0528 if (old_class != class)
0529 batadv_gw_reselect(bat_priv);
0530
0531 return count;
0532 }
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543 static int batadv_v_gw_throughput_get(struct batadv_gw_node *gw_node, u32 *bw)
0544 {
0545 struct batadv_neigh_ifinfo *router_ifinfo = NULL;
0546 struct batadv_orig_node *orig_node;
0547 struct batadv_neigh_node *router;
0548 int ret = -1;
0549
0550 orig_node = gw_node->orig_node;
0551 router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
0552 if (!router)
0553 goto out;
0554
0555 router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
0556 if (!router_ifinfo)
0557 goto out;
0558
0559
0560
0561
0562
0563
0564 *bw = router_ifinfo->bat_v.throughput;
0565 *bw = min_t(u32, *bw, gw_node->bandwidth_down);
0566
0567 ret = 0;
0568 out:
0569 batadv_neigh_node_put(router);
0570 batadv_neigh_ifinfo_put(router_ifinfo);
0571
0572 return ret;
0573 }
0574
0575
0576
0577
0578
0579
0580
0581 static struct batadv_gw_node *
0582 batadv_v_gw_get_best_gw_node(struct batadv_priv *bat_priv)
0583 {
0584 struct batadv_gw_node *gw_node, *curr_gw = NULL;
0585 u32 max_bw = 0, bw;
0586
0587 rcu_read_lock();
0588 hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
0589 if (!kref_get_unless_zero(&gw_node->refcount))
0590 continue;
0591
0592 if (batadv_v_gw_throughput_get(gw_node, &bw) < 0)
0593 goto next;
0594
0595 if (curr_gw && bw <= max_bw)
0596 goto next;
0597
0598 batadv_gw_node_put(curr_gw);
0599
0600 curr_gw = gw_node;
0601 kref_get(&curr_gw->refcount);
0602 max_bw = bw;
0603
0604 next:
0605 batadv_gw_node_put(gw_node);
0606 }
0607 rcu_read_unlock();
0608
0609 return curr_gw;
0610 }
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620 static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv,
0621 struct batadv_orig_node *curr_gw_orig,
0622 struct batadv_orig_node *orig_node)
0623 {
0624 struct batadv_gw_node *curr_gw, *orig_gw = NULL;
0625 u32 gw_throughput, orig_throughput, threshold;
0626 bool ret = false;
0627
0628 threshold = atomic_read(&bat_priv->gw.sel_class);
0629
0630 curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig);
0631 if (!curr_gw) {
0632 ret = true;
0633 goto out;
0634 }
0635
0636 if (batadv_v_gw_throughput_get(curr_gw, &gw_throughput) < 0) {
0637 ret = true;
0638 goto out;
0639 }
0640
0641 orig_gw = batadv_gw_node_get(bat_priv, orig_node);
0642 if (!orig_gw)
0643 goto out;
0644
0645 if (batadv_v_gw_throughput_get(orig_gw, &orig_throughput) < 0)
0646 goto out;
0647
0648 if (orig_throughput < gw_throughput)
0649 goto out;
0650
0651 if ((orig_throughput - gw_throughput) < threshold)
0652 goto out;
0653
0654 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
0655 "Restarting gateway selection: better gateway found (throughput curr: %u, throughput new: %u)\n",
0656 gw_throughput, orig_throughput);
0657
0658 ret = true;
0659 out:
0660 batadv_gw_node_put(curr_gw);
0661 batadv_gw_node_put(orig_gw);
0662
0663 return ret;
0664 }
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675
0676 static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid,
0677 struct netlink_callback *cb,
0678 struct batadv_priv *bat_priv,
0679 struct batadv_gw_node *gw_node)
0680 {
0681 struct batadv_neigh_ifinfo *router_ifinfo = NULL;
0682 struct batadv_neigh_node *router;
0683 struct batadv_gw_node *curr_gw = NULL;
0684 int ret = 0;
0685 void *hdr;
0686
0687 router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
0688 if (!router)
0689 goto out;
0690
0691 router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
0692 if (!router_ifinfo)
0693 goto out;
0694
0695 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
0696
0697 hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
0698 &batadv_netlink_family, NLM_F_MULTI,
0699 BATADV_CMD_GET_GATEWAYS);
0700 if (!hdr) {
0701 ret = -ENOBUFS;
0702 goto out;
0703 }
0704
0705 genl_dump_check_consistent(cb, hdr);
0706
0707 ret = -EMSGSIZE;
0708
0709 if (curr_gw == gw_node) {
0710 if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) {
0711 genlmsg_cancel(msg, hdr);
0712 goto out;
0713 }
0714 }
0715
0716 if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
0717 gw_node->orig_node->orig)) {
0718 genlmsg_cancel(msg, hdr);
0719 goto out;
0720 }
0721
0722 if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT,
0723 router_ifinfo->bat_v.throughput)) {
0724 genlmsg_cancel(msg, hdr);
0725 goto out;
0726 }
0727
0728 if (nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN, router->addr)) {
0729 genlmsg_cancel(msg, hdr);
0730 goto out;
0731 }
0732
0733 if (nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
0734 router->if_incoming->net_dev->name)) {
0735 genlmsg_cancel(msg, hdr);
0736 goto out;
0737 }
0738
0739 if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
0740 router->if_incoming->net_dev->ifindex)) {
0741 genlmsg_cancel(msg, hdr);
0742 goto out;
0743 }
0744
0745 if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
0746 gw_node->bandwidth_down)) {
0747 genlmsg_cancel(msg, hdr);
0748 goto out;
0749 }
0750
0751 if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP, gw_node->bandwidth_up)) {
0752 genlmsg_cancel(msg, hdr);
0753 goto out;
0754 }
0755
0756 genlmsg_end(msg, hdr);
0757 ret = 0;
0758
0759 out:
0760 batadv_gw_node_put(curr_gw);
0761 batadv_neigh_ifinfo_put(router_ifinfo);
0762 batadv_neigh_node_put(router);
0763 return ret;
0764 }
0765
0766
0767
0768
0769
0770
0771
0772 static void batadv_v_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
0773 struct batadv_priv *bat_priv)
0774 {
0775 int portid = NETLINK_CB(cb->skb).portid;
0776 struct batadv_gw_node *gw_node;
0777 int idx_skip = cb->args[0];
0778 int idx = 0;
0779
0780 spin_lock_bh(&bat_priv->gw.list_lock);
0781 cb->seq = bat_priv->gw.generation << 1 | 1;
0782
0783 hlist_for_each_entry(gw_node, &bat_priv->gw.gateway_list, list) {
0784 if (idx++ < idx_skip)
0785 continue;
0786
0787 if (batadv_v_gw_dump_entry(msg, portid, cb, bat_priv,
0788 gw_node)) {
0789 idx_skip = idx - 1;
0790 goto unlock;
0791 }
0792 }
0793
0794 idx_skip = idx;
0795 unlock:
0796 spin_unlock_bh(&bat_priv->gw.list_lock);
0797
0798 cb->args[0] = idx_skip;
0799 }
0800
0801 static struct batadv_algo_ops batadv_batman_v __read_mostly = {
0802 .name = "BATMAN_V",
0803 .iface = {
0804 .activate = batadv_v_iface_activate,
0805 .enable = batadv_v_iface_enable,
0806 .disable = batadv_v_iface_disable,
0807 .update_mac = batadv_v_iface_update_mac,
0808 .primary_set = batadv_v_primary_iface_set,
0809 },
0810 .neigh = {
0811 .hardif_init = batadv_v_hardif_neigh_init,
0812 .cmp = batadv_v_neigh_cmp,
0813 .is_similar_or_better = batadv_v_neigh_is_sob,
0814 .dump = batadv_v_neigh_dump,
0815 },
0816 .orig = {
0817 .dump = batadv_v_orig_dump,
0818 },
0819 .gw = {
0820 .init_sel_class = batadv_v_init_sel_class,
0821 .store_sel_class = batadv_v_store_sel_class,
0822 .get_best_gw_node = batadv_v_gw_get_best_gw_node,
0823 .is_eligible = batadv_v_gw_is_eligible,
0824 .dump = batadv_v_gw_dump,
0825 },
0826 };
0827
0828
0829
0830
0831
0832
0833 void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface)
0834 {
0835
0836
0837
0838 atomic_set(&hard_iface->bat_v.throughput_override, 0);
0839 atomic_set(&hard_iface->bat_v.elp_interval, 500);
0840
0841 hard_iface->bat_v.aggr_len = 0;
0842 skb_queue_head_init(&hard_iface->bat_v.aggr_list);
0843 INIT_DELAYED_WORK(&hard_iface->bat_v.aggr_wq,
0844 batadv_v_ogm_aggr_work);
0845 }
0846
0847
0848
0849
0850
0851
0852
0853
0854 int batadv_v_mesh_init(struct batadv_priv *bat_priv)
0855 {
0856 int ret = 0;
0857
0858 ret = batadv_v_ogm_init(bat_priv);
0859 if (ret < 0)
0860 return ret;
0861
0862 return 0;
0863 }
0864
0865
0866
0867
0868
0869 void batadv_v_mesh_free(struct batadv_priv *bat_priv)
0870 {
0871 batadv_v_ogm_free(bat_priv);
0872 }
0873
0874
0875
0876
0877
0878
0879
0880
0881
0882 int __init batadv_v_init(void)
0883 {
0884 int ret;
0885
0886
0887 ret = batadv_recv_handler_register(BATADV_ELP,
0888 batadv_v_elp_packet_recv);
0889 if (ret < 0)
0890 return ret;
0891
0892 ret = batadv_recv_handler_register(BATADV_OGM2,
0893 batadv_v_ogm_packet_recv);
0894 if (ret < 0)
0895 goto elp_unregister;
0896
0897 ret = batadv_algo_register(&batadv_batman_v);
0898 if (ret < 0)
0899 goto ogm_unregister;
0900
0901 return ret;
0902
0903 ogm_unregister:
0904 batadv_recv_handler_unregister(BATADV_OGM2);
0905
0906 elp_unregister:
0907 batadv_recv_handler_unregister(BATADV_ELP);
0908
0909 return ret;
0910 }