xref: /openbmc/linux/net/batman-adv/bat_v.c (revision fec149f5)
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