17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0 2ac79cbb9SSven Eckelmann /* Copyright (C) 2013-2017 B.A.T.M.A.N. contributors: 3d6f94d91SLinus Luessing * 4d6f94d91SLinus Luessing * Linus Lüssing, Marek Lindner 5d6f94d91SLinus Luessing * 6d6f94d91SLinus Luessing * This program is free software; you can redistribute it and/or 7d6f94d91SLinus Luessing * modify it under the terms of version 2 of the GNU General Public 8d6f94d91SLinus Luessing * License as published by the Free Software Foundation. 9d6f94d91SLinus Luessing * 10d6f94d91SLinus Luessing * This program is distributed in the hope that it will be useful, but 11d6f94d91SLinus Luessing * WITHOUT ANY WARRANTY; without even the implied warranty of 12d6f94d91SLinus Luessing * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13d6f94d91SLinus Luessing * General Public License for more details. 14d6f94d91SLinus Luessing * 15d6f94d91SLinus Luessing * You should have received a copy of the GNU General Public License 16d6f94d91SLinus Luessing * along with this program; if not, see <http://www.gnu.org/licenses/>. 17d6f94d91SLinus Luessing */ 18d6f94d91SLinus Luessing 19a2d08166SSven Eckelmann #include "bat_v.h" 20d6f94d91SLinus Luessing #include "main.h" 21d6f94d91SLinus Luessing 220b5ecc68SAntonio Quartulli #include <linux/atomic.h> 23d6f94d91SLinus Luessing #include <linux/cache.h> 2408686943SAntonio Quartulli #include <linux/errno.h> 25f02a478fSMatthias Schiffer #include <linux/if_ether.h> 26d6f94d91SLinus Luessing #include <linux/init.h> 27261e264dSAntonio Quartulli #include <linux/jiffies.h> 2808686943SAntonio Quartulli #include <linux/kernel.h> 2950164d8fSAntonio Quartulli #include <linux/kref.h> 30261e264dSAntonio Quartulli #include <linux/netdevice.h> 31f02a478fSMatthias Schiffer #include <linux/netlink.h> 32261e264dSAntonio Quartulli #include <linux/rculist.h> 33261e264dSAntonio Quartulli #include <linux/rcupdate.h> 34261e264dSAntonio Quartulli #include <linux/seq_file.h> 35a45e932aSSven Eckelmann #include <linux/stddef.h> 3697869060SAntonio Quartulli #include <linux/types.h> 37c833484eSAntonio Quartulli #include <linux/workqueue.h> 38f02a478fSMatthias Schiffer #include <net/genetlink.h> 39f02a478fSMatthias Schiffer #include <net/netlink.h> 40fec149f5SSven Eckelmann #include <uapi/linux/batadv_packet.h> 41f02a478fSMatthias Schiffer #include <uapi/linux/batman_adv.h> 42d6f94d91SLinus Luessing 43a2d08166SSven Eckelmann #include "bat_algo.h" 44d6f94d91SLinus Luessing #include "bat_v_elp.h" 450da00359SAntonio Quartulli #include "bat_v_ogm.h" 4608686943SAntonio Quartulli #include "gateway_client.h" 4708686943SAntonio Quartulli #include "gateway_common.h" 48b6cf5d49SAntonio Quartulli #include "hard-interface.h" 49261e264dSAntonio Quartulli #include "hash.h" 5050164d8fSAntonio Quartulli #include "log.h" 51f02a478fSMatthias Schiffer #include "netlink.h" 5297869060SAntonio Quartulli #include "originator.h" 53d6f94d91SLinus Luessing 54f02a478fSMatthias Schiffer struct sk_buff; 55f02a478fSMatthias Schiffer 56b6cf5d49SAntonio Quartulli static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface) 57b6cf5d49SAntonio Quartulli { 58ebe24ceaSMarek Lindner struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); 59ebe24ceaSMarek Lindner struct batadv_hard_iface *primary_if; 60ebe24ceaSMarek Lindner 61ebe24ceaSMarek Lindner primary_if = batadv_primary_if_get_selected(bat_priv); 62ebe24ceaSMarek Lindner 63ebe24ceaSMarek Lindner if (primary_if) { 64ebe24ceaSMarek Lindner batadv_v_elp_iface_activate(primary_if, hard_iface); 65ebe24ceaSMarek Lindner batadv_hardif_put(primary_if); 66ebe24ceaSMarek Lindner } 67ebe24ceaSMarek Lindner 68b6cf5d49SAntonio Quartulli /* B.A.T.M.A.N. V does not use any queuing mechanism, therefore it can 69b6cf5d49SAntonio Quartulli * set the interface as ACTIVE right away, without any risk of race 70b6cf5d49SAntonio Quartulli * condition 71b6cf5d49SAntonio Quartulli */ 72b6cf5d49SAntonio Quartulli if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED) 73b6cf5d49SAntonio Quartulli hard_iface->if_status = BATADV_IF_ACTIVE; 74b6cf5d49SAntonio Quartulli } 75b6cf5d49SAntonio Quartulli 76d6f94d91SLinus Luessing static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface) 77d6f94d91SLinus Luessing { 780da00359SAntonio Quartulli int ret; 790da00359SAntonio Quartulli 800da00359SAntonio Quartulli ret = batadv_v_elp_iface_enable(hard_iface); 810da00359SAntonio Quartulli if (ret < 0) 820da00359SAntonio Quartulli return ret; 830da00359SAntonio Quartulli 840da00359SAntonio Quartulli ret = batadv_v_ogm_iface_enable(hard_iface); 850da00359SAntonio Quartulli if (ret < 0) 860da00359SAntonio Quartulli batadv_v_elp_iface_disable(hard_iface); 870da00359SAntonio Quartulli 880da00359SAntonio Quartulli return ret; 89d6f94d91SLinus Luessing } 90d6f94d91SLinus Luessing 91d6f94d91SLinus Luessing static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface) 92d6f94d91SLinus Luessing { 93d6f94d91SLinus Luessing batadv_v_elp_iface_disable(hard_iface); 94d6f94d91SLinus Luessing } 95d6f94d91SLinus Luessing 96d6f94d91SLinus Luessing static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface) 97d6f94d91SLinus Luessing { 98d6f94d91SLinus Luessing batadv_v_elp_primary_iface_set(hard_iface); 990da00359SAntonio Quartulli batadv_v_ogm_primary_iface_set(hard_iface); 100d6f94d91SLinus Luessing } 101d6f94d91SLinus Luessing 1021653f61dSAntonio Quartulli /** 1037e9a8c2cSSven Eckelmann * batadv_v_iface_update_mac() - react to hard-interface MAC address change 1041653f61dSAntonio Quartulli * @hard_iface: the modified interface 1051653f61dSAntonio Quartulli * 1061653f61dSAntonio Quartulli * If the modified interface is the primary one, update the originator 1071653f61dSAntonio Quartulli * address in the ELP and OGM messages to reflect the new MAC address. 1081653f61dSAntonio Quartulli */ 1091653f61dSAntonio Quartulli static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface) 1101653f61dSAntonio Quartulli { 1111653f61dSAntonio Quartulli struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); 1121653f61dSAntonio Quartulli struct batadv_hard_iface *primary_if; 1131653f61dSAntonio Quartulli 1141653f61dSAntonio Quartulli primary_if = batadv_primary_if_get_selected(bat_priv); 1151653f61dSAntonio Quartulli if (primary_if != hard_iface) 1161653f61dSAntonio Quartulli goto out; 1171653f61dSAntonio Quartulli 1181653f61dSAntonio Quartulli batadv_v_primary_iface_set(hard_iface); 1191653f61dSAntonio Quartulli out: 1201653f61dSAntonio Quartulli if (primary_if) 1211653f61dSAntonio Quartulli batadv_hardif_put(primary_if); 1221653f61dSAntonio Quartulli } 1231653f61dSAntonio Quartulli 124162bd64cSLinus Luessing static void 125162bd64cSLinus Luessing batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh) 126162bd64cSLinus Luessing { 127162bd64cSLinus Luessing ewma_throughput_init(&hardif_neigh->bat_v.throughput); 128c833484eSAntonio Quartulli INIT_WORK(&hardif_neigh->bat_v.metric_work, 129c833484eSAntonio Quartulli batadv_v_elp_throughput_metric_update); 130162bd64cSLinus Luessing } 131162bd64cSLinus Luessing 132dc1cbd14SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUGFS 133261e264dSAntonio Quartulli /** 1347e9a8c2cSSven Eckelmann * batadv_v_orig_print_neigh() - print neighbors for the originator table 135261e264dSAntonio Quartulli * @orig_node: the orig_node for which the neighbors are printed 136261e264dSAntonio Quartulli * @if_outgoing: outgoing interface for these entries 137261e264dSAntonio Quartulli * @seq: debugfs table seq_file struct 138261e264dSAntonio Quartulli * 139261e264dSAntonio Quartulli * Must be called while holding an rcu lock. 140261e264dSAntonio Quartulli */ 141261e264dSAntonio Quartulli static void 142261e264dSAntonio Quartulli batadv_v_orig_print_neigh(struct batadv_orig_node *orig_node, 143261e264dSAntonio Quartulli struct batadv_hard_iface *if_outgoing, 144261e264dSAntonio Quartulli struct seq_file *seq) 145261e264dSAntonio Quartulli { 146261e264dSAntonio Quartulli struct batadv_neigh_node *neigh_node; 147261e264dSAntonio Quartulli struct batadv_neigh_ifinfo *n_ifinfo; 148261e264dSAntonio Quartulli 149261e264dSAntonio Quartulli hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { 150261e264dSAntonio Quartulli n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); 151261e264dSAntonio Quartulli if (!n_ifinfo) 152261e264dSAntonio Quartulli continue; 153261e264dSAntonio Quartulli 154261e264dSAntonio Quartulli seq_printf(seq, " %pM (%9u.%1u)", 155261e264dSAntonio Quartulli neigh_node->addr, 156261e264dSAntonio Quartulli n_ifinfo->bat_v.throughput / 10, 157261e264dSAntonio Quartulli n_ifinfo->bat_v.throughput % 10); 158261e264dSAntonio Quartulli 159261e264dSAntonio Quartulli batadv_neigh_ifinfo_put(n_ifinfo); 160261e264dSAntonio Quartulli } 161261e264dSAntonio Quartulli } 162261e264dSAntonio Quartulli 163261e264dSAntonio Quartulli /** 1647e9a8c2cSSven Eckelmann * batadv_v_hardif_neigh_print() - print a single ELP neighbour node 165626d23e8SLinus Luessing * @seq: neighbour table seq_file struct 166626d23e8SLinus Luessing * @hardif_neigh: hardif neighbour information 167626d23e8SLinus Luessing */ 168626d23e8SLinus Luessing static void 169626d23e8SLinus Luessing batadv_v_hardif_neigh_print(struct seq_file *seq, 170626d23e8SLinus Luessing struct batadv_hardif_neigh_node *hardif_neigh) 171626d23e8SLinus Luessing { 172626d23e8SLinus Luessing int last_secs, last_msecs; 173626d23e8SLinus Luessing u32 throughput; 174626d23e8SLinus Luessing 175626d23e8SLinus Luessing last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000; 176626d23e8SLinus Luessing last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000; 177626d23e8SLinus Luessing throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput); 178626d23e8SLinus Luessing 179626d23e8SLinus Luessing seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n", 180626d23e8SLinus Luessing hardif_neigh->addr, last_secs, last_msecs, throughput / 10, 181626d23e8SLinus Luessing throughput % 10, hardif_neigh->if_incoming->net_dev->name); 182626d23e8SLinus Luessing } 183626d23e8SLinus Luessing 184626d23e8SLinus Luessing /** 1857e9a8c2cSSven Eckelmann * batadv_v_neigh_print() - print the single hop neighbour list 186626d23e8SLinus Luessing * @bat_priv: the bat priv with all the soft interface information 187626d23e8SLinus Luessing * @seq: neighbour table seq_file struct 188626d23e8SLinus Luessing */ 189626d23e8SLinus Luessing static void batadv_v_neigh_print(struct batadv_priv *bat_priv, 190626d23e8SLinus Luessing struct seq_file *seq) 191626d23e8SLinus Luessing { 192626d23e8SLinus Luessing struct net_device *net_dev = (struct net_device *)seq->private; 193626d23e8SLinus Luessing struct batadv_hardif_neigh_node *hardif_neigh; 194626d23e8SLinus Luessing struct batadv_hard_iface *hard_iface; 195626d23e8SLinus Luessing int batman_count = 0; 196626d23e8SLinus Luessing 197925a6f37SAntonio Quartulli seq_puts(seq, 198925a6f37SAntonio Quartulli " Neighbor last-seen ( throughput) [ IF]\n"); 199626d23e8SLinus Luessing 200626d23e8SLinus Luessing rcu_read_lock(); 201626d23e8SLinus Luessing list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 202626d23e8SLinus Luessing if (hard_iface->soft_iface != net_dev) 203626d23e8SLinus Luessing continue; 204626d23e8SLinus Luessing 205626d23e8SLinus Luessing hlist_for_each_entry_rcu(hardif_neigh, 206626d23e8SLinus Luessing &hard_iface->neigh_list, list) { 207626d23e8SLinus Luessing batadv_v_hardif_neigh_print(seq, hardif_neigh); 208626d23e8SLinus Luessing batman_count++; 209626d23e8SLinus Luessing } 210626d23e8SLinus Luessing } 211626d23e8SLinus Luessing rcu_read_unlock(); 212626d23e8SLinus Luessing 213626d23e8SLinus Luessing if (batman_count == 0) 214626d23e8SLinus Luessing seq_puts(seq, "No batman nodes in range ...\n"); 215626d23e8SLinus Luessing } 216dc1cbd14SSven Eckelmann #endif 217626d23e8SLinus Luessing 218626d23e8SLinus Luessing /** 2197e9a8c2cSSven Eckelmann * batadv_v_neigh_dump_neigh() - Dump a neighbour into a message 220f02a478fSMatthias Schiffer * @msg: Netlink message to dump into 221f02a478fSMatthias Schiffer * @portid: Port making netlink request 222f02a478fSMatthias Schiffer * @seq: Sequence number of netlink message 223f02a478fSMatthias Schiffer * @hardif_neigh: Neighbour to dump 224f02a478fSMatthias Schiffer * 225f02a478fSMatthias Schiffer * Return: Error code, or 0 on success 226f02a478fSMatthias Schiffer */ 227f02a478fSMatthias Schiffer static int 228f02a478fSMatthias Schiffer batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq, 229f02a478fSMatthias Schiffer struct batadv_hardif_neigh_node *hardif_neigh) 230f02a478fSMatthias Schiffer { 231f02a478fSMatthias Schiffer void *hdr; 232f02a478fSMatthias Schiffer unsigned int last_seen_msecs; 233f02a478fSMatthias Schiffer u32 throughput; 234f02a478fSMatthias Schiffer 235f02a478fSMatthias Schiffer last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen); 236f02a478fSMatthias Schiffer throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput); 237f02a478fSMatthias Schiffer throughput = throughput * 100; 238f02a478fSMatthias Schiffer 239f02a478fSMatthias Schiffer hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, 240f02a478fSMatthias Schiffer BATADV_CMD_GET_NEIGHBORS); 241f02a478fSMatthias Schiffer if (!hdr) 242f02a478fSMatthias Schiffer return -ENOBUFS; 243f02a478fSMatthias Schiffer 244f02a478fSMatthias Schiffer if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN, 245f02a478fSMatthias Schiffer hardif_neigh->addr) || 246f02a478fSMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, 247f02a478fSMatthias Schiffer hardif_neigh->if_incoming->net_dev->ifindex) || 248f02a478fSMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, 249f02a478fSMatthias Schiffer last_seen_msecs) || 250f02a478fSMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput)) 251f02a478fSMatthias Schiffer goto nla_put_failure; 252f02a478fSMatthias Schiffer 253f02a478fSMatthias Schiffer genlmsg_end(msg, hdr); 254f02a478fSMatthias Schiffer return 0; 255f02a478fSMatthias Schiffer 256f02a478fSMatthias Schiffer nla_put_failure: 257f02a478fSMatthias Schiffer genlmsg_cancel(msg, hdr); 258f02a478fSMatthias Schiffer return -EMSGSIZE; 259f02a478fSMatthias Schiffer } 260f02a478fSMatthias Schiffer 261f02a478fSMatthias Schiffer /** 2627e9a8c2cSSven Eckelmann * batadv_v_neigh_dump_hardif() - Dump the neighbours of a hard interface into 263f02a478fSMatthias Schiffer * a message 264f02a478fSMatthias Schiffer * @msg: Netlink message to dump into 265f02a478fSMatthias Schiffer * @portid: Port making netlink request 266f02a478fSMatthias Schiffer * @seq: Sequence number of netlink message 267f02a478fSMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 268f02a478fSMatthias Schiffer * @hard_iface: The hard interface to be dumped 269f02a478fSMatthias Schiffer * @idx_s: Entries to be skipped 270f02a478fSMatthias Schiffer * 271f02a478fSMatthias Schiffer * This function assumes the caller holds rcu_read_lock(). 272f02a478fSMatthias Schiffer * 273f02a478fSMatthias Schiffer * Return: Error code, or 0 on success 274f02a478fSMatthias Schiffer */ 275f02a478fSMatthias Schiffer static int 276f02a478fSMatthias Schiffer batadv_v_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq, 277f02a478fSMatthias Schiffer struct batadv_priv *bat_priv, 278f02a478fSMatthias Schiffer struct batadv_hard_iface *hard_iface, 279f02a478fSMatthias Schiffer int *idx_s) 280f02a478fSMatthias Schiffer { 281f02a478fSMatthias Schiffer struct batadv_hardif_neigh_node *hardif_neigh; 282f02a478fSMatthias Schiffer int idx = 0; 283f02a478fSMatthias Schiffer 284f02a478fSMatthias Schiffer hlist_for_each_entry_rcu(hardif_neigh, 285f02a478fSMatthias Schiffer &hard_iface->neigh_list, list) { 286f02a478fSMatthias Schiffer if (idx++ < *idx_s) 287f02a478fSMatthias Schiffer continue; 288f02a478fSMatthias Schiffer 289f02a478fSMatthias Schiffer if (batadv_v_neigh_dump_neigh(msg, portid, seq, hardif_neigh)) { 290f02a478fSMatthias Schiffer *idx_s = idx - 1; 291f02a478fSMatthias Schiffer return -EMSGSIZE; 292f02a478fSMatthias Schiffer } 293f02a478fSMatthias Schiffer } 294f02a478fSMatthias Schiffer 295f02a478fSMatthias Schiffer *idx_s = 0; 296f02a478fSMatthias Schiffer return 0; 297f02a478fSMatthias Schiffer } 298f02a478fSMatthias Schiffer 299f02a478fSMatthias Schiffer /** 3007e9a8c2cSSven Eckelmann * batadv_v_neigh_dump() - Dump the neighbours of a hard interface into a 301f02a478fSMatthias Schiffer * message 302f02a478fSMatthias Schiffer * @msg: Netlink message to dump into 303f02a478fSMatthias Schiffer * @cb: Control block containing additional options 304f02a478fSMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 305f02a478fSMatthias Schiffer * @single_hardif: Limit dumping to this hard interface 306f02a478fSMatthias Schiffer */ 307f02a478fSMatthias Schiffer static void 308f02a478fSMatthias Schiffer batadv_v_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb, 309f02a478fSMatthias Schiffer struct batadv_priv *bat_priv, 310f02a478fSMatthias Schiffer struct batadv_hard_iface *single_hardif) 311f02a478fSMatthias Schiffer { 312f02a478fSMatthias Schiffer struct batadv_hard_iface *hard_iface; 313f02a478fSMatthias Schiffer int i_hardif = 0; 314f02a478fSMatthias Schiffer int i_hardif_s = cb->args[0]; 315f02a478fSMatthias Schiffer int idx = cb->args[1]; 316f02a478fSMatthias Schiffer int portid = NETLINK_CB(cb->skb).portid; 317f02a478fSMatthias Schiffer 318f02a478fSMatthias Schiffer rcu_read_lock(); 319f02a478fSMatthias Schiffer if (single_hardif) { 320f02a478fSMatthias Schiffer if (i_hardif_s == 0) { 321f02a478fSMatthias Schiffer if (batadv_v_neigh_dump_hardif(msg, portid, 322f02a478fSMatthias Schiffer cb->nlh->nlmsg_seq, 323f02a478fSMatthias Schiffer bat_priv, single_hardif, 324f02a478fSMatthias Schiffer &idx) == 0) 325f02a478fSMatthias Schiffer i_hardif++; 326f02a478fSMatthias Schiffer } 327f02a478fSMatthias Schiffer } else { 328f02a478fSMatthias Schiffer list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 329f02a478fSMatthias Schiffer if (hard_iface->soft_iface != bat_priv->soft_iface) 330f02a478fSMatthias Schiffer continue; 331f02a478fSMatthias Schiffer 332f02a478fSMatthias Schiffer if (i_hardif++ < i_hardif_s) 333f02a478fSMatthias Schiffer continue; 334f02a478fSMatthias Schiffer 335f02a478fSMatthias Schiffer if (batadv_v_neigh_dump_hardif(msg, portid, 336f02a478fSMatthias Schiffer cb->nlh->nlmsg_seq, 337f02a478fSMatthias Schiffer bat_priv, hard_iface, 338f02a478fSMatthias Schiffer &idx)) { 339f02a478fSMatthias Schiffer i_hardif--; 340f02a478fSMatthias Schiffer break; 341f02a478fSMatthias Schiffer } 342f02a478fSMatthias Schiffer } 343f02a478fSMatthias Schiffer } 344f02a478fSMatthias Schiffer rcu_read_unlock(); 345f02a478fSMatthias Schiffer 346f02a478fSMatthias Schiffer cb->args[0] = i_hardif; 347f02a478fSMatthias Schiffer cb->args[1] = idx; 348f02a478fSMatthias Schiffer } 349f02a478fSMatthias Schiffer 350dc1cbd14SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUGFS 351f02a478fSMatthias Schiffer /** 3527e9a8c2cSSven Eckelmann * batadv_v_orig_print() - print the originator table 353261e264dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 354261e264dSAntonio Quartulli * @seq: debugfs table seq_file struct 355261e264dSAntonio Quartulli * @if_outgoing: the outgoing interface for which this should be printed 356261e264dSAntonio Quartulli */ 357261e264dSAntonio Quartulli static void batadv_v_orig_print(struct batadv_priv *bat_priv, 358261e264dSAntonio Quartulli struct seq_file *seq, 359261e264dSAntonio Quartulli struct batadv_hard_iface *if_outgoing) 360261e264dSAntonio Quartulli { 361261e264dSAntonio Quartulli struct batadv_neigh_node *neigh_node; 362261e264dSAntonio Quartulli struct batadv_hashtable *hash = bat_priv->orig_hash; 363261e264dSAntonio Quartulli int last_seen_msecs, last_seen_secs; 364261e264dSAntonio Quartulli struct batadv_orig_node *orig_node; 365261e264dSAntonio Quartulli struct batadv_neigh_ifinfo *n_ifinfo; 366261e264dSAntonio Quartulli unsigned long last_seen_jiffies; 367261e264dSAntonio Quartulli struct hlist_head *head; 368261e264dSAntonio Quartulli int batman_count = 0; 369261e264dSAntonio Quartulli u32 i; 370261e264dSAntonio Quartulli 371925a6f37SAntonio Quartulli seq_puts(seq, 372925a6f37SAntonio Quartulli " Originator last-seen ( throughput) Nexthop [outgoingIF]: Potential nexthops ...\n"); 373261e264dSAntonio Quartulli 374261e264dSAntonio Quartulli for (i = 0; i < hash->size; i++) { 375261e264dSAntonio Quartulli head = &hash->table[i]; 376261e264dSAntonio Quartulli 377261e264dSAntonio Quartulli rcu_read_lock(); 378261e264dSAntonio Quartulli hlist_for_each_entry_rcu(orig_node, head, hash_entry) { 379261e264dSAntonio Quartulli neigh_node = batadv_orig_router_get(orig_node, 380261e264dSAntonio Quartulli if_outgoing); 381261e264dSAntonio Quartulli if (!neigh_node) 382261e264dSAntonio Quartulli continue; 383261e264dSAntonio Quartulli 384261e264dSAntonio Quartulli n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, 385261e264dSAntonio Quartulli if_outgoing); 386261e264dSAntonio Quartulli if (!n_ifinfo) 387261e264dSAntonio Quartulli goto next; 388261e264dSAntonio Quartulli 389261e264dSAntonio Quartulli last_seen_jiffies = jiffies - orig_node->last_seen; 390261e264dSAntonio Quartulli last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 391261e264dSAntonio Quartulli last_seen_secs = last_seen_msecs / 1000; 392261e264dSAntonio Quartulli last_seen_msecs = last_seen_msecs % 1000; 393261e264dSAntonio Quartulli 394261e264dSAntonio Quartulli seq_printf(seq, "%pM %4i.%03is (%9u.%1u) %pM [%10s]:", 395261e264dSAntonio Quartulli orig_node->orig, last_seen_secs, 396261e264dSAntonio Quartulli last_seen_msecs, 397261e264dSAntonio Quartulli n_ifinfo->bat_v.throughput / 10, 398261e264dSAntonio Quartulli n_ifinfo->bat_v.throughput % 10, 399261e264dSAntonio Quartulli neigh_node->addr, 400261e264dSAntonio Quartulli neigh_node->if_incoming->net_dev->name); 401261e264dSAntonio Quartulli 402261e264dSAntonio Quartulli batadv_v_orig_print_neigh(orig_node, if_outgoing, seq); 403626caae9SMarkus Elfring seq_putc(seq, '\n'); 404261e264dSAntonio Quartulli batman_count++; 405261e264dSAntonio Quartulli 406261e264dSAntonio Quartulli next: 407261e264dSAntonio Quartulli batadv_neigh_node_put(neigh_node); 408261e264dSAntonio Quartulli if (n_ifinfo) 409261e264dSAntonio Quartulli batadv_neigh_ifinfo_put(n_ifinfo); 410261e264dSAntonio Quartulli } 411261e264dSAntonio Quartulli rcu_read_unlock(); 412261e264dSAntonio Quartulli } 413261e264dSAntonio Quartulli 414261e264dSAntonio Quartulli if (batman_count == 0) 415261e264dSAntonio Quartulli seq_puts(seq, "No batman nodes in range ...\n"); 416261e264dSAntonio Quartulli } 417dc1cbd14SSven Eckelmann #endif 418261e264dSAntonio Quartulli 419f02a478fSMatthias Schiffer /** 4207e9a8c2cSSven Eckelmann * batadv_v_orig_dump_subentry() - Dump an originator subentry into a message 421f02a478fSMatthias Schiffer * @msg: Netlink message to dump into 422f02a478fSMatthias Schiffer * @portid: Port making netlink request 423f02a478fSMatthias Schiffer * @seq: Sequence number of netlink message 424f02a478fSMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 425f02a478fSMatthias Schiffer * @if_outgoing: Limit dump to entries with this outgoing interface 426f02a478fSMatthias Schiffer * @orig_node: Originator to dump 427f02a478fSMatthias Schiffer * @neigh_node: Single hops neighbour 428f02a478fSMatthias Schiffer * @best: Is the best originator 429f02a478fSMatthias Schiffer * 430f02a478fSMatthias Schiffer * Return: Error code, or 0 on success 431f02a478fSMatthias Schiffer */ 432f02a478fSMatthias Schiffer static int 433f02a478fSMatthias Schiffer batadv_v_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, 434f02a478fSMatthias Schiffer struct batadv_priv *bat_priv, 435f02a478fSMatthias Schiffer struct batadv_hard_iface *if_outgoing, 436f02a478fSMatthias Schiffer struct batadv_orig_node *orig_node, 437f02a478fSMatthias Schiffer struct batadv_neigh_node *neigh_node, 438f02a478fSMatthias Schiffer bool best) 439f02a478fSMatthias Schiffer { 440f02a478fSMatthias Schiffer struct batadv_neigh_ifinfo *n_ifinfo; 441f02a478fSMatthias Schiffer unsigned int last_seen_msecs; 442f02a478fSMatthias Schiffer u32 throughput; 443f02a478fSMatthias Schiffer void *hdr; 444f02a478fSMatthias Schiffer 445f02a478fSMatthias Schiffer n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); 446f02a478fSMatthias Schiffer if (!n_ifinfo) 447f02a478fSMatthias Schiffer return 0; 448f02a478fSMatthias Schiffer 449f02a478fSMatthias Schiffer throughput = n_ifinfo->bat_v.throughput * 100; 450f02a478fSMatthias Schiffer 451f02a478fSMatthias Schiffer batadv_neigh_ifinfo_put(n_ifinfo); 452f02a478fSMatthias Schiffer 453f02a478fSMatthias Schiffer last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen); 454f02a478fSMatthias Schiffer 455f02a478fSMatthias Schiffer if (if_outgoing != BATADV_IF_DEFAULT && 456f02a478fSMatthias Schiffer if_outgoing != neigh_node->if_incoming) 457f02a478fSMatthias Schiffer return 0; 458f02a478fSMatthias Schiffer 459f02a478fSMatthias Schiffer hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, 460f02a478fSMatthias Schiffer BATADV_CMD_GET_ORIGINATORS); 461f02a478fSMatthias Schiffer if (!hdr) 462f02a478fSMatthias Schiffer return -ENOBUFS; 463f02a478fSMatthias Schiffer 464f02a478fSMatthias Schiffer if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) || 465f02a478fSMatthias Schiffer nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN, 466f02a478fSMatthias Schiffer neigh_node->addr) || 467f02a478fSMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, 468f02a478fSMatthias Schiffer neigh_node->if_incoming->net_dev->ifindex) || 469f02a478fSMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput) || 470f02a478fSMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, 471f02a478fSMatthias Schiffer last_seen_msecs)) 472f02a478fSMatthias Schiffer goto nla_put_failure; 473f02a478fSMatthias Schiffer 474f02a478fSMatthias Schiffer if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) 475f02a478fSMatthias Schiffer goto nla_put_failure; 476f02a478fSMatthias Schiffer 477f02a478fSMatthias Schiffer genlmsg_end(msg, hdr); 478f02a478fSMatthias Schiffer return 0; 479f02a478fSMatthias Schiffer 480f02a478fSMatthias Schiffer nla_put_failure: 481f02a478fSMatthias Schiffer genlmsg_cancel(msg, hdr); 482f02a478fSMatthias Schiffer return -EMSGSIZE; 483f02a478fSMatthias Schiffer } 484f02a478fSMatthias Schiffer 485f02a478fSMatthias Schiffer /** 4867e9a8c2cSSven Eckelmann * batadv_v_orig_dump_entry() - Dump an originator entry into a message 487f02a478fSMatthias Schiffer * @msg: Netlink message to dump into 488f02a478fSMatthias Schiffer * @portid: Port making netlink request 489f02a478fSMatthias Schiffer * @seq: Sequence number of netlink message 490f02a478fSMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 491f02a478fSMatthias Schiffer * @if_outgoing: Limit dump to entries with this outgoing interface 492f02a478fSMatthias Schiffer * @orig_node: Originator to dump 493f02a478fSMatthias Schiffer * @sub_s: Number of sub entries to skip 494f02a478fSMatthias Schiffer * 495f02a478fSMatthias Schiffer * This function assumes the caller holds rcu_read_lock(). 496f02a478fSMatthias Schiffer * 497f02a478fSMatthias Schiffer * Return: Error code, or 0 on success 498f02a478fSMatthias Schiffer */ 499f02a478fSMatthias Schiffer static int 500f02a478fSMatthias Schiffer batadv_v_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, 501f02a478fSMatthias Schiffer struct batadv_priv *bat_priv, 502f02a478fSMatthias Schiffer struct batadv_hard_iface *if_outgoing, 503f02a478fSMatthias Schiffer struct batadv_orig_node *orig_node, int *sub_s) 504f02a478fSMatthias Schiffer { 505f02a478fSMatthias Schiffer struct batadv_neigh_node *neigh_node_best; 506f02a478fSMatthias Schiffer struct batadv_neigh_node *neigh_node; 507f02a478fSMatthias Schiffer int sub = 0; 508f02a478fSMatthias Schiffer bool best; 509f02a478fSMatthias Schiffer 510f02a478fSMatthias Schiffer neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing); 511f02a478fSMatthias Schiffer if (!neigh_node_best) 512f02a478fSMatthias Schiffer goto out; 513f02a478fSMatthias Schiffer 514f02a478fSMatthias Schiffer hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { 515f02a478fSMatthias Schiffer if (sub++ < *sub_s) 516f02a478fSMatthias Schiffer continue; 517f02a478fSMatthias Schiffer 518f02a478fSMatthias Schiffer best = (neigh_node == neigh_node_best); 519f02a478fSMatthias Schiffer 520f02a478fSMatthias Schiffer if (batadv_v_orig_dump_subentry(msg, portid, seq, bat_priv, 521f02a478fSMatthias Schiffer if_outgoing, orig_node, 522f02a478fSMatthias Schiffer neigh_node, best)) { 523f02a478fSMatthias Schiffer batadv_neigh_node_put(neigh_node_best); 524f02a478fSMatthias Schiffer 525f02a478fSMatthias Schiffer *sub_s = sub - 1; 526f02a478fSMatthias Schiffer return -EMSGSIZE; 527f02a478fSMatthias Schiffer } 528f02a478fSMatthias Schiffer } 529f02a478fSMatthias Schiffer 530f02a478fSMatthias Schiffer out: 531f02a478fSMatthias Schiffer if (neigh_node_best) 532f02a478fSMatthias Schiffer batadv_neigh_node_put(neigh_node_best); 533f02a478fSMatthias Schiffer 534f02a478fSMatthias Schiffer *sub_s = 0; 535f02a478fSMatthias Schiffer return 0; 536f02a478fSMatthias Schiffer } 537f02a478fSMatthias Schiffer 538f02a478fSMatthias Schiffer /** 5397e9a8c2cSSven Eckelmann * batadv_v_orig_dump_bucket() - Dump an originator bucket into a message 540f02a478fSMatthias Schiffer * @msg: Netlink message to dump into 541f02a478fSMatthias Schiffer * @portid: Port making netlink request 542f02a478fSMatthias Schiffer * @seq: Sequence number of netlink message 543f02a478fSMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 544f02a478fSMatthias Schiffer * @if_outgoing: Limit dump to entries with this outgoing interface 545f02a478fSMatthias Schiffer * @head: Bucket to be dumped 546f02a478fSMatthias Schiffer * @idx_s: Number of entries to be skipped 547f02a478fSMatthias Schiffer * @sub: Number of sub entries to be skipped 548f02a478fSMatthias Schiffer * 549f02a478fSMatthias Schiffer * Return: Error code, or 0 on success 550f02a478fSMatthias Schiffer */ 551f02a478fSMatthias Schiffer static int 552f02a478fSMatthias Schiffer batadv_v_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, 553f02a478fSMatthias Schiffer struct batadv_priv *bat_priv, 554f02a478fSMatthias Schiffer struct batadv_hard_iface *if_outgoing, 555f02a478fSMatthias Schiffer struct hlist_head *head, int *idx_s, int *sub) 556f02a478fSMatthias Schiffer { 557f02a478fSMatthias Schiffer struct batadv_orig_node *orig_node; 558f02a478fSMatthias Schiffer int idx = 0; 559f02a478fSMatthias Schiffer 560f02a478fSMatthias Schiffer rcu_read_lock(); 561f02a478fSMatthias Schiffer hlist_for_each_entry_rcu(orig_node, head, hash_entry) { 562f02a478fSMatthias Schiffer if (idx++ < *idx_s) 563f02a478fSMatthias Schiffer continue; 564f02a478fSMatthias Schiffer 565f02a478fSMatthias Schiffer if (batadv_v_orig_dump_entry(msg, portid, seq, bat_priv, 566f02a478fSMatthias Schiffer if_outgoing, orig_node, sub)) { 567f02a478fSMatthias Schiffer rcu_read_unlock(); 568f02a478fSMatthias Schiffer *idx_s = idx - 1; 569f02a478fSMatthias Schiffer return -EMSGSIZE; 570f02a478fSMatthias Schiffer } 571f02a478fSMatthias Schiffer } 572f02a478fSMatthias Schiffer rcu_read_unlock(); 573f02a478fSMatthias Schiffer 574f02a478fSMatthias Schiffer *idx_s = 0; 575f02a478fSMatthias Schiffer *sub = 0; 576f02a478fSMatthias Schiffer return 0; 577f02a478fSMatthias Schiffer } 578f02a478fSMatthias Schiffer 579f02a478fSMatthias Schiffer /** 5807e9a8c2cSSven Eckelmann * batadv_v_orig_dump() - Dump the originators into a message 581f02a478fSMatthias Schiffer * @msg: Netlink message to dump into 582f02a478fSMatthias Schiffer * @cb: Control block containing additional options 583f02a478fSMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 584f02a478fSMatthias Schiffer * @if_outgoing: Limit dump to entries with this outgoing interface 585f02a478fSMatthias Schiffer */ 586f02a478fSMatthias Schiffer static void 587f02a478fSMatthias Schiffer batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb, 588f02a478fSMatthias Schiffer struct batadv_priv *bat_priv, 589f02a478fSMatthias Schiffer struct batadv_hard_iface *if_outgoing) 590f02a478fSMatthias Schiffer { 591f02a478fSMatthias Schiffer struct batadv_hashtable *hash = bat_priv->orig_hash; 592f02a478fSMatthias Schiffer struct hlist_head *head; 593f02a478fSMatthias Schiffer int bucket = cb->args[0]; 594f02a478fSMatthias Schiffer int idx = cb->args[1]; 595f02a478fSMatthias Schiffer int sub = cb->args[2]; 596f02a478fSMatthias Schiffer int portid = NETLINK_CB(cb->skb).portid; 597f02a478fSMatthias Schiffer 598f02a478fSMatthias Schiffer while (bucket < hash->size) { 599f02a478fSMatthias Schiffer head = &hash->table[bucket]; 600f02a478fSMatthias Schiffer 601f02a478fSMatthias Schiffer if (batadv_v_orig_dump_bucket(msg, portid, 602f02a478fSMatthias Schiffer cb->nlh->nlmsg_seq, 603f02a478fSMatthias Schiffer bat_priv, if_outgoing, head, &idx, 604f02a478fSMatthias Schiffer &sub)) 605f02a478fSMatthias Schiffer break; 606f02a478fSMatthias Schiffer 607f02a478fSMatthias Schiffer bucket++; 608f02a478fSMatthias Schiffer } 609f02a478fSMatthias Schiffer 610f02a478fSMatthias Schiffer cb->args[0] = bucket; 611f02a478fSMatthias Schiffer cb->args[1] = idx; 612f02a478fSMatthias Schiffer cb->args[2] = sub; 613f02a478fSMatthias Schiffer } 614f02a478fSMatthias Schiffer 61597869060SAntonio Quartulli static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1, 61697869060SAntonio Quartulli struct batadv_hard_iface *if_outgoing1, 61797869060SAntonio Quartulli struct batadv_neigh_node *neigh2, 61897869060SAntonio Quartulli struct batadv_hard_iface *if_outgoing2) 61997869060SAntonio Quartulli { 62097869060SAntonio Quartulli struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2; 62171f9d27dSSven Eckelmann int ret = 0; 62297869060SAntonio Quartulli 62397869060SAntonio Quartulli ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); 6246a4bc44bSSven Eckelmann if (!ifinfo1) 62571f9d27dSSven Eckelmann goto err_ifinfo1; 62671f9d27dSSven Eckelmann 62797869060SAntonio Quartulli ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); 6286a4bc44bSSven Eckelmann if (!ifinfo2) 62971f9d27dSSven Eckelmann goto err_ifinfo2; 63097869060SAntonio Quartulli 63171f9d27dSSven Eckelmann ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput; 63297869060SAntonio Quartulli 63371f9d27dSSven Eckelmann batadv_neigh_ifinfo_put(ifinfo2); 63471f9d27dSSven Eckelmann err_ifinfo2: 63571f9d27dSSven Eckelmann batadv_neigh_ifinfo_put(ifinfo1); 63671f9d27dSSven Eckelmann err_ifinfo1: 63771f9d27dSSven Eckelmann return ret; 63897869060SAntonio Quartulli } 63997869060SAntonio Quartulli 64097869060SAntonio Quartulli static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, 64197869060SAntonio Quartulli struct batadv_hard_iface *if_outgoing1, 64297869060SAntonio Quartulli struct batadv_neigh_node *neigh2, 64397869060SAntonio Quartulli struct batadv_hard_iface *if_outgoing2) 64497869060SAntonio Quartulli { 64597869060SAntonio Quartulli struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2; 64697869060SAntonio Quartulli u32 threshold; 64771f9d27dSSven Eckelmann bool ret = false; 64897869060SAntonio Quartulli 64997869060SAntonio Quartulli ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); 6506a4bc44bSSven Eckelmann if (!ifinfo1) 65171f9d27dSSven Eckelmann goto err_ifinfo1; 65297869060SAntonio Quartulli 65371f9d27dSSven Eckelmann ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); 6546a4bc44bSSven Eckelmann if (!ifinfo2) 65571f9d27dSSven Eckelmann goto err_ifinfo2; 656a45e932aSSven Eckelmann 65797869060SAntonio Quartulli threshold = ifinfo1->bat_v.throughput / 4; 65897869060SAntonio Quartulli threshold = ifinfo1->bat_v.throughput - threshold; 65997869060SAntonio Quartulli 66071f9d27dSSven Eckelmann ret = ifinfo2->bat_v.throughput > threshold; 66171f9d27dSSven Eckelmann 66271f9d27dSSven Eckelmann batadv_neigh_ifinfo_put(ifinfo2); 66371f9d27dSSven Eckelmann err_ifinfo2: 66471f9d27dSSven Eckelmann batadv_neigh_ifinfo_put(ifinfo1); 66571f9d27dSSven Eckelmann err_ifinfo1: 66671f9d27dSSven Eckelmann return ret; 66797869060SAntonio Quartulli } 66897869060SAntonio Quartulli 6691a9070ecSSven Eckelmann /** 6707e9a8c2cSSven Eckelmann * batadv_v_init_sel_class() - initialize GW selection class 6711a9070ecSSven Eckelmann * @bat_priv: the bat priv with all the soft interface information 6721a9070ecSSven Eckelmann */ 6731a9070ecSSven Eckelmann static void batadv_v_init_sel_class(struct batadv_priv *bat_priv) 6741a9070ecSSven Eckelmann { 6751a9070ecSSven Eckelmann /* set default throughput difference threshold to 5Mbps */ 6761a9070ecSSven Eckelmann atomic_set(&bat_priv->gw.sel_class, 50); 6771a9070ecSSven Eckelmann } 6781a9070ecSSven Eckelmann 67908686943SAntonio Quartulli static ssize_t batadv_v_store_sel_class(struct batadv_priv *bat_priv, 68008686943SAntonio Quartulli char *buff, size_t count) 68108686943SAntonio Quartulli { 68208686943SAntonio Quartulli u32 old_class, class; 68308686943SAntonio Quartulli 68408686943SAntonio Quartulli if (!batadv_parse_throughput(bat_priv->soft_iface, buff, 68508686943SAntonio Quartulli "B.A.T.M.A.N. V GW selection class", 68608686943SAntonio Quartulli &class)) 68708686943SAntonio Quartulli return -EINVAL; 68808686943SAntonio Quartulli 68908686943SAntonio Quartulli old_class = atomic_read(&bat_priv->gw.sel_class); 69008686943SAntonio Quartulli atomic_set(&bat_priv->gw.sel_class, class); 69108686943SAntonio Quartulli 69208686943SAntonio Quartulli if (old_class != class) 69308686943SAntonio Quartulli batadv_gw_reselect(bat_priv); 69408686943SAntonio Quartulli 69508686943SAntonio Quartulli return count; 69608686943SAntonio Quartulli } 69708686943SAntonio Quartulli 69808686943SAntonio Quartulli static ssize_t batadv_v_show_sel_class(struct batadv_priv *bat_priv, char *buff) 69908686943SAntonio Quartulli { 70008686943SAntonio Quartulli u32 class = atomic_read(&bat_priv->gw.sel_class); 70108686943SAntonio Quartulli 70208686943SAntonio Quartulli return sprintf(buff, "%u.%u MBit\n", class / 10, class % 10); 70308686943SAntonio Quartulli } 70408686943SAntonio Quartulli 70550164d8fSAntonio Quartulli /** 7067e9a8c2cSSven Eckelmann * batadv_v_gw_throughput_get() - retrieve the GW-bandwidth for a given GW 70750164d8fSAntonio Quartulli * @gw_node: the GW to retrieve the metric for 70850164d8fSAntonio Quartulli * @bw: the pointer where the metric will be stored. The metric is computed as 70950164d8fSAntonio Quartulli * the minimum between the GW advertised throughput and the path throughput to 71050164d8fSAntonio Quartulli * it in the mesh 71150164d8fSAntonio Quartulli * 71250164d8fSAntonio Quartulli * Return: 0 on success, -1 on failure 71350164d8fSAntonio Quartulli */ 71450164d8fSAntonio Quartulli static int batadv_v_gw_throughput_get(struct batadv_gw_node *gw_node, u32 *bw) 71550164d8fSAntonio Quartulli { 71650164d8fSAntonio Quartulli struct batadv_neigh_ifinfo *router_ifinfo = NULL; 71750164d8fSAntonio Quartulli struct batadv_orig_node *orig_node; 71850164d8fSAntonio Quartulli struct batadv_neigh_node *router; 71950164d8fSAntonio Quartulli int ret = -1; 72050164d8fSAntonio Quartulli 72150164d8fSAntonio Quartulli orig_node = gw_node->orig_node; 72250164d8fSAntonio Quartulli router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); 72350164d8fSAntonio Quartulli if (!router) 72450164d8fSAntonio Quartulli goto out; 72550164d8fSAntonio Quartulli 72650164d8fSAntonio Quartulli router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); 72750164d8fSAntonio Quartulli if (!router_ifinfo) 72850164d8fSAntonio Quartulli goto out; 72950164d8fSAntonio Quartulli 73050164d8fSAntonio Quartulli /* the GW metric is computed as the minimum between the path throughput 73150164d8fSAntonio Quartulli * to reach the GW itself and the advertised bandwidth. 73250164d8fSAntonio Quartulli * This gives us an approximation of the effective throughput that the 73350164d8fSAntonio Quartulli * client can expect via this particular GW node 73450164d8fSAntonio Quartulli */ 73550164d8fSAntonio Quartulli *bw = router_ifinfo->bat_v.throughput; 73650164d8fSAntonio Quartulli *bw = min_t(u32, *bw, gw_node->bandwidth_down); 73750164d8fSAntonio Quartulli 73850164d8fSAntonio Quartulli ret = 0; 73950164d8fSAntonio Quartulli out: 74050164d8fSAntonio Quartulli if (router) 74150164d8fSAntonio Quartulli batadv_neigh_node_put(router); 74250164d8fSAntonio Quartulli if (router_ifinfo) 74350164d8fSAntonio Quartulli batadv_neigh_ifinfo_put(router_ifinfo); 74450164d8fSAntonio Quartulli 74550164d8fSAntonio Quartulli return ret; 74650164d8fSAntonio Quartulli } 74750164d8fSAntonio Quartulli 74850164d8fSAntonio Quartulli /** 7497e9a8c2cSSven Eckelmann * batadv_v_gw_get_best_gw_node() - retrieve the best GW node 75050164d8fSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 75150164d8fSAntonio Quartulli * 75250164d8fSAntonio Quartulli * Return: the GW node having the best GW-metric, NULL if no GW is known 75350164d8fSAntonio Quartulli */ 75450164d8fSAntonio Quartulli static struct batadv_gw_node * 75550164d8fSAntonio Quartulli batadv_v_gw_get_best_gw_node(struct batadv_priv *bat_priv) 75650164d8fSAntonio Quartulli { 75750164d8fSAntonio Quartulli struct batadv_gw_node *gw_node, *curr_gw = NULL; 75850164d8fSAntonio Quartulli u32 max_bw = 0, bw; 75950164d8fSAntonio Quartulli 76050164d8fSAntonio Quartulli rcu_read_lock(); 76170ea5ceeSSven Eckelmann hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) { 76250164d8fSAntonio Quartulli if (!kref_get_unless_zero(&gw_node->refcount)) 76350164d8fSAntonio Quartulli continue; 76450164d8fSAntonio Quartulli 76550164d8fSAntonio Quartulli if (batadv_v_gw_throughput_get(gw_node, &bw) < 0) 76650164d8fSAntonio Quartulli goto next; 76750164d8fSAntonio Quartulli 768825ffe1fSSven Eckelmann if (curr_gw && bw <= max_bw) 76950164d8fSAntonio Quartulli goto next; 77050164d8fSAntonio Quartulli 77150164d8fSAntonio Quartulli if (curr_gw) 77250164d8fSAntonio Quartulli batadv_gw_node_put(curr_gw); 77350164d8fSAntonio Quartulli 77450164d8fSAntonio Quartulli curr_gw = gw_node; 77550164d8fSAntonio Quartulli kref_get(&curr_gw->refcount); 77650164d8fSAntonio Quartulli max_bw = bw; 77750164d8fSAntonio Quartulli 77850164d8fSAntonio Quartulli next: 77950164d8fSAntonio Quartulli batadv_gw_node_put(gw_node); 78050164d8fSAntonio Quartulli } 78150164d8fSAntonio Quartulli rcu_read_unlock(); 78250164d8fSAntonio Quartulli 78350164d8fSAntonio Quartulli return curr_gw; 78450164d8fSAntonio Quartulli } 78550164d8fSAntonio Quartulli 78650164d8fSAntonio Quartulli /** 7877e9a8c2cSSven Eckelmann * batadv_v_gw_is_eligible() - check if a originator would be selected as GW 78850164d8fSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 78950164d8fSAntonio Quartulli * @curr_gw_orig: originator representing the currently selected GW 79050164d8fSAntonio Quartulli * @orig_node: the originator representing the new candidate 79150164d8fSAntonio Quartulli * 79250164d8fSAntonio Quartulli * Return: true if orig_node can be selected as current GW, false otherwise 79350164d8fSAntonio Quartulli */ 79450164d8fSAntonio Quartulli static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv, 79550164d8fSAntonio Quartulli struct batadv_orig_node *curr_gw_orig, 79650164d8fSAntonio Quartulli struct batadv_orig_node *orig_node) 79750164d8fSAntonio Quartulli { 798422d2f77SSven Eckelmann struct batadv_gw_node *curr_gw, *orig_gw = NULL; 79950164d8fSAntonio Quartulli u32 gw_throughput, orig_throughput, threshold; 80050164d8fSAntonio Quartulli bool ret = false; 80150164d8fSAntonio Quartulli 80250164d8fSAntonio Quartulli threshold = atomic_read(&bat_priv->gw.sel_class); 80350164d8fSAntonio Quartulli 80450164d8fSAntonio Quartulli curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig); 80550164d8fSAntonio Quartulli if (!curr_gw) { 80650164d8fSAntonio Quartulli ret = true; 80750164d8fSAntonio Quartulli goto out; 80850164d8fSAntonio Quartulli } 80950164d8fSAntonio Quartulli 81050164d8fSAntonio Quartulli if (batadv_v_gw_throughput_get(curr_gw, &gw_throughput) < 0) { 81150164d8fSAntonio Quartulli ret = true; 81250164d8fSAntonio Quartulli goto out; 81350164d8fSAntonio Quartulli } 81450164d8fSAntonio Quartulli 81550164d8fSAntonio Quartulli orig_gw = batadv_gw_node_get(bat_priv, orig_node); 816198a62ddSSven Eckelmann if (!orig_gw) 81750164d8fSAntonio Quartulli goto out; 81850164d8fSAntonio Quartulli 81950164d8fSAntonio Quartulli if (batadv_v_gw_throughput_get(orig_gw, &orig_throughput) < 0) 82050164d8fSAntonio Quartulli goto out; 82150164d8fSAntonio Quartulli 82250164d8fSAntonio Quartulli if (orig_throughput < gw_throughput) 82350164d8fSAntonio Quartulli goto out; 82450164d8fSAntonio Quartulli 82550164d8fSAntonio Quartulli if ((orig_throughput - gw_throughput) < threshold) 82650164d8fSAntonio Quartulli goto out; 82750164d8fSAntonio Quartulli 82850164d8fSAntonio Quartulli batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 82950164d8fSAntonio Quartulli "Restarting gateway selection: better gateway found (throughput curr: %u, throughput new: %u)\n", 83050164d8fSAntonio Quartulli gw_throughput, orig_throughput); 83150164d8fSAntonio Quartulli 83250164d8fSAntonio Quartulli ret = true; 83350164d8fSAntonio Quartulli out: 83450164d8fSAntonio Quartulli if (curr_gw) 83550164d8fSAntonio Quartulli batadv_gw_node_put(curr_gw); 83650164d8fSAntonio Quartulli if (orig_gw) 83750164d8fSAntonio Quartulli batadv_gw_node_put(orig_gw); 83850164d8fSAntonio Quartulli 83950164d8fSAntonio Quartulli return ret; 84050164d8fSAntonio Quartulli } 84150164d8fSAntonio Quartulli 842dc1cbd14SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUGFS 84350164d8fSAntonio Quartulli /* fails if orig_node has no router */ 84450164d8fSAntonio Quartulli static int batadv_v_gw_write_buffer_text(struct batadv_priv *bat_priv, 84550164d8fSAntonio Quartulli struct seq_file *seq, 84650164d8fSAntonio Quartulli const struct batadv_gw_node *gw_node) 84750164d8fSAntonio Quartulli { 84850164d8fSAntonio Quartulli struct batadv_gw_node *curr_gw; 84950164d8fSAntonio Quartulli struct batadv_neigh_node *router; 85050164d8fSAntonio Quartulli struct batadv_neigh_ifinfo *router_ifinfo = NULL; 85150164d8fSAntonio Quartulli int ret = -1; 85250164d8fSAntonio Quartulli 85350164d8fSAntonio Quartulli router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); 85450164d8fSAntonio Quartulli if (!router) 85550164d8fSAntonio Quartulli goto out; 85650164d8fSAntonio Quartulli 85750164d8fSAntonio Quartulli router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); 85850164d8fSAntonio Quartulli if (!router_ifinfo) 85950164d8fSAntonio Quartulli goto out; 86050164d8fSAntonio Quartulli 86150164d8fSAntonio Quartulli curr_gw = batadv_gw_get_selected_gw_node(bat_priv); 86250164d8fSAntonio Quartulli 86350164d8fSAntonio Quartulli seq_printf(seq, "%s %pM (%9u.%1u) %pM [%10s]: %u.%u/%u.%u MBit\n", 86450164d8fSAntonio Quartulli (curr_gw == gw_node ? "=>" : " "), 86550164d8fSAntonio Quartulli gw_node->orig_node->orig, 86650164d8fSAntonio Quartulli router_ifinfo->bat_v.throughput / 10, 86750164d8fSAntonio Quartulli router_ifinfo->bat_v.throughput % 10, router->addr, 86850164d8fSAntonio Quartulli router->if_incoming->net_dev->name, 86950164d8fSAntonio Quartulli gw_node->bandwidth_down / 10, 87050164d8fSAntonio Quartulli gw_node->bandwidth_down % 10, 87150164d8fSAntonio Quartulli gw_node->bandwidth_up / 10, 87250164d8fSAntonio Quartulli gw_node->bandwidth_up % 10); 87350164d8fSAntonio Quartulli ret = seq_has_overflowed(seq) ? -1 : 0; 87450164d8fSAntonio Quartulli 87550164d8fSAntonio Quartulli if (curr_gw) 87650164d8fSAntonio Quartulli batadv_gw_node_put(curr_gw); 87750164d8fSAntonio Quartulli out: 87850164d8fSAntonio Quartulli if (router_ifinfo) 87950164d8fSAntonio Quartulli batadv_neigh_ifinfo_put(router_ifinfo); 88050164d8fSAntonio Quartulli if (router) 88150164d8fSAntonio Quartulli batadv_neigh_node_put(router); 88250164d8fSAntonio Quartulli return ret; 88350164d8fSAntonio Quartulli } 88450164d8fSAntonio Quartulli 88550164d8fSAntonio Quartulli /** 8867e9a8c2cSSven Eckelmann * batadv_v_gw_print() - print the gateway list 88750164d8fSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 88850164d8fSAntonio Quartulli * @seq: gateway table seq_file struct 88950164d8fSAntonio Quartulli */ 89050164d8fSAntonio Quartulli static void batadv_v_gw_print(struct batadv_priv *bat_priv, 89150164d8fSAntonio Quartulli struct seq_file *seq) 89250164d8fSAntonio Quartulli { 89350164d8fSAntonio Quartulli struct batadv_gw_node *gw_node; 89450164d8fSAntonio Quartulli int gw_count = 0; 89550164d8fSAntonio Quartulli 89650164d8fSAntonio Quartulli seq_puts(seq, 89750164d8fSAntonio Quartulli " Gateway ( throughput) Nexthop [outgoingIF]: advertised uplink bandwidth\n"); 89850164d8fSAntonio Quartulli 89950164d8fSAntonio Quartulli rcu_read_lock(); 90070ea5ceeSSven Eckelmann hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) { 90150164d8fSAntonio Quartulli /* fails if orig_node has no router */ 90250164d8fSAntonio Quartulli if (batadv_v_gw_write_buffer_text(bat_priv, seq, gw_node) < 0) 90350164d8fSAntonio Quartulli continue; 90450164d8fSAntonio Quartulli 90550164d8fSAntonio Quartulli gw_count++; 90650164d8fSAntonio Quartulli } 90750164d8fSAntonio Quartulli rcu_read_unlock(); 90850164d8fSAntonio Quartulli 90950164d8fSAntonio Quartulli if (gw_count == 0) 91050164d8fSAntonio Quartulli seq_puts(seq, "No gateways in range ...\n"); 91150164d8fSAntonio Quartulli } 912dc1cbd14SSven Eckelmann #endif 91350164d8fSAntonio Quartulli 914b71bb6f9SSven Eckelmann /** 9157e9a8c2cSSven Eckelmann * batadv_v_gw_dump_entry() - Dump a gateway into a message 916b71bb6f9SSven Eckelmann * @msg: Netlink message to dump into 917b71bb6f9SSven Eckelmann * @portid: Port making netlink request 918b71bb6f9SSven Eckelmann * @seq: Sequence number of netlink message 919b71bb6f9SSven Eckelmann * @bat_priv: The bat priv with all the soft interface information 920b71bb6f9SSven Eckelmann * @gw_node: Gateway to be dumped 921b71bb6f9SSven Eckelmann * 922b71bb6f9SSven Eckelmann * Return: Error code, or 0 on success 923b71bb6f9SSven Eckelmann */ 924b71bb6f9SSven Eckelmann static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, 925b71bb6f9SSven Eckelmann struct batadv_priv *bat_priv, 926b71bb6f9SSven Eckelmann struct batadv_gw_node *gw_node) 927b71bb6f9SSven Eckelmann { 928b71bb6f9SSven Eckelmann struct batadv_neigh_ifinfo *router_ifinfo = NULL; 929b71bb6f9SSven Eckelmann struct batadv_neigh_node *router; 930b71bb6f9SSven Eckelmann struct batadv_gw_node *curr_gw; 931b71bb6f9SSven Eckelmann int ret = -EINVAL; 932b71bb6f9SSven Eckelmann void *hdr; 933b71bb6f9SSven Eckelmann 934b71bb6f9SSven Eckelmann router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); 935b71bb6f9SSven Eckelmann if (!router) 936b71bb6f9SSven Eckelmann goto out; 937b71bb6f9SSven Eckelmann 938b71bb6f9SSven Eckelmann router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); 939b71bb6f9SSven Eckelmann if (!router_ifinfo) 940b71bb6f9SSven Eckelmann goto out; 941b71bb6f9SSven Eckelmann 942b71bb6f9SSven Eckelmann curr_gw = batadv_gw_get_selected_gw_node(bat_priv); 943b71bb6f9SSven Eckelmann 944b71bb6f9SSven Eckelmann hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, 945b71bb6f9SSven Eckelmann NLM_F_MULTI, BATADV_CMD_GET_GATEWAYS); 946b71bb6f9SSven Eckelmann if (!hdr) { 947b71bb6f9SSven Eckelmann ret = -ENOBUFS; 948b71bb6f9SSven Eckelmann goto out; 949b71bb6f9SSven Eckelmann } 950b71bb6f9SSven Eckelmann 951b71bb6f9SSven Eckelmann ret = -EMSGSIZE; 952b71bb6f9SSven Eckelmann 953b71bb6f9SSven Eckelmann if (curr_gw == gw_node) { 954b71bb6f9SSven Eckelmann if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) { 955b71bb6f9SSven Eckelmann genlmsg_cancel(msg, hdr); 956b71bb6f9SSven Eckelmann goto out; 957b71bb6f9SSven Eckelmann } 958b71bb6f9SSven Eckelmann } 959b71bb6f9SSven Eckelmann 960b71bb6f9SSven Eckelmann if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, 961b71bb6f9SSven Eckelmann gw_node->orig_node->orig)) { 962b71bb6f9SSven Eckelmann genlmsg_cancel(msg, hdr); 963b71bb6f9SSven Eckelmann goto out; 964b71bb6f9SSven Eckelmann } 965b71bb6f9SSven Eckelmann 966b71bb6f9SSven Eckelmann if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, 967b71bb6f9SSven Eckelmann router_ifinfo->bat_v.throughput)) { 968b71bb6f9SSven Eckelmann genlmsg_cancel(msg, hdr); 969b71bb6f9SSven Eckelmann goto out; 970b71bb6f9SSven Eckelmann } 971b71bb6f9SSven Eckelmann 972b71bb6f9SSven Eckelmann if (nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN, router->addr)) { 973b71bb6f9SSven Eckelmann genlmsg_cancel(msg, hdr); 974b71bb6f9SSven Eckelmann goto out; 975b71bb6f9SSven Eckelmann } 976b71bb6f9SSven Eckelmann 977b71bb6f9SSven Eckelmann if (nla_put_string(msg, BATADV_ATTR_HARD_IFNAME, 978b71bb6f9SSven Eckelmann router->if_incoming->net_dev->name)) { 979b71bb6f9SSven Eckelmann genlmsg_cancel(msg, hdr); 980b71bb6f9SSven Eckelmann goto out; 981b71bb6f9SSven Eckelmann } 982b71bb6f9SSven Eckelmann 983b71bb6f9SSven Eckelmann if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN, 984b71bb6f9SSven Eckelmann gw_node->bandwidth_down)) { 985b71bb6f9SSven Eckelmann genlmsg_cancel(msg, hdr); 986b71bb6f9SSven Eckelmann goto out; 987b71bb6f9SSven Eckelmann } 988b71bb6f9SSven Eckelmann 989b71bb6f9SSven Eckelmann if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP, gw_node->bandwidth_up)) { 990b71bb6f9SSven Eckelmann genlmsg_cancel(msg, hdr); 991b71bb6f9SSven Eckelmann goto out; 992b71bb6f9SSven Eckelmann } 993b71bb6f9SSven Eckelmann 994b71bb6f9SSven Eckelmann genlmsg_end(msg, hdr); 995b71bb6f9SSven Eckelmann ret = 0; 996b71bb6f9SSven Eckelmann 997b71bb6f9SSven Eckelmann out: 998b71bb6f9SSven Eckelmann if (router_ifinfo) 999b71bb6f9SSven Eckelmann batadv_neigh_ifinfo_put(router_ifinfo); 1000b71bb6f9SSven Eckelmann if (router) 1001b71bb6f9SSven Eckelmann batadv_neigh_node_put(router); 1002b71bb6f9SSven Eckelmann return ret; 1003b71bb6f9SSven Eckelmann } 1004b71bb6f9SSven Eckelmann 1005b71bb6f9SSven Eckelmann /** 10067e9a8c2cSSven Eckelmann * batadv_v_gw_dump() - Dump gateways into a message 1007b71bb6f9SSven Eckelmann * @msg: Netlink message to dump into 1008b71bb6f9SSven Eckelmann * @cb: Control block containing additional options 1009b71bb6f9SSven Eckelmann * @bat_priv: The bat priv with all the soft interface information 1010b71bb6f9SSven Eckelmann */ 1011b71bb6f9SSven Eckelmann static void batadv_v_gw_dump(struct sk_buff *msg, struct netlink_callback *cb, 1012b71bb6f9SSven Eckelmann struct batadv_priv *bat_priv) 1013b71bb6f9SSven Eckelmann { 1014b71bb6f9SSven Eckelmann int portid = NETLINK_CB(cb->skb).portid; 1015b71bb6f9SSven Eckelmann struct batadv_gw_node *gw_node; 1016b71bb6f9SSven Eckelmann int idx_skip = cb->args[0]; 1017b71bb6f9SSven Eckelmann int idx = 0; 1018b71bb6f9SSven Eckelmann 1019b71bb6f9SSven Eckelmann rcu_read_lock(); 102070ea5ceeSSven Eckelmann hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) { 1021b71bb6f9SSven Eckelmann if (idx++ < idx_skip) 1022b71bb6f9SSven Eckelmann continue; 1023b71bb6f9SSven Eckelmann 1024b71bb6f9SSven Eckelmann if (batadv_v_gw_dump_entry(msg, portid, cb->nlh->nlmsg_seq, 1025b71bb6f9SSven Eckelmann bat_priv, gw_node)) { 1026b71bb6f9SSven Eckelmann idx_skip = idx - 1; 1027b71bb6f9SSven Eckelmann goto unlock; 1028b71bb6f9SSven Eckelmann } 1029b71bb6f9SSven Eckelmann } 1030b71bb6f9SSven Eckelmann 1031b71bb6f9SSven Eckelmann idx_skip = idx; 1032b71bb6f9SSven Eckelmann unlock: 1033b71bb6f9SSven Eckelmann rcu_read_unlock(); 1034b71bb6f9SSven Eckelmann 1035b71bb6f9SSven Eckelmann cb->args[0] = idx_skip; 1036b71bb6f9SSven Eckelmann } 1037b71bb6f9SSven Eckelmann 1038d6f94d91SLinus Luessing static struct batadv_algo_ops batadv_batman_v __read_mostly = { 1039d6f94d91SLinus Luessing .name = "BATMAN_V", 104029824a55SAntonio Quartulli .iface = { 104129824a55SAntonio Quartulli .activate = batadv_v_iface_activate, 104229824a55SAntonio Quartulli .enable = batadv_v_iface_enable, 104329824a55SAntonio Quartulli .disable = batadv_v_iface_disable, 104429824a55SAntonio Quartulli .update_mac = batadv_v_iface_update_mac, 104529824a55SAntonio Quartulli .primary_set = batadv_v_primary_iface_set, 104629824a55SAntonio Quartulli }, 104729824a55SAntonio Quartulli .neigh = { 104829824a55SAntonio Quartulli .hardif_init = batadv_v_hardif_neigh_init, 104929824a55SAntonio Quartulli .cmp = batadv_v_neigh_cmp, 105029824a55SAntonio Quartulli .is_similar_or_better = batadv_v_neigh_is_sob, 1051dc1cbd14SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUGFS 105229824a55SAntonio Quartulli .print = batadv_v_neigh_print, 1053dc1cbd14SSven Eckelmann #endif 1054f02a478fSMatthias Schiffer .dump = batadv_v_neigh_dump, 105529824a55SAntonio Quartulli }, 105629824a55SAntonio Quartulli .orig = { 1057dc1cbd14SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUGFS 105829824a55SAntonio Quartulli .print = batadv_v_orig_print, 1059dc1cbd14SSven Eckelmann #endif 1060f02a478fSMatthias Schiffer .dump = batadv_v_orig_dump, 106129824a55SAntonio Quartulli }, 106208686943SAntonio Quartulli .gw = { 10631a9070ecSSven Eckelmann .init_sel_class = batadv_v_init_sel_class, 106408686943SAntonio Quartulli .store_sel_class = batadv_v_store_sel_class, 106508686943SAntonio Quartulli .show_sel_class = batadv_v_show_sel_class, 106650164d8fSAntonio Quartulli .get_best_gw_node = batadv_v_gw_get_best_gw_node, 106750164d8fSAntonio Quartulli .is_eligible = batadv_v_gw_is_eligible, 1068dc1cbd14SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUGFS 106950164d8fSAntonio Quartulli .print = batadv_v_gw_print, 1070dc1cbd14SSven Eckelmann #endif 1071b71bb6f9SSven Eckelmann .dump = batadv_v_gw_dump, 107208686943SAntonio Quartulli }, 1073d6f94d91SLinus Luessing }; 1074d6f94d91SLinus Luessing 1075d6f94d91SLinus Luessing /** 10767e9a8c2cSSven Eckelmann * batadv_v_hardif_init() - initialize the algorithm specific fields in the 10777db682d1SMarek Lindner * hard-interface object 10787db682d1SMarek Lindner * @hard_iface: the hard-interface to initialize 10797db682d1SMarek Lindner */ 10807db682d1SMarek Lindner void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface) 10817db682d1SMarek Lindner { 10827db682d1SMarek Lindner /* enable link throughput auto-detection by setting the throughput 10837db682d1SMarek Lindner * override to zero 10847db682d1SMarek Lindner */ 10857db682d1SMarek Lindner atomic_set(&hard_iface->bat_v.throughput_override, 0); 10867db682d1SMarek Lindner atomic_set(&hard_iface->bat_v.elp_interval, 500); 10877db682d1SMarek Lindner } 10887db682d1SMarek Lindner 10897db682d1SMarek Lindner /** 10907e9a8c2cSSven Eckelmann * batadv_v_mesh_init() - initialize the B.A.T.M.A.N. V private resources for a 10910da00359SAntonio Quartulli * mesh 10920da00359SAntonio Quartulli * @bat_priv: the object representing the mesh interface to initialise 10930da00359SAntonio Quartulli * 10940da00359SAntonio Quartulli * Return: 0 on success or a negative error code otherwise 10950da00359SAntonio Quartulli */ 10960da00359SAntonio Quartulli int batadv_v_mesh_init(struct batadv_priv *bat_priv) 10970da00359SAntonio Quartulli { 109850164d8fSAntonio Quartulli int ret = 0; 109950164d8fSAntonio Quartulli 110050164d8fSAntonio Quartulli ret = batadv_v_ogm_init(bat_priv); 110150164d8fSAntonio Quartulli if (ret < 0) 110250164d8fSAntonio Quartulli return ret; 110350164d8fSAntonio Quartulli 110450164d8fSAntonio Quartulli return 0; 11050da00359SAntonio Quartulli } 11060da00359SAntonio Quartulli 11070da00359SAntonio Quartulli /** 11087e9a8c2cSSven Eckelmann * batadv_v_mesh_free() - free the B.A.T.M.A.N. V private resources for a mesh 11090da00359SAntonio Quartulli * @bat_priv: the object representing the mesh interface to free 11100da00359SAntonio Quartulli */ 11110da00359SAntonio Quartulli void batadv_v_mesh_free(struct batadv_priv *bat_priv) 11120da00359SAntonio Quartulli { 11130da00359SAntonio Quartulli batadv_v_ogm_free(bat_priv); 11140da00359SAntonio Quartulli } 11150da00359SAntonio Quartulli 11160da00359SAntonio Quartulli /** 11177e9a8c2cSSven Eckelmann * batadv_v_init() - B.A.T.M.A.N. V initialization function 1118d6f94d91SLinus Luessing * 1119d6f94d91SLinus Luessing * Description: Takes care of initializing all the subcomponents. 1120d6f94d91SLinus Luessing * It is invoked upon module load only. 1121d6f94d91SLinus Luessing * 1122d6f94d91SLinus Luessing * Return: 0 on success or a negative error code otherwise 1123d6f94d91SLinus Luessing */ 1124d6f94d91SLinus Luessing int __init batadv_v_init(void) 1125d6f94d91SLinus Luessing { 1126162bd64cSLinus Luessing int ret; 1127162bd64cSLinus Luessing 1128162bd64cSLinus Luessing /* B.A.T.M.A.N. V echo location protocol packet */ 1129162bd64cSLinus Luessing ret = batadv_recv_handler_register(BATADV_ELP, 1130162bd64cSLinus Luessing batadv_v_elp_packet_recv); 1131162bd64cSLinus Luessing if (ret < 0) 1132162bd64cSLinus Luessing return ret; 1133162bd64cSLinus Luessing 11340da00359SAntonio Quartulli ret = batadv_recv_handler_register(BATADV_OGM2, 11350da00359SAntonio Quartulli batadv_v_ogm_packet_recv); 1136162bd64cSLinus Luessing if (ret < 0) 11370da00359SAntonio Quartulli goto elp_unregister; 11380da00359SAntonio Quartulli 11390da00359SAntonio Quartulli ret = batadv_algo_register(&batadv_batman_v); 11400da00359SAntonio Quartulli if (ret < 0) 11410da00359SAntonio Quartulli goto ogm_unregister; 11420da00359SAntonio Quartulli 11430da00359SAntonio Quartulli return ret; 11440da00359SAntonio Quartulli 11450da00359SAntonio Quartulli ogm_unregister: 11460da00359SAntonio Quartulli batadv_recv_handler_unregister(BATADV_OGM2); 11470da00359SAntonio Quartulli 11480da00359SAntonio Quartulli elp_unregister: 1149162bd64cSLinus Luessing batadv_recv_handler_unregister(BATADV_ELP); 1150162bd64cSLinus Luessing 1151162bd64cSLinus Luessing return ret; 1152d6f94d91SLinus Luessing } 1153