linux/net/batman-adv/bat_v.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (C) B.A.T.M.A.N. contributors:
   3 *
   4 * Linus Lüssing, Marek Lindner
   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        /* B.A.T.M.A.N. V does not use any queuing mechanism, therefore it can
  57         * set the interface as ACTIVE right away, without any risk of race
  58         * condition
  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 * batadv_v_iface_update_mac() - react to hard-interface MAC address change
  93 * @hard_iface: the modified interface
  94 *
  95 * If the modified interface is the primary one, update the originator
  96 * address in the ELP and OGM messages to reflect the new MAC address.
  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 * batadv_v_neigh_dump_neigh() - Dump a neighbour into a message
 123 * @msg: Netlink message to dump into
 124 * @portid: Port making netlink request
 125 * @seq: Sequence number of netlink message
 126 * @hardif_neigh: Neighbour to dump
 127 *
 128 * Return: Error code, or 0 on success
 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 * batadv_v_neigh_dump_hardif() - Dump the  neighbours of a hard interface into
 168 *  a message
 169 * @msg: Netlink message to dump into
 170 * @portid: Port making netlink request
 171 * @seq: Sequence number of netlink message
 172 * @bat_priv: The bat priv with all the soft interface information
 173 * @hard_iface: The hard interface to be dumped
 174 * @idx_s: Entries to be skipped
 175 *
 176 * This function assumes the caller holds rcu_read_lock().
 177 *
 178 * Return: Error code, or 0 on success
 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 * batadv_v_neigh_dump() - Dump the neighbours of a hard interface  into a
 206 *  message
 207 * @msg: Netlink message to dump into
 208 * @cb: Control block containing additional options
 209 * @bat_priv: The bat priv with all the soft interface information
 210 * @single_hardif: Limit dumping to this hard interface
 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 * batadv_v_orig_dump_subentry() - Dump an originator subentry into a message
 257 * @msg: Netlink message to dump into
 258 * @portid: Port making netlink request
 259 * @seq: Sequence number of netlink message
 260 * @bat_priv: The bat priv with all the soft interface information
 261 * @if_outgoing: Limit dump to entries with this outgoing interface
 262 * @orig_node: Originator to dump
 263 * @neigh_node: Single hops neighbour
 264 * @best: Is the best originator
 265 *
 266 * Return: Error code, or 0 on success
 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 * batadv_v_orig_dump_entry() - Dump an originator entry into a message
 325 * @msg: Netlink message to dump into
 326 * @portid: Port making netlink request
 327 * @seq: Sequence number of netlink message
 328 * @bat_priv: The bat priv with all the soft interface information
 329 * @if_outgoing: Limit dump to entries with this outgoing interface
 330 * @orig_node: Originator to dump
 331 * @sub_s: Number of sub entries to skip
 332 *
 333 * This function assumes the caller holds rcu_read_lock().
 334 *
 335 * Return: Error code, or 0 on success
 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 * batadv_v_orig_dump_bucket() - Dump an originator bucket into a message
 378 * @msg: Netlink message to dump into
 379 * @portid: Port making netlink request
 380 * @seq: Sequence number of netlink message
 381 * @bat_priv: The bat priv with all the soft interface information
 382 * @if_outgoing: Limit dump to entries with this outgoing interface
 383 * @head: Bucket to be dumped
 384 * @idx_s: Number of entries to be skipped
 385 * @sub: Number of sub entries to be skipped
 386 *
 387 * Return: Error code, or 0 on success
 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 * batadv_v_orig_dump() - Dump the originators into a message
 419 * @msg: Netlink message to dump into
 420 * @cb: Control block containing additional options
 421 * @bat_priv: The bat priv with all the soft interface information
 422 * @if_outgoing: Limit dump to entries with this outgoing interface
 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 * batadv_v_init_sel_class() - initialize GW selection class
 509 * @bat_priv: the bat priv with all the soft interface information
 510 */
 511static void batadv_v_init_sel_class(struct batadv_priv *bat_priv)
 512{
 513        /* set default throughput difference threshold to 5Mbps */
 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 * batadv_v_gw_throughput_get() - retrieve the GW-bandwidth for a given GW
 538 * @gw_node: the GW to retrieve the metric for
 539 * @bw: the pointer where the metric will be stored. The metric is computed as
 540 *  the minimum between the GW advertised throughput and the path throughput to
 541 *  it in the mesh
 542 *
 543 * Return: 0 on success, -1 on failure
 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        /* the GW metric is computed as the minimum between the path throughput
 562         * to reach the GW itself and the advertised bandwidth.
 563         * This gives us an approximation of the effective throughput that the
 564         * client can expect via this particular GW node
 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 * batadv_v_gw_get_best_gw_node() - retrieve the best GW node
 581 * @bat_priv: the bat priv with all the soft interface information
 582 *
 583 * Return: the GW node having the best GW-metric, NULL if no GW is known
 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 * batadv_v_gw_is_eligible() - check if a originator would be selected as GW
 619 * @bat_priv: the bat priv with all the soft interface information
 620 * @curr_gw_orig: originator representing the currently selected GW
 621 * @orig_node: the originator representing the new candidate
 622 *
 623 * Return: true if orig_node can be selected as current GW, false otherwise
 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 * batadv_v_gw_dump_entry() - Dump a gateway into a message
 675 * @msg: Netlink message to dump into
 676 * @portid: Port making netlink request
 677 * @cb: Control block containing additional options
 678 * @bat_priv: The bat priv with all the soft interface information
 679 * @gw_node: Gateway to be dumped
 680 *
 681 * Return: Error code, or 0 on success
 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 * batadv_v_gw_dump() - Dump gateways into a message
 778 * @msg: Netlink message to dump into
 779 * @cb: Control block containing additional options
 780 * @bat_priv: The bat priv with all the soft interface information
 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 * batadv_v_hardif_init() - initialize the algorithm specific fields in the
 840 *  hard-interface object
 841 * @hard_iface: the hard-interface to initialize
 842 */
 843void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface)
 844{
 845        /* enable link throughput auto-detection by setting the throughput
 846         * override to zero
 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 * batadv_v_mesh_init() - initialize the B.A.T.M.A.N. V private resources for a
 859 *  mesh
 860 * @bat_priv: the object representing the mesh interface to initialise
 861 *
 862 * Return: 0 on success or a negative error code otherwise
 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 * batadv_v_mesh_free() - free the B.A.T.M.A.N. V private resources for a mesh
 877 * @bat_priv: the object representing the mesh interface to free
 878 */
 879void batadv_v_mesh_free(struct batadv_priv *bat_priv)
 880{
 881        batadv_v_ogm_free(bat_priv);
 882}
 883
 884/**
 885 * batadv_v_init() - B.A.T.M.A.N. V initialization function
 886 *
 887 * Description: Takes care of initializing all the subcomponents.
 888 * It is invoked upon module load only.
 889 *
 890 * Return: 0 on success or a negative error code otherwise
 891 */
 892int __init batadv_v_init(void)
 893{
 894        int ret;
 895
 896        /* B.A.T.M.A.N. V echo location protocol packet  */
 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