cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bat_v.c (23750B)


      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	batadv_hardif_put(primary_if);
    110}
    111
    112static void
    113batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
    114{
    115	ewma_throughput_init(&hardif_neigh->bat_v.throughput);
    116	INIT_WORK(&hardif_neigh->bat_v.metric_work,
    117		  batadv_v_elp_throughput_metric_update);
    118}
    119
    120/**
    121 * batadv_v_neigh_dump_neigh() - Dump a neighbour into a message
    122 * @msg: Netlink message to dump into
    123 * @portid: Port making netlink request
    124 * @seq: Sequence number of netlink message
    125 * @hardif_neigh: Neighbour to dump
    126 *
    127 * Return: Error code, or 0 on success
    128 */
    129static int
    130batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
    131			  struct batadv_hardif_neigh_node *hardif_neigh)
    132{
    133	void *hdr;
    134	unsigned int last_seen_msecs;
    135	u32 throughput;
    136
    137	last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen);
    138	throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
    139	throughput = throughput * 100;
    140
    141	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
    142			  BATADV_CMD_GET_NEIGHBORS);
    143	if (!hdr)
    144		return -ENOBUFS;
    145
    146	if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
    147		    hardif_neigh->addr) ||
    148	    nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
    149			   hardif_neigh->if_incoming->net_dev->name) ||
    150	    nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
    151			hardif_neigh->if_incoming->net_dev->ifindex) ||
    152	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
    153			last_seen_msecs) ||
    154	    nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput))
    155		goto nla_put_failure;
    156
    157	genlmsg_end(msg, hdr);
    158	return 0;
    159
    160 nla_put_failure:
    161	genlmsg_cancel(msg, hdr);
    162	return -EMSGSIZE;
    163}
    164
    165/**
    166 * batadv_v_neigh_dump_hardif() - Dump the  neighbours of a hard interface into
    167 *  a message
    168 * @msg: Netlink message to dump into
    169 * @portid: Port making netlink request
    170 * @seq: Sequence number of netlink message
    171 * @bat_priv: The bat priv with all the soft interface information
    172 * @hard_iface: The hard interface to be dumped
    173 * @idx_s: Entries to be skipped
    174 *
    175 * This function assumes the caller holds rcu_read_lock().
    176 *
    177 * Return: Error code, or 0 on success
    178 */
    179static int
    180batadv_v_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
    181			   struct batadv_priv *bat_priv,
    182			   struct batadv_hard_iface *hard_iface,
    183			   int *idx_s)
    184{
    185	struct batadv_hardif_neigh_node *hardif_neigh;
    186	int idx = 0;
    187
    188	hlist_for_each_entry_rcu(hardif_neigh,
    189				 &hard_iface->neigh_list, list) {
    190		if (idx++ < *idx_s)
    191			continue;
    192
    193		if (batadv_v_neigh_dump_neigh(msg, portid, seq, hardif_neigh)) {
    194			*idx_s = idx - 1;
    195			return -EMSGSIZE;
    196		}
    197	}
    198
    199	*idx_s = 0;
    200	return 0;
    201}
    202
    203/**
    204 * batadv_v_neigh_dump() - Dump the neighbours of a hard interface  into a
    205 *  message
    206 * @msg: Netlink message to dump into
    207 * @cb: Control block containing additional options
    208 * @bat_priv: The bat priv with all the soft interface information
    209 * @single_hardif: Limit dumping to this hard interface
    210 */
    211static void
    212batadv_v_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb,
    213		    struct batadv_priv *bat_priv,
    214		    struct batadv_hard_iface *single_hardif)
    215{
    216	struct batadv_hard_iface *hard_iface;
    217	int i_hardif = 0;
    218	int i_hardif_s = cb->args[0];
    219	int idx = cb->args[1];
    220	int portid = NETLINK_CB(cb->skb).portid;
    221
    222	rcu_read_lock();
    223	if (single_hardif) {
    224		if (i_hardif_s == 0) {
    225			if (batadv_v_neigh_dump_hardif(msg, portid,
    226						       cb->nlh->nlmsg_seq,
    227						       bat_priv, single_hardif,
    228						       &idx) == 0)
    229				i_hardif++;
    230		}
    231	} else {
    232		list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
    233			if (hard_iface->soft_iface != bat_priv->soft_iface)
    234				continue;
    235
    236			if (i_hardif++ < i_hardif_s)
    237				continue;
    238
    239			if (batadv_v_neigh_dump_hardif(msg, portid,
    240						       cb->nlh->nlmsg_seq,
    241						       bat_priv, hard_iface,
    242						       &idx)) {
    243				i_hardif--;
    244				break;
    245			}
    246		}
    247	}
    248	rcu_read_unlock();
    249
    250	cb->args[0] = i_hardif;
    251	cb->args[1] = idx;
    252}
    253
    254/**
    255 * batadv_v_orig_dump_subentry() - Dump an originator subentry into a message
    256 * @msg: Netlink message to dump into
    257 * @portid: Port making netlink request
    258 * @seq: Sequence number of netlink message
    259 * @bat_priv: The bat priv with all the soft interface information
    260 * @if_outgoing: Limit dump to entries with this outgoing interface
    261 * @orig_node: Originator to dump
    262 * @neigh_node: Single hops neighbour
    263 * @best: Is the best originator
    264 *
    265 * Return: Error code, or 0 on success
    266 */
    267static int
    268batadv_v_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
    269			    struct batadv_priv *bat_priv,
    270			    struct batadv_hard_iface *if_outgoing,
    271			    struct batadv_orig_node *orig_node,
    272			    struct batadv_neigh_node *neigh_node,
    273			    bool best)
    274{
    275	struct batadv_neigh_ifinfo *n_ifinfo;
    276	unsigned int last_seen_msecs;
    277	u32 throughput;
    278	void *hdr;
    279
    280	n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
    281	if (!n_ifinfo)
    282		return 0;
    283
    284	throughput = n_ifinfo->bat_v.throughput * 100;
    285
    286	batadv_neigh_ifinfo_put(n_ifinfo);
    287
    288	last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen);
    289
    290	if (if_outgoing != BATADV_IF_DEFAULT &&
    291	    if_outgoing != neigh_node->if_incoming)
    292		return 0;
    293
    294	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
    295			  BATADV_CMD_GET_ORIGINATORS);
    296	if (!hdr)
    297		return -ENOBUFS;
    298
    299	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) ||
    300	    nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
    301		    neigh_node->addr) ||
    302	    nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
    303			   neigh_node->if_incoming->net_dev->name) ||
    304	    nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
    305			neigh_node->if_incoming->net_dev->ifindex) ||
    306	    nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput) ||
    307	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
    308			last_seen_msecs))
    309		goto nla_put_failure;
    310
    311	if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
    312		goto nla_put_failure;
    313
    314	genlmsg_end(msg, hdr);
    315	return 0;
    316
    317 nla_put_failure:
    318	genlmsg_cancel(msg, hdr);
    319	return -EMSGSIZE;
    320}
    321
    322/**
    323 * batadv_v_orig_dump_entry() - Dump an originator entry into a message
    324 * @msg: Netlink message to dump into
    325 * @portid: Port making netlink request
    326 * @seq: Sequence number of netlink message
    327 * @bat_priv: The bat priv with all the soft interface information
    328 * @if_outgoing: Limit dump to entries with this outgoing interface
    329 * @orig_node: Originator to dump
    330 * @sub_s: Number of sub entries to skip
    331 *
    332 * This function assumes the caller holds rcu_read_lock().
    333 *
    334 * Return: Error code, or 0 on success
    335 */
    336static int
    337batadv_v_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
    338			 struct batadv_priv *bat_priv,
    339			 struct batadv_hard_iface *if_outgoing,
    340			 struct batadv_orig_node *orig_node, int *sub_s)
    341{
    342	struct batadv_neigh_node *neigh_node_best;
    343	struct batadv_neigh_node *neigh_node;
    344	int sub = 0;
    345	bool best;
    346
    347	neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing);
    348	if (!neigh_node_best)
    349		goto out;
    350
    351	hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
    352		if (sub++ < *sub_s)
    353			continue;
    354
    355		best = (neigh_node == neigh_node_best);
    356
    357		if (batadv_v_orig_dump_subentry(msg, portid, seq, bat_priv,
    358						if_outgoing, orig_node,
    359						neigh_node, best)) {
    360			batadv_neigh_node_put(neigh_node_best);
    361
    362			*sub_s = sub - 1;
    363			return -EMSGSIZE;
    364		}
    365	}
    366
    367 out:
    368	batadv_neigh_node_put(neigh_node_best);
    369
    370	*sub_s = 0;
    371	return 0;
    372}
    373
    374/**
    375 * batadv_v_orig_dump_bucket() - Dump an originator bucket into a message
    376 * @msg: Netlink message to dump into
    377 * @portid: Port making netlink request
    378 * @seq: Sequence number of netlink message
    379 * @bat_priv: The bat priv with all the soft interface information
    380 * @if_outgoing: Limit dump to entries with this outgoing interface
    381 * @head: Bucket to be dumped
    382 * @idx_s: Number of entries to be skipped
    383 * @sub: Number of sub entries to be skipped
    384 *
    385 * Return: Error code, or 0 on success
    386 */
    387static int
    388batadv_v_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
    389			  struct batadv_priv *bat_priv,
    390			  struct batadv_hard_iface *if_outgoing,
    391			  struct hlist_head *head, int *idx_s, int *sub)
    392{
    393	struct batadv_orig_node *orig_node;
    394	int idx = 0;
    395
    396	rcu_read_lock();
    397	hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
    398		if (idx++ < *idx_s)
    399			continue;
    400
    401		if (batadv_v_orig_dump_entry(msg, portid, seq, bat_priv,
    402					     if_outgoing, orig_node, sub)) {
    403			rcu_read_unlock();
    404			*idx_s = idx - 1;
    405			return -EMSGSIZE;
    406		}
    407	}
    408	rcu_read_unlock();
    409
    410	*idx_s = 0;
    411	*sub = 0;
    412	return 0;
    413}
    414
    415/**
    416 * batadv_v_orig_dump() - Dump the originators into a message
    417 * @msg: Netlink message to dump into
    418 * @cb: Control block containing additional options
    419 * @bat_priv: The bat priv with all the soft interface information
    420 * @if_outgoing: Limit dump to entries with this outgoing interface
    421 */
    422static void
    423batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb,
    424		   struct batadv_priv *bat_priv,
    425		   struct batadv_hard_iface *if_outgoing)
    426{
    427	struct batadv_hashtable *hash = bat_priv->orig_hash;
    428	struct hlist_head *head;
    429	int bucket = cb->args[0];
    430	int idx = cb->args[1];
    431	int sub = cb->args[2];
    432	int portid = NETLINK_CB(cb->skb).portid;
    433
    434	while (bucket < hash->size) {
    435		head = &hash->table[bucket];
    436
    437		if (batadv_v_orig_dump_bucket(msg, portid,
    438					      cb->nlh->nlmsg_seq,
    439					      bat_priv, if_outgoing, head, &idx,
    440					      &sub))
    441			break;
    442
    443		bucket++;
    444	}
    445
    446	cb->args[0] = bucket;
    447	cb->args[1] = idx;
    448	cb->args[2] = sub;
    449}
    450
    451static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
    452			      struct batadv_hard_iface *if_outgoing1,
    453			      struct batadv_neigh_node *neigh2,
    454			      struct batadv_hard_iface *if_outgoing2)
    455{
    456	struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
    457	int ret = 0;
    458
    459	ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
    460	if (!ifinfo1)
    461		goto err_ifinfo1;
    462
    463	ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
    464	if (!ifinfo2)
    465		goto err_ifinfo2;
    466
    467	ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
    468
    469	batadv_neigh_ifinfo_put(ifinfo2);
    470err_ifinfo2:
    471	batadv_neigh_ifinfo_put(ifinfo1);
    472err_ifinfo1:
    473	return ret;
    474}
    475
    476static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
    477				  struct batadv_hard_iface *if_outgoing1,
    478				  struct batadv_neigh_node *neigh2,
    479				  struct batadv_hard_iface *if_outgoing2)
    480{
    481	struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
    482	u32 threshold;
    483	bool ret = false;
    484
    485	ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
    486	if (!ifinfo1)
    487		goto err_ifinfo1;
    488
    489	ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
    490	if (!ifinfo2)
    491		goto err_ifinfo2;
    492
    493	threshold = ifinfo1->bat_v.throughput / 4;
    494	threshold = ifinfo1->bat_v.throughput - threshold;
    495
    496	ret = ifinfo2->bat_v.throughput > threshold;
    497
    498	batadv_neigh_ifinfo_put(ifinfo2);
    499err_ifinfo2:
    500	batadv_neigh_ifinfo_put(ifinfo1);
    501err_ifinfo1:
    502	return ret;
    503}
    504
    505/**
    506 * batadv_v_init_sel_class() - initialize GW selection class
    507 * @bat_priv: the bat priv with all the soft interface information
    508 */
    509static void batadv_v_init_sel_class(struct batadv_priv *bat_priv)
    510{
    511	/* set default throughput difference threshold to 5Mbps */
    512	atomic_set(&bat_priv->gw.sel_class, 50);
    513}
    514
    515static ssize_t batadv_v_store_sel_class(struct batadv_priv *bat_priv,
    516					char *buff, size_t count)
    517{
    518	u32 old_class, class;
    519
    520	if (!batadv_parse_throughput(bat_priv->soft_iface, buff,
    521				     "B.A.T.M.A.N. V GW selection class",
    522				     &class))
    523		return -EINVAL;
    524
    525	old_class = atomic_read(&bat_priv->gw.sel_class);
    526	atomic_set(&bat_priv->gw.sel_class, class);
    527
    528	if (old_class != class)
    529		batadv_gw_reselect(bat_priv);
    530
    531	return count;
    532}
    533
    534/**
    535 * batadv_v_gw_throughput_get() - retrieve the GW-bandwidth for a given GW
    536 * @gw_node: the GW to retrieve the metric for
    537 * @bw: the pointer where the metric will be stored. The metric is computed as
    538 *  the minimum between the GW advertised throughput and the path throughput to
    539 *  it in the mesh
    540 *
    541 * Return: 0 on success, -1 on failure
    542 */
    543static int batadv_v_gw_throughput_get(struct batadv_gw_node *gw_node, u32 *bw)
    544{
    545	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
    546	struct batadv_orig_node *orig_node;
    547	struct batadv_neigh_node *router;
    548	int ret = -1;
    549
    550	orig_node = gw_node->orig_node;
    551	router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
    552	if (!router)
    553		goto out;
    554
    555	router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
    556	if (!router_ifinfo)
    557		goto out;
    558
    559	/* the GW metric is computed as the minimum between the path throughput
    560	 * to reach the GW itself and the advertised bandwidth.
    561	 * This gives us an approximation of the effective throughput that the
    562	 * client can expect via this particular GW node
    563	 */
    564	*bw = router_ifinfo->bat_v.throughput;
    565	*bw = min_t(u32, *bw, gw_node->bandwidth_down);
    566
    567	ret = 0;
    568out:
    569	batadv_neigh_node_put(router);
    570	batadv_neigh_ifinfo_put(router_ifinfo);
    571
    572	return ret;
    573}
    574
    575/**
    576 * batadv_v_gw_get_best_gw_node() - retrieve the best GW node
    577 * @bat_priv: the bat priv with all the soft interface information
    578 *
    579 * Return: the GW node having the best GW-metric, NULL if no GW is known
    580 */
    581static struct batadv_gw_node *
    582batadv_v_gw_get_best_gw_node(struct batadv_priv *bat_priv)
    583{
    584	struct batadv_gw_node *gw_node, *curr_gw = NULL;
    585	u32 max_bw = 0, bw;
    586
    587	rcu_read_lock();
    588	hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
    589		if (!kref_get_unless_zero(&gw_node->refcount))
    590			continue;
    591
    592		if (batadv_v_gw_throughput_get(gw_node, &bw) < 0)
    593			goto next;
    594
    595		if (curr_gw && bw <= max_bw)
    596			goto next;
    597
    598		batadv_gw_node_put(curr_gw);
    599
    600		curr_gw = gw_node;
    601		kref_get(&curr_gw->refcount);
    602		max_bw = bw;
    603
    604next:
    605		batadv_gw_node_put(gw_node);
    606	}
    607	rcu_read_unlock();
    608
    609	return curr_gw;
    610}
    611
    612/**
    613 * batadv_v_gw_is_eligible() - check if a originator would be selected as GW
    614 * @bat_priv: the bat priv with all the soft interface information
    615 * @curr_gw_orig: originator representing the currently selected GW
    616 * @orig_node: the originator representing the new candidate
    617 *
    618 * Return: true if orig_node can be selected as current GW, false otherwise
    619 */
    620static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv,
    621				    struct batadv_orig_node *curr_gw_orig,
    622				    struct batadv_orig_node *orig_node)
    623{
    624	struct batadv_gw_node *curr_gw, *orig_gw = NULL;
    625	u32 gw_throughput, orig_throughput, threshold;
    626	bool ret = false;
    627
    628	threshold = atomic_read(&bat_priv->gw.sel_class);
    629
    630	curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig);
    631	if (!curr_gw) {
    632		ret = true;
    633		goto out;
    634	}
    635
    636	if (batadv_v_gw_throughput_get(curr_gw, &gw_throughput) < 0) {
    637		ret = true;
    638		goto out;
    639	}
    640
    641	orig_gw = batadv_gw_node_get(bat_priv, orig_node);
    642	if (!orig_gw)
    643		goto out;
    644
    645	if (batadv_v_gw_throughput_get(orig_gw, &orig_throughput) < 0)
    646		goto out;
    647
    648	if (orig_throughput < gw_throughput)
    649		goto out;
    650
    651	if ((orig_throughput - gw_throughput) < threshold)
    652		goto out;
    653
    654	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
    655		   "Restarting gateway selection: better gateway found (throughput curr: %u, throughput new: %u)\n",
    656		   gw_throughput, orig_throughput);
    657
    658	ret = true;
    659out:
    660	batadv_gw_node_put(curr_gw);
    661	batadv_gw_node_put(orig_gw);
    662
    663	return ret;
    664}
    665
    666/**
    667 * batadv_v_gw_dump_entry() - Dump a gateway into a message
    668 * @msg: Netlink message to dump into
    669 * @portid: Port making netlink request
    670 * @cb: Control block containing additional options
    671 * @bat_priv: The bat priv with all the soft interface information
    672 * @gw_node: Gateway to be dumped
    673 *
    674 * Return: Error code, or 0 on success
    675 */
    676static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid,
    677				  struct netlink_callback *cb,
    678				  struct batadv_priv *bat_priv,
    679				  struct batadv_gw_node *gw_node)
    680{
    681	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
    682	struct batadv_neigh_node *router;
    683	struct batadv_gw_node *curr_gw = NULL;
    684	int ret = 0;
    685	void *hdr;
    686
    687	router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
    688	if (!router)
    689		goto out;
    690
    691	router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
    692	if (!router_ifinfo)
    693		goto out;
    694
    695	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
    696
    697	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
    698			  &batadv_netlink_family, NLM_F_MULTI,
    699			  BATADV_CMD_GET_GATEWAYS);
    700	if (!hdr) {
    701		ret = -ENOBUFS;
    702		goto out;
    703	}
    704
    705	genl_dump_check_consistent(cb, hdr);
    706
    707	ret = -EMSGSIZE;
    708
    709	if (curr_gw == gw_node) {
    710		if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) {
    711			genlmsg_cancel(msg, hdr);
    712			goto out;
    713		}
    714	}
    715
    716	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
    717		    gw_node->orig_node->orig)) {
    718		genlmsg_cancel(msg, hdr);
    719		goto out;
    720	}
    721
    722	if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT,
    723			router_ifinfo->bat_v.throughput)) {
    724		genlmsg_cancel(msg, hdr);
    725		goto out;
    726	}
    727
    728	if (nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN, router->addr)) {
    729		genlmsg_cancel(msg, hdr);
    730		goto out;
    731	}
    732
    733	if (nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
    734			   router->if_incoming->net_dev->name)) {
    735		genlmsg_cancel(msg, hdr);
    736		goto out;
    737	}
    738
    739	if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
    740			router->if_incoming->net_dev->ifindex)) {
    741		genlmsg_cancel(msg, hdr);
    742		goto out;
    743	}
    744
    745	if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
    746			gw_node->bandwidth_down)) {
    747		genlmsg_cancel(msg, hdr);
    748		goto out;
    749	}
    750
    751	if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP, gw_node->bandwidth_up)) {
    752		genlmsg_cancel(msg, hdr);
    753		goto out;
    754	}
    755
    756	genlmsg_end(msg, hdr);
    757	ret = 0;
    758
    759out:
    760	batadv_gw_node_put(curr_gw);
    761	batadv_neigh_ifinfo_put(router_ifinfo);
    762	batadv_neigh_node_put(router);
    763	return ret;
    764}
    765
    766/**
    767 * batadv_v_gw_dump() - Dump gateways into a message
    768 * @msg: Netlink message to dump into
    769 * @cb: Control block containing additional options
    770 * @bat_priv: The bat priv with all the soft interface information
    771 */
    772static void batadv_v_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
    773			     struct batadv_priv *bat_priv)
    774{
    775	int portid = NETLINK_CB(cb->skb).portid;
    776	struct batadv_gw_node *gw_node;
    777	int idx_skip = cb->args[0];
    778	int idx = 0;
    779
    780	spin_lock_bh(&bat_priv->gw.list_lock);
    781	cb->seq = bat_priv->gw.generation << 1 | 1;
    782
    783	hlist_for_each_entry(gw_node, &bat_priv->gw.gateway_list, list) {
    784		if (idx++ < idx_skip)
    785			continue;
    786
    787		if (batadv_v_gw_dump_entry(msg, portid, cb, bat_priv,
    788					   gw_node)) {
    789			idx_skip = idx - 1;
    790			goto unlock;
    791		}
    792	}
    793
    794	idx_skip = idx;
    795unlock:
    796	spin_unlock_bh(&bat_priv->gw.list_lock);
    797
    798	cb->args[0] = idx_skip;
    799}
    800
    801static struct batadv_algo_ops batadv_batman_v __read_mostly = {
    802	.name = "BATMAN_V",
    803	.iface = {
    804		.activate = batadv_v_iface_activate,
    805		.enable = batadv_v_iface_enable,
    806		.disable = batadv_v_iface_disable,
    807		.update_mac = batadv_v_iface_update_mac,
    808		.primary_set = batadv_v_primary_iface_set,
    809	},
    810	.neigh = {
    811		.hardif_init = batadv_v_hardif_neigh_init,
    812		.cmp = batadv_v_neigh_cmp,
    813		.is_similar_or_better = batadv_v_neigh_is_sob,
    814		.dump = batadv_v_neigh_dump,
    815	},
    816	.orig = {
    817		.dump = batadv_v_orig_dump,
    818	},
    819	.gw = {
    820		.init_sel_class = batadv_v_init_sel_class,
    821		.store_sel_class = batadv_v_store_sel_class,
    822		.get_best_gw_node = batadv_v_gw_get_best_gw_node,
    823		.is_eligible = batadv_v_gw_is_eligible,
    824		.dump = batadv_v_gw_dump,
    825	},
    826};
    827
    828/**
    829 * batadv_v_hardif_init() - initialize the algorithm specific fields in the
    830 *  hard-interface object
    831 * @hard_iface: the hard-interface to initialize
    832 */
    833void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface)
    834{
    835	/* enable link throughput auto-detection by setting the throughput
    836	 * override to zero
    837	 */
    838	atomic_set(&hard_iface->bat_v.throughput_override, 0);
    839	atomic_set(&hard_iface->bat_v.elp_interval, 500);
    840
    841	hard_iface->bat_v.aggr_len = 0;
    842	skb_queue_head_init(&hard_iface->bat_v.aggr_list);
    843	INIT_DELAYED_WORK(&hard_iface->bat_v.aggr_wq,
    844			  batadv_v_ogm_aggr_work);
    845}
    846
    847/**
    848 * batadv_v_mesh_init() - initialize the B.A.T.M.A.N. V private resources for a
    849 *  mesh
    850 * @bat_priv: the object representing the mesh interface to initialise
    851 *
    852 * Return: 0 on success or a negative error code otherwise
    853 */
    854int batadv_v_mesh_init(struct batadv_priv *bat_priv)
    855{
    856	int ret = 0;
    857
    858	ret = batadv_v_ogm_init(bat_priv);
    859	if (ret < 0)
    860		return ret;
    861
    862	return 0;
    863}
    864
    865/**
    866 * batadv_v_mesh_free() - free the B.A.T.M.A.N. V private resources for a mesh
    867 * @bat_priv: the object representing the mesh interface to free
    868 */
    869void batadv_v_mesh_free(struct batadv_priv *bat_priv)
    870{
    871	batadv_v_ogm_free(bat_priv);
    872}
    873
    874/**
    875 * batadv_v_init() - B.A.T.M.A.N. V initialization function
    876 *
    877 * Description: Takes care of initializing all the subcomponents.
    878 * It is invoked upon module load only.
    879 *
    880 * Return: 0 on success or a negative error code otherwise
    881 */
    882int __init batadv_v_init(void)
    883{
    884	int ret;
    885
    886	/* B.A.T.M.A.N. V echo location protocol packet  */
    887	ret = batadv_recv_handler_register(BATADV_ELP,
    888					   batadv_v_elp_packet_recv);
    889	if (ret < 0)
    890		return ret;
    891
    892	ret = batadv_recv_handler_register(BATADV_OGM2,
    893					   batadv_v_ogm_packet_recv);
    894	if (ret < 0)
    895		goto elp_unregister;
    896
    897	ret = batadv_algo_register(&batadv_batman_v);
    898	if (ret < 0)
    899		goto ogm_unregister;
    900
    901	return ret;
    902
    903ogm_unregister:
    904	batadv_recv_handler_unregister(BATADV_OGM2);
    905
    906elp_unregister:
    907	batadv_recv_handler_unregister(BATADV_ELP);
    908
    909	return ret;
    910}