xref: /OK3568_Linux_fs/kernel/net/batman-adv/bat_v.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (C) 2013-2020  B.A.T.M.A.N. contributors:
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Linus Lüssing, Marek Lindner
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include "bat_v.h"
8*4882a593Smuzhiyun #include "main.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/atomic.h>
11*4882a593Smuzhiyun #include <linux/cache.h>
12*4882a593Smuzhiyun #include <linux/errno.h>
13*4882a593Smuzhiyun #include <linux/if_ether.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/jiffies.h>
16*4882a593Smuzhiyun #include <linux/kernel.h>
17*4882a593Smuzhiyun #include <linux/kref.h>
18*4882a593Smuzhiyun #include <linux/list.h>
19*4882a593Smuzhiyun #include <linux/netdevice.h>
20*4882a593Smuzhiyun #include <linux/netlink.h>
21*4882a593Smuzhiyun #include <linux/rculist.h>
22*4882a593Smuzhiyun #include <linux/rcupdate.h>
23*4882a593Smuzhiyun #include <linux/seq_file.h>
24*4882a593Smuzhiyun #include <linux/skbuff.h>
25*4882a593Smuzhiyun #include <linux/spinlock.h>
26*4882a593Smuzhiyun #include <linux/stddef.h>
27*4882a593Smuzhiyun #include <linux/types.h>
28*4882a593Smuzhiyun #include <linux/workqueue.h>
29*4882a593Smuzhiyun #include <net/genetlink.h>
30*4882a593Smuzhiyun #include <net/netlink.h>
31*4882a593Smuzhiyun #include <uapi/linux/batadv_packet.h>
32*4882a593Smuzhiyun #include <uapi/linux/batman_adv.h>
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #include "bat_algo.h"
35*4882a593Smuzhiyun #include "bat_v_elp.h"
36*4882a593Smuzhiyun #include "bat_v_ogm.h"
37*4882a593Smuzhiyun #include "gateway_client.h"
38*4882a593Smuzhiyun #include "gateway_common.h"
39*4882a593Smuzhiyun #include "hard-interface.h"
40*4882a593Smuzhiyun #include "hash.h"
41*4882a593Smuzhiyun #include "log.h"
42*4882a593Smuzhiyun #include "netlink.h"
43*4882a593Smuzhiyun #include "originator.h"
44*4882a593Smuzhiyun 
batadv_v_iface_activate(struct batadv_hard_iface * hard_iface)45*4882a593Smuzhiyun static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
48*4882a593Smuzhiyun 	struct batadv_hard_iface *primary_if;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	primary_if = batadv_primary_if_get_selected(bat_priv);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	if (primary_if) {
53*4882a593Smuzhiyun 		batadv_v_elp_iface_activate(primary_if, hard_iface);
54*4882a593Smuzhiyun 		batadv_hardif_put(primary_if);
55*4882a593Smuzhiyun 	}
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	/* B.A.T.M.A.N. V does not use any queuing mechanism, therefore it can
58*4882a593Smuzhiyun 	 * set the interface as ACTIVE right away, without any risk of race
59*4882a593Smuzhiyun 	 * condition
60*4882a593Smuzhiyun 	 */
61*4882a593Smuzhiyun 	if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
62*4882a593Smuzhiyun 		hard_iface->if_status = BATADV_IF_ACTIVE;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
batadv_v_iface_enable(struct batadv_hard_iface * hard_iface)65*4882a593Smuzhiyun static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	int ret;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	ret = batadv_v_elp_iface_enable(hard_iface);
70*4882a593Smuzhiyun 	if (ret < 0)
71*4882a593Smuzhiyun 		return ret;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	ret = batadv_v_ogm_iface_enable(hard_iface);
74*4882a593Smuzhiyun 	if (ret < 0)
75*4882a593Smuzhiyun 		batadv_v_elp_iface_disable(hard_iface);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return ret;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
batadv_v_iface_disable(struct batadv_hard_iface * hard_iface)80*4882a593Smuzhiyun static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	batadv_v_ogm_iface_disable(hard_iface);
83*4882a593Smuzhiyun 	batadv_v_elp_iface_disable(hard_iface);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
batadv_v_primary_iface_set(struct batadv_hard_iface * hard_iface)86*4882a593Smuzhiyun static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	batadv_v_elp_primary_iface_set(hard_iface);
89*4882a593Smuzhiyun 	batadv_v_ogm_primary_iface_set(hard_iface);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun /**
93*4882a593Smuzhiyun  * batadv_v_iface_update_mac() - react to hard-interface MAC address change
94*4882a593Smuzhiyun  * @hard_iface: the modified interface
95*4882a593Smuzhiyun  *
96*4882a593Smuzhiyun  * If the modified interface is the primary one, update the originator
97*4882a593Smuzhiyun  * address in the ELP and OGM messages to reflect the new MAC address.
98*4882a593Smuzhiyun  */
batadv_v_iface_update_mac(struct batadv_hard_iface * hard_iface)99*4882a593Smuzhiyun static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
102*4882a593Smuzhiyun 	struct batadv_hard_iface *primary_if;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	primary_if = batadv_primary_if_get_selected(bat_priv);
105*4882a593Smuzhiyun 	if (primary_if != hard_iface)
106*4882a593Smuzhiyun 		goto out;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	batadv_v_primary_iface_set(hard_iface);
109*4882a593Smuzhiyun out:
110*4882a593Smuzhiyun 	if (primary_if)
111*4882a593Smuzhiyun 		batadv_hardif_put(primary_if);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun static void
batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node * hardif_neigh)115*4882a593Smuzhiyun batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	ewma_throughput_init(&hardif_neigh->bat_v.throughput);
118*4882a593Smuzhiyun 	INIT_WORK(&hardif_neigh->bat_v.metric_work,
119*4882a593Smuzhiyun 		  batadv_v_elp_throughput_metric_update);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_DEBUGFS
123*4882a593Smuzhiyun /**
124*4882a593Smuzhiyun  * batadv_v_orig_print_neigh() - print neighbors for the originator table
125*4882a593Smuzhiyun  * @orig_node: the orig_node for which the neighbors are printed
126*4882a593Smuzhiyun  * @if_outgoing: outgoing interface for these entries
127*4882a593Smuzhiyun  * @seq: debugfs table seq_file struct
128*4882a593Smuzhiyun  *
129*4882a593Smuzhiyun  * Must be called while holding an rcu lock.
130*4882a593Smuzhiyun  */
131*4882a593Smuzhiyun static void
batadv_v_orig_print_neigh(struct batadv_orig_node * orig_node,struct batadv_hard_iface * if_outgoing,struct seq_file * seq)132*4882a593Smuzhiyun batadv_v_orig_print_neigh(struct batadv_orig_node *orig_node,
133*4882a593Smuzhiyun 			  struct batadv_hard_iface *if_outgoing,
134*4882a593Smuzhiyun 			  struct seq_file *seq)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node;
137*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *n_ifinfo;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
140*4882a593Smuzhiyun 		n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
141*4882a593Smuzhiyun 		if (!n_ifinfo)
142*4882a593Smuzhiyun 			continue;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 		seq_printf(seq, " %pM (%9u.%1u)",
145*4882a593Smuzhiyun 			   neigh_node->addr,
146*4882a593Smuzhiyun 			   n_ifinfo->bat_v.throughput / 10,
147*4882a593Smuzhiyun 			   n_ifinfo->bat_v.throughput % 10);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 		batadv_neigh_ifinfo_put(n_ifinfo);
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun /**
154*4882a593Smuzhiyun  * batadv_v_hardif_neigh_print() - print a single ELP neighbour node
155*4882a593Smuzhiyun  * @seq: neighbour table seq_file struct
156*4882a593Smuzhiyun  * @hardif_neigh: hardif neighbour information
157*4882a593Smuzhiyun  */
158*4882a593Smuzhiyun static void
batadv_v_hardif_neigh_print(struct seq_file * seq,struct batadv_hardif_neigh_node * hardif_neigh)159*4882a593Smuzhiyun batadv_v_hardif_neigh_print(struct seq_file *seq,
160*4882a593Smuzhiyun 			    struct batadv_hardif_neigh_node *hardif_neigh)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	int last_secs, last_msecs;
163*4882a593Smuzhiyun 	u32 throughput;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000;
166*4882a593Smuzhiyun 	last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000;
167*4882a593Smuzhiyun 	throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n",
170*4882a593Smuzhiyun 		   hardif_neigh->addr, last_secs, last_msecs, throughput / 10,
171*4882a593Smuzhiyun 		   throughput % 10, hardif_neigh->if_incoming->net_dev->name);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun /**
175*4882a593Smuzhiyun  * batadv_v_neigh_print() - print the single hop neighbour list
176*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
177*4882a593Smuzhiyun  * @seq: neighbour table seq_file struct
178*4882a593Smuzhiyun  */
batadv_v_neigh_print(struct batadv_priv * bat_priv,struct seq_file * seq)179*4882a593Smuzhiyun static void batadv_v_neigh_print(struct batadv_priv *bat_priv,
180*4882a593Smuzhiyun 				 struct seq_file *seq)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct net_device *net_dev = (struct net_device *)seq->private;
183*4882a593Smuzhiyun 	struct batadv_hardif_neigh_node *hardif_neigh;
184*4882a593Smuzhiyun 	struct batadv_hard_iface *hard_iface;
185*4882a593Smuzhiyun 	int batman_count = 0;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	seq_puts(seq,
188*4882a593Smuzhiyun 		 "  Neighbor        last-seen ( throughput) [        IF]\n");
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	rcu_read_lock();
191*4882a593Smuzhiyun 	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
192*4882a593Smuzhiyun 		if (hard_iface->soft_iface != net_dev)
193*4882a593Smuzhiyun 			continue;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 		hlist_for_each_entry_rcu(hardif_neigh,
196*4882a593Smuzhiyun 					 &hard_iface->neigh_list, list) {
197*4882a593Smuzhiyun 			batadv_v_hardif_neigh_print(seq, hardif_neigh);
198*4882a593Smuzhiyun 			batman_count++;
199*4882a593Smuzhiyun 		}
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 	rcu_read_unlock();
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (batman_count == 0)
204*4882a593Smuzhiyun 		seq_puts(seq, "No batman nodes in range ...\n");
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun #endif
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun /**
209*4882a593Smuzhiyun  * batadv_v_neigh_dump_neigh() - Dump a neighbour into a message
210*4882a593Smuzhiyun  * @msg: Netlink message to dump into
211*4882a593Smuzhiyun  * @portid: Port making netlink request
212*4882a593Smuzhiyun  * @seq: Sequence number of netlink message
213*4882a593Smuzhiyun  * @hardif_neigh: Neighbour to dump
214*4882a593Smuzhiyun  *
215*4882a593Smuzhiyun  * Return: Error code, or 0 on success
216*4882a593Smuzhiyun  */
217*4882a593Smuzhiyun static int
batadv_v_neigh_dump_neigh(struct sk_buff * msg,u32 portid,u32 seq,struct batadv_hardif_neigh_node * hardif_neigh)218*4882a593Smuzhiyun batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
219*4882a593Smuzhiyun 			  struct batadv_hardif_neigh_node *hardif_neigh)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	void *hdr;
222*4882a593Smuzhiyun 	unsigned int last_seen_msecs;
223*4882a593Smuzhiyun 	u32 throughput;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen);
226*4882a593Smuzhiyun 	throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
227*4882a593Smuzhiyun 	throughput = throughput * 100;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
230*4882a593Smuzhiyun 			  BATADV_CMD_GET_NEIGHBORS);
231*4882a593Smuzhiyun 	if (!hdr)
232*4882a593Smuzhiyun 		return -ENOBUFS;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
235*4882a593Smuzhiyun 		    hardif_neigh->addr) ||
236*4882a593Smuzhiyun 	    nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
237*4882a593Smuzhiyun 			hardif_neigh->if_incoming->net_dev->ifindex) ||
238*4882a593Smuzhiyun 	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
239*4882a593Smuzhiyun 			last_seen_msecs) ||
240*4882a593Smuzhiyun 	    nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput))
241*4882a593Smuzhiyun 		goto nla_put_failure;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	genlmsg_end(msg, hdr);
244*4882a593Smuzhiyun 	return 0;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun  nla_put_failure:
247*4882a593Smuzhiyun 	genlmsg_cancel(msg, hdr);
248*4882a593Smuzhiyun 	return -EMSGSIZE;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun /**
252*4882a593Smuzhiyun  * batadv_v_neigh_dump_hardif() - Dump the  neighbours of a hard interface into
253*4882a593Smuzhiyun  *  a message
254*4882a593Smuzhiyun  * @msg: Netlink message to dump into
255*4882a593Smuzhiyun  * @portid: Port making netlink request
256*4882a593Smuzhiyun  * @seq: Sequence number of netlink message
257*4882a593Smuzhiyun  * @bat_priv: The bat priv with all the soft interface information
258*4882a593Smuzhiyun  * @hard_iface: The hard interface to be dumped
259*4882a593Smuzhiyun  * @idx_s: Entries to be skipped
260*4882a593Smuzhiyun  *
261*4882a593Smuzhiyun  * This function assumes the caller holds rcu_read_lock().
262*4882a593Smuzhiyun  *
263*4882a593Smuzhiyun  * Return: Error code, or 0 on success
264*4882a593Smuzhiyun  */
265*4882a593Smuzhiyun static int
batadv_v_neigh_dump_hardif(struct sk_buff * msg,u32 portid,u32 seq,struct batadv_priv * bat_priv,struct batadv_hard_iface * hard_iface,int * idx_s)266*4882a593Smuzhiyun batadv_v_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
267*4882a593Smuzhiyun 			   struct batadv_priv *bat_priv,
268*4882a593Smuzhiyun 			   struct batadv_hard_iface *hard_iface,
269*4882a593Smuzhiyun 			   int *idx_s)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	struct batadv_hardif_neigh_node *hardif_neigh;
272*4882a593Smuzhiyun 	int idx = 0;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(hardif_neigh,
275*4882a593Smuzhiyun 				 &hard_iface->neigh_list, list) {
276*4882a593Smuzhiyun 		if (idx++ < *idx_s)
277*4882a593Smuzhiyun 			continue;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 		if (batadv_v_neigh_dump_neigh(msg, portid, seq, hardif_neigh)) {
280*4882a593Smuzhiyun 			*idx_s = idx - 1;
281*4882a593Smuzhiyun 			return -EMSGSIZE;
282*4882a593Smuzhiyun 		}
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	*idx_s = 0;
286*4882a593Smuzhiyun 	return 0;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun /**
290*4882a593Smuzhiyun  * batadv_v_neigh_dump() - Dump the neighbours of a hard interface  into a
291*4882a593Smuzhiyun  *  message
292*4882a593Smuzhiyun  * @msg: Netlink message to dump into
293*4882a593Smuzhiyun  * @cb: Control block containing additional options
294*4882a593Smuzhiyun  * @bat_priv: The bat priv with all the soft interface information
295*4882a593Smuzhiyun  * @single_hardif: Limit dumping to this hard interface
296*4882a593Smuzhiyun  */
297*4882a593Smuzhiyun static void
batadv_v_neigh_dump(struct sk_buff * msg,struct netlink_callback * cb,struct batadv_priv * bat_priv,struct batadv_hard_iface * single_hardif)298*4882a593Smuzhiyun batadv_v_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb,
299*4882a593Smuzhiyun 		    struct batadv_priv *bat_priv,
300*4882a593Smuzhiyun 		    struct batadv_hard_iface *single_hardif)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	struct batadv_hard_iface *hard_iface;
303*4882a593Smuzhiyun 	int i_hardif = 0;
304*4882a593Smuzhiyun 	int i_hardif_s = cb->args[0];
305*4882a593Smuzhiyun 	int idx = cb->args[1];
306*4882a593Smuzhiyun 	int portid = NETLINK_CB(cb->skb).portid;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	rcu_read_lock();
309*4882a593Smuzhiyun 	if (single_hardif) {
310*4882a593Smuzhiyun 		if (i_hardif_s == 0) {
311*4882a593Smuzhiyun 			if (batadv_v_neigh_dump_hardif(msg, portid,
312*4882a593Smuzhiyun 						       cb->nlh->nlmsg_seq,
313*4882a593Smuzhiyun 						       bat_priv, single_hardif,
314*4882a593Smuzhiyun 						       &idx) == 0)
315*4882a593Smuzhiyun 				i_hardif++;
316*4882a593Smuzhiyun 		}
317*4882a593Smuzhiyun 	} else {
318*4882a593Smuzhiyun 		list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
319*4882a593Smuzhiyun 			if (hard_iface->soft_iface != bat_priv->soft_iface)
320*4882a593Smuzhiyun 				continue;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 			if (i_hardif++ < i_hardif_s)
323*4882a593Smuzhiyun 				continue;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 			if (batadv_v_neigh_dump_hardif(msg, portid,
326*4882a593Smuzhiyun 						       cb->nlh->nlmsg_seq,
327*4882a593Smuzhiyun 						       bat_priv, hard_iface,
328*4882a593Smuzhiyun 						       &idx)) {
329*4882a593Smuzhiyun 				i_hardif--;
330*4882a593Smuzhiyun 				break;
331*4882a593Smuzhiyun 			}
332*4882a593Smuzhiyun 		}
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 	rcu_read_unlock();
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	cb->args[0] = i_hardif;
337*4882a593Smuzhiyun 	cb->args[1] = idx;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_DEBUGFS
341*4882a593Smuzhiyun /**
342*4882a593Smuzhiyun  * batadv_v_orig_print() - print the originator table
343*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
344*4882a593Smuzhiyun  * @seq: debugfs table seq_file struct
345*4882a593Smuzhiyun  * @if_outgoing: the outgoing interface for which this should be printed
346*4882a593Smuzhiyun  */
batadv_v_orig_print(struct batadv_priv * bat_priv,struct seq_file * seq,struct batadv_hard_iface * if_outgoing)347*4882a593Smuzhiyun static void batadv_v_orig_print(struct batadv_priv *bat_priv,
348*4882a593Smuzhiyun 				struct seq_file *seq,
349*4882a593Smuzhiyun 				struct batadv_hard_iface *if_outgoing)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node;
352*4882a593Smuzhiyun 	struct batadv_hashtable *hash = bat_priv->orig_hash;
353*4882a593Smuzhiyun 	int last_seen_msecs, last_seen_secs;
354*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node;
355*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *n_ifinfo;
356*4882a593Smuzhiyun 	unsigned long last_seen_jiffies;
357*4882a593Smuzhiyun 	struct hlist_head *head;
358*4882a593Smuzhiyun 	int batman_count = 0;
359*4882a593Smuzhiyun 	u32 i;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	seq_puts(seq,
362*4882a593Smuzhiyun 		 "  Originator      last-seen ( throughput)           Nexthop [outgoingIF]:   Potential nexthops ...\n");
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	for (i = 0; i < hash->size; i++) {
365*4882a593Smuzhiyun 		head = &hash->table[i];
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 		rcu_read_lock();
368*4882a593Smuzhiyun 		hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
369*4882a593Smuzhiyun 			neigh_node = batadv_orig_router_get(orig_node,
370*4882a593Smuzhiyun 							    if_outgoing);
371*4882a593Smuzhiyun 			if (!neigh_node)
372*4882a593Smuzhiyun 				continue;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 			n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
375*4882a593Smuzhiyun 							   if_outgoing);
376*4882a593Smuzhiyun 			if (!n_ifinfo)
377*4882a593Smuzhiyun 				goto next;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 			last_seen_jiffies = jiffies - orig_node->last_seen;
380*4882a593Smuzhiyun 			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
381*4882a593Smuzhiyun 			last_seen_secs = last_seen_msecs / 1000;
382*4882a593Smuzhiyun 			last_seen_msecs = last_seen_msecs % 1000;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 			seq_printf(seq, "%pM %4i.%03is (%9u.%1u) %pM [%10s]:",
385*4882a593Smuzhiyun 				   orig_node->orig, last_seen_secs,
386*4882a593Smuzhiyun 				   last_seen_msecs,
387*4882a593Smuzhiyun 				   n_ifinfo->bat_v.throughput / 10,
388*4882a593Smuzhiyun 				   n_ifinfo->bat_v.throughput % 10,
389*4882a593Smuzhiyun 				   neigh_node->addr,
390*4882a593Smuzhiyun 				   neigh_node->if_incoming->net_dev->name);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 			batadv_v_orig_print_neigh(orig_node, if_outgoing, seq);
393*4882a593Smuzhiyun 			seq_putc(seq, '\n');
394*4882a593Smuzhiyun 			batman_count++;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun next:
397*4882a593Smuzhiyun 			batadv_neigh_node_put(neigh_node);
398*4882a593Smuzhiyun 			if (n_ifinfo)
399*4882a593Smuzhiyun 				batadv_neigh_ifinfo_put(n_ifinfo);
400*4882a593Smuzhiyun 		}
401*4882a593Smuzhiyun 		rcu_read_unlock();
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	if (batman_count == 0)
405*4882a593Smuzhiyun 		seq_puts(seq, "No batman nodes in range ...\n");
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun #endif
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun /**
410*4882a593Smuzhiyun  * batadv_v_orig_dump_subentry() - Dump an originator subentry into a message
411*4882a593Smuzhiyun  * @msg: Netlink message to dump into
412*4882a593Smuzhiyun  * @portid: Port making netlink request
413*4882a593Smuzhiyun  * @seq: Sequence number of netlink message
414*4882a593Smuzhiyun  * @bat_priv: The bat priv with all the soft interface information
415*4882a593Smuzhiyun  * @if_outgoing: Limit dump to entries with this outgoing interface
416*4882a593Smuzhiyun  * @orig_node: Originator to dump
417*4882a593Smuzhiyun  * @neigh_node: Single hops neighbour
418*4882a593Smuzhiyun  * @best: Is the best originator
419*4882a593Smuzhiyun  *
420*4882a593Smuzhiyun  * Return: Error code, or 0 on success
421*4882a593Smuzhiyun  */
422*4882a593Smuzhiyun static int
batadv_v_orig_dump_subentry(struct sk_buff * msg,u32 portid,u32 seq,struct batadv_priv * bat_priv,struct batadv_hard_iface * if_outgoing,struct batadv_orig_node * orig_node,struct batadv_neigh_node * neigh_node,bool best)423*4882a593Smuzhiyun batadv_v_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
424*4882a593Smuzhiyun 			    struct batadv_priv *bat_priv,
425*4882a593Smuzhiyun 			    struct batadv_hard_iface *if_outgoing,
426*4882a593Smuzhiyun 			    struct batadv_orig_node *orig_node,
427*4882a593Smuzhiyun 			    struct batadv_neigh_node *neigh_node,
428*4882a593Smuzhiyun 			    bool best)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *n_ifinfo;
431*4882a593Smuzhiyun 	unsigned int last_seen_msecs;
432*4882a593Smuzhiyun 	u32 throughput;
433*4882a593Smuzhiyun 	void *hdr;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
436*4882a593Smuzhiyun 	if (!n_ifinfo)
437*4882a593Smuzhiyun 		return 0;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	throughput = n_ifinfo->bat_v.throughput * 100;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	batadv_neigh_ifinfo_put(n_ifinfo);
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	if (if_outgoing != BATADV_IF_DEFAULT &&
446*4882a593Smuzhiyun 	    if_outgoing != neigh_node->if_incoming)
447*4882a593Smuzhiyun 		return 0;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
450*4882a593Smuzhiyun 			  BATADV_CMD_GET_ORIGINATORS);
451*4882a593Smuzhiyun 	if (!hdr)
452*4882a593Smuzhiyun 		return -ENOBUFS;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) ||
455*4882a593Smuzhiyun 	    nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
456*4882a593Smuzhiyun 		    neigh_node->addr) ||
457*4882a593Smuzhiyun 	    nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
458*4882a593Smuzhiyun 			neigh_node->if_incoming->net_dev->ifindex) ||
459*4882a593Smuzhiyun 	    nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput) ||
460*4882a593Smuzhiyun 	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
461*4882a593Smuzhiyun 			last_seen_msecs))
462*4882a593Smuzhiyun 		goto nla_put_failure;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
465*4882a593Smuzhiyun 		goto nla_put_failure;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	genlmsg_end(msg, hdr);
468*4882a593Smuzhiyun 	return 0;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun  nla_put_failure:
471*4882a593Smuzhiyun 	genlmsg_cancel(msg, hdr);
472*4882a593Smuzhiyun 	return -EMSGSIZE;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun /**
476*4882a593Smuzhiyun  * batadv_v_orig_dump_entry() - Dump an originator entry into a message
477*4882a593Smuzhiyun  * @msg: Netlink message to dump into
478*4882a593Smuzhiyun  * @portid: Port making netlink request
479*4882a593Smuzhiyun  * @seq: Sequence number of netlink message
480*4882a593Smuzhiyun  * @bat_priv: The bat priv with all the soft interface information
481*4882a593Smuzhiyun  * @if_outgoing: Limit dump to entries with this outgoing interface
482*4882a593Smuzhiyun  * @orig_node: Originator to dump
483*4882a593Smuzhiyun  * @sub_s: Number of sub entries to skip
484*4882a593Smuzhiyun  *
485*4882a593Smuzhiyun  * This function assumes the caller holds rcu_read_lock().
486*4882a593Smuzhiyun  *
487*4882a593Smuzhiyun  * Return: Error code, or 0 on success
488*4882a593Smuzhiyun  */
489*4882a593Smuzhiyun static int
batadv_v_orig_dump_entry(struct sk_buff * msg,u32 portid,u32 seq,struct batadv_priv * bat_priv,struct batadv_hard_iface * if_outgoing,struct batadv_orig_node * orig_node,int * sub_s)490*4882a593Smuzhiyun batadv_v_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
491*4882a593Smuzhiyun 			 struct batadv_priv *bat_priv,
492*4882a593Smuzhiyun 			 struct batadv_hard_iface *if_outgoing,
493*4882a593Smuzhiyun 			 struct batadv_orig_node *orig_node, int *sub_s)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node_best;
496*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node;
497*4882a593Smuzhiyun 	int sub = 0;
498*4882a593Smuzhiyun 	bool best;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing);
501*4882a593Smuzhiyun 	if (!neigh_node_best)
502*4882a593Smuzhiyun 		goto out;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
505*4882a593Smuzhiyun 		if (sub++ < *sub_s)
506*4882a593Smuzhiyun 			continue;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 		best = (neigh_node == neigh_node_best);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 		if (batadv_v_orig_dump_subentry(msg, portid, seq, bat_priv,
511*4882a593Smuzhiyun 						if_outgoing, orig_node,
512*4882a593Smuzhiyun 						neigh_node, best)) {
513*4882a593Smuzhiyun 			batadv_neigh_node_put(neigh_node_best);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 			*sub_s = sub - 1;
516*4882a593Smuzhiyun 			return -EMSGSIZE;
517*4882a593Smuzhiyun 		}
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun  out:
521*4882a593Smuzhiyun 	if (neigh_node_best)
522*4882a593Smuzhiyun 		batadv_neigh_node_put(neigh_node_best);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	*sub_s = 0;
525*4882a593Smuzhiyun 	return 0;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun /**
529*4882a593Smuzhiyun  * batadv_v_orig_dump_bucket() - Dump an originator bucket into a message
530*4882a593Smuzhiyun  * @msg: Netlink message to dump into
531*4882a593Smuzhiyun  * @portid: Port making netlink request
532*4882a593Smuzhiyun  * @seq: Sequence number of netlink message
533*4882a593Smuzhiyun  * @bat_priv: The bat priv with all the soft interface information
534*4882a593Smuzhiyun  * @if_outgoing: Limit dump to entries with this outgoing interface
535*4882a593Smuzhiyun  * @head: Bucket to be dumped
536*4882a593Smuzhiyun  * @idx_s: Number of entries to be skipped
537*4882a593Smuzhiyun  * @sub: Number of sub entries to be skipped
538*4882a593Smuzhiyun  *
539*4882a593Smuzhiyun  * Return: Error code, or 0 on success
540*4882a593Smuzhiyun  */
541*4882a593Smuzhiyun static int
batadv_v_orig_dump_bucket(struct sk_buff * msg,u32 portid,u32 seq,struct batadv_priv * bat_priv,struct batadv_hard_iface * if_outgoing,struct hlist_head * head,int * idx_s,int * sub)542*4882a593Smuzhiyun batadv_v_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
543*4882a593Smuzhiyun 			  struct batadv_priv *bat_priv,
544*4882a593Smuzhiyun 			  struct batadv_hard_iface *if_outgoing,
545*4882a593Smuzhiyun 			  struct hlist_head *head, int *idx_s, int *sub)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node;
548*4882a593Smuzhiyun 	int idx = 0;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	rcu_read_lock();
551*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
552*4882a593Smuzhiyun 		if (idx++ < *idx_s)
553*4882a593Smuzhiyun 			continue;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 		if (batadv_v_orig_dump_entry(msg, portid, seq, bat_priv,
556*4882a593Smuzhiyun 					     if_outgoing, orig_node, sub)) {
557*4882a593Smuzhiyun 			rcu_read_unlock();
558*4882a593Smuzhiyun 			*idx_s = idx - 1;
559*4882a593Smuzhiyun 			return -EMSGSIZE;
560*4882a593Smuzhiyun 		}
561*4882a593Smuzhiyun 	}
562*4882a593Smuzhiyun 	rcu_read_unlock();
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	*idx_s = 0;
565*4882a593Smuzhiyun 	*sub = 0;
566*4882a593Smuzhiyun 	return 0;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun /**
570*4882a593Smuzhiyun  * batadv_v_orig_dump() - Dump the originators into a message
571*4882a593Smuzhiyun  * @msg: Netlink message to dump into
572*4882a593Smuzhiyun  * @cb: Control block containing additional options
573*4882a593Smuzhiyun  * @bat_priv: The bat priv with all the soft interface information
574*4882a593Smuzhiyun  * @if_outgoing: Limit dump to entries with this outgoing interface
575*4882a593Smuzhiyun  */
576*4882a593Smuzhiyun static void
batadv_v_orig_dump(struct sk_buff * msg,struct netlink_callback * cb,struct batadv_priv * bat_priv,struct batadv_hard_iface * if_outgoing)577*4882a593Smuzhiyun batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb,
578*4882a593Smuzhiyun 		   struct batadv_priv *bat_priv,
579*4882a593Smuzhiyun 		   struct batadv_hard_iface *if_outgoing)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun 	struct batadv_hashtable *hash = bat_priv->orig_hash;
582*4882a593Smuzhiyun 	struct hlist_head *head;
583*4882a593Smuzhiyun 	int bucket = cb->args[0];
584*4882a593Smuzhiyun 	int idx = cb->args[1];
585*4882a593Smuzhiyun 	int sub = cb->args[2];
586*4882a593Smuzhiyun 	int portid = NETLINK_CB(cb->skb).portid;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	while (bucket < hash->size) {
589*4882a593Smuzhiyun 		head = &hash->table[bucket];
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 		if (batadv_v_orig_dump_bucket(msg, portid,
592*4882a593Smuzhiyun 					      cb->nlh->nlmsg_seq,
593*4882a593Smuzhiyun 					      bat_priv, if_outgoing, head, &idx,
594*4882a593Smuzhiyun 					      &sub))
595*4882a593Smuzhiyun 			break;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 		bucket++;
598*4882a593Smuzhiyun 	}
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	cb->args[0] = bucket;
601*4882a593Smuzhiyun 	cb->args[1] = idx;
602*4882a593Smuzhiyun 	cb->args[2] = sub;
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun 
batadv_v_neigh_cmp(struct batadv_neigh_node * neigh1,struct batadv_hard_iface * if_outgoing1,struct batadv_neigh_node * neigh2,struct batadv_hard_iface * if_outgoing2)605*4882a593Smuzhiyun static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
606*4882a593Smuzhiyun 			      struct batadv_hard_iface *if_outgoing1,
607*4882a593Smuzhiyun 			      struct batadv_neigh_node *neigh2,
608*4882a593Smuzhiyun 			      struct batadv_hard_iface *if_outgoing2)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
611*4882a593Smuzhiyun 	int ret = 0;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
614*4882a593Smuzhiyun 	if (!ifinfo1)
615*4882a593Smuzhiyun 		goto err_ifinfo1;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
618*4882a593Smuzhiyun 	if (!ifinfo2)
619*4882a593Smuzhiyun 		goto err_ifinfo2;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	batadv_neigh_ifinfo_put(ifinfo2);
624*4882a593Smuzhiyun err_ifinfo2:
625*4882a593Smuzhiyun 	batadv_neigh_ifinfo_put(ifinfo1);
626*4882a593Smuzhiyun err_ifinfo1:
627*4882a593Smuzhiyun 	return ret;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
batadv_v_neigh_is_sob(struct batadv_neigh_node * neigh1,struct batadv_hard_iface * if_outgoing1,struct batadv_neigh_node * neigh2,struct batadv_hard_iface * if_outgoing2)630*4882a593Smuzhiyun static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
631*4882a593Smuzhiyun 				  struct batadv_hard_iface *if_outgoing1,
632*4882a593Smuzhiyun 				  struct batadv_neigh_node *neigh2,
633*4882a593Smuzhiyun 				  struct batadv_hard_iface *if_outgoing2)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
636*4882a593Smuzhiyun 	u32 threshold;
637*4882a593Smuzhiyun 	bool ret = false;
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
640*4882a593Smuzhiyun 	if (!ifinfo1)
641*4882a593Smuzhiyun 		goto err_ifinfo1;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
644*4882a593Smuzhiyun 	if (!ifinfo2)
645*4882a593Smuzhiyun 		goto err_ifinfo2;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	threshold = ifinfo1->bat_v.throughput / 4;
648*4882a593Smuzhiyun 	threshold = ifinfo1->bat_v.throughput - threshold;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	ret = ifinfo2->bat_v.throughput > threshold;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	batadv_neigh_ifinfo_put(ifinfo2);
653*4882a593Smuzhiyun err_ifinfo2:
654*4882a593Smuzhiyun 	batadv_neigh_ifinfo_put(ifinfo1);
655*4882a593Smuzhiyun err_ifinfo1:
656*4882a593Smuzhiyun 	return ret;
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun /**
660*4882a593Smuzhiyun  * batadv_v_init_sel_class() - initialize GW selection class
661*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
662*4882a593Smuzhiyun  */
batadv_v_init_sel_class(struct batadv_priv * bat_priv)663*4882a593Smuzhiyun static void batadv_v_init_sel_class(struct batadv_priv *bat_priv)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	/* set default throughput difference threshold to 5Mbps */
666*4882a593Smuzhiyun 	atomic_set(&bat_priv->gw.sel_class, 50);
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
batadv_v_store_sel_class(struct batadv_priv * bat_priv,char * buff,size_t count)669*4882a593Smuzhiyun static ssize_t batadv_v_store_sel_class(struct batadv_priv *bat_priv,
670*4882a593Smuzhiyun 					char *buff, size_t count)
671*4882a593Smuzhiyun {
672*4882a593Smuzhiyun 	u32 old_class, class;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	if (!batadv_parse_throughput(bat_priv->soft_iface, buff,
675*4882a593Smuzhiyun 				     "B.A.T.M.A.N. V GW selection class",
676*4882a593Smuzhiyun 				     &class))
677*4882a593Smuzhiyun 		return -EINVAL;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	old_class = atomic_read(&bat_priv->gw.sel_class);
680*4882a593Smuzhiyun 	atomic_set(&bat_priv->gw.sel_class, class);
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	if (old_class != class)
683*4882a593Smuzhiyun 		batadv_gw_reselect(bat_priv);
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	return count;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun 
batadv_v_show_sel_class(struct batadv_priv * bat_priv,char * buff)688*4882a593Smuzhiyun static ssize_t batadv_v_show_sel_class(struct batadv_priv *bat_priv, char *buff)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun 	u32 class = atomic_read(&bat_priv->gw.sel_class);
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	return sprintf(buff, "%u.%u MBit\n", class / 10, class % 10);
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun /**
696*4882a593Smuzhiyun  * batadv_v_gw_throughput_get() - retrieve the GW-bandwidth for a given GW
697*4882a593Smuzhiyun  * @gw_node: the GW to retrieve the metric for
698*4882a593Smuzhiyun  * @bw: the pointer where the metric will be stored. The metric is computed as
699*4882a593Smuzhiyun  *  the minimum between the GW advertised throughput and the path throughput to
700*4882a593Smuzhiyun  *  it in the mesh
701*4882a593Smuzhiyun  *
702*4882a593Smuzhiyun  * Return: 0 on success, -1 on failure
703*4882a593Smuzhiyun  */
batadv_v_gw_throughput_get(struct batadv_gw_node * gw_node,u32 * bw)704*4882a593Smuzhiyun static int batadv_v_gw_throughput_get(struct batadv_gw_node *gw_node, u32 *bw)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
707*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node;
708*4882a593Smuzhiyun 	struct batadv_neigh_node *router;
709*4882a593Smuzhiyun 	int ret = -1;
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	orig_node = gw_node->orig_node;
712*4882a593Smuzhiyun 	router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
713*4882a593Smuzhiyun 	if (!router)
714*4882a593Smuzhiyun 		goto out;
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
717*4882a593Smuzhiyun 	if (!router_ifinfo)
718*4882a593Smuzhiyun 		goto out;
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	/* the GW metric is computed as the minimum between the path throughput
721*4882a593Smuzhiyun 	 * to reach the GW itself and the advertised bandwidth.
722*4882a593Smuzhiyun 	 * This gives us an approximation of the effective throughput that the
723*4882a593Smuzhiyun 	 * client can expect via this particular GW node
724*4882a593Smuzhiyun 	 */
725*4882a593Smuzhiyun 	*bw = router_ifinfo->bat_v.throughput;
726*4882a593Smuzhiyun 	*bw = min_t(u32, *bw, gw_node->bandwidth_down);
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	ret = 0;
729*4882a593Smuzhiyun out:
730*4882a593Smuzhiyun 	if (router)
731*4882a593Smuzhiyun 		batadv_neigh_node_put(router);
732*4882a593Smuzhiyun 	if (router_ifinfo)
733*4882a593Smuzhiyun 		batadv_neigh_ifinfo_put(router_ifinfo);
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	return ret;
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun /**
739*4882a593Smuzhiyun  * batadv_v_gw_get_best_gw_node() - retrieve the best GW node
740*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
741*4882a593Smuzhiyun  *
742*4882a593Smuzhiyun  * Return: the GW node having the best GW-metric, NULL if no GW is known
743*4882a593Smuzhiyun  */
744*4882a593Smuzhiyun static struct batadv_gw_node *
batadv_v_gw_get_best_gw_node(struct batadv_priv * bat_priv)745*4882a593Smuzhiyun batadv_v_gw_get_best_gw_node(struct batadv_priv *bat_priv)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun 	struct batadv_gw_node *gw_node, *curr_gw = NULL;
748*4882a593Smuzhiyun 	u32 max_bw = 0, bw;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	rcu_read_lock();
751*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
752*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&gw_node->refcount))
753*4882a593Smuzhiyun 			continue;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 		if (batadv_v_gw_throughput_get(gw_node, &bw) < 0)
756*4882a593Smuzhiyun 			goto next;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 		if (curr_gw && bw <= max_bw)
759*4882a593Smuzhiyun 			goto next;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 		if (curr_gw)
762*4882a593Smuzhiyun 			batadv_gw_node_put(curr_gw);
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 		curr_gw = gw_node;
765*4882a593Smuzhiyun 		kref_get(&curr_gw->refcount);
766*4882a593Smuzhiyun 		max_bw = bw;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun next:
769*4882a593Smuzhiyun 		batadv_gw_node_put(gw_node);
770*4882a593Smuzhiyun 	}
771*4882a593Smuzhiyun 	rcu_read_unlock();
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	return curr_gw;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun /**
777*4882a593Smuzhiyun  * batadv_v_gw_is_eligible() - check if a originator would be selected as GW
778*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
779*4882a593Smuzhiyun  * @curr_gw_orig: originator representing the currently selected GW
780*4882a593Smuzhiyun  * @orig_node: the originator representing the new candidate
781*4882a593Smuzhiyun  *
782*4882a593Smuzhiyun  * Return: true if orig_node can be selected as current GW, false otherwise
783*4882a593Smuzhiyun  */
batadv_v_gw_is_eligible(struct batadv_priv * bat_priv,struct batadv_orig_node * curr_gw_orig,struct batadv_orig_node * orig_node)784*4882a593Smuzhiyun static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv,
785*4882a593Smuzhiyun 				    struct batadv_orig_node *curr_gw_orig,
786*4882a593Smuzhiyun 				    struct batadv_orig_node *orig_node)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun 	struct batadv_gw_node *curr_gw, *orig_gw = NULL;
789*4882a593Smuzhiyun 	u32 gw_throughput, orig_throughput, threshold;
790*4882a593Smuzhiyun 	bool ret = false;
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	threshold = atomic_read(&bat_priv->gw.sel_class);
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig);
795*4882a593Smuzhiyun 	if (!curr_gw) {
796*4882a593Smuzhiyun 		ret = true;
797*4882a593Smuzhiyun 		goto out;
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	if (batadv_v_gw_throughput_get(curr_gw, &gw_throughput) < 0) {
801*4882a593Smuzhiyun 		ret = true;
802*4882a593Smuzhiyun 		goto out;
803*4882a593Smuzhiyun 	}
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	orig_gw = batadv_gw_node_get(bat_priv, orig_node);
806*4882a593Smuzhiyun 	if (!orig_gw)
807*4882a593Smuzhiyun 		goto out;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	if (batadv_v_gw_throughput_get(orig_gw, &orig_throughput) < 0)
810*4882a593Smuzhiyun 		goto out;
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	if (orig_throughput < gw_throughput)
813*4882a593Smuzhiyun 		goto out;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	if ((orig_throughput - gw_throughput) < threshold)
816*4882a593Smuzhiyun 		goto out;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
819*4882a593Smuzhiyun 		   "Restarting gateway selection: better gateway found (throughput curr: %u, throughput new: %u)\n",
820*4882a593Smuzhiyun 		   gw_throughput, orig_throughput);
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	ret = true;
823*4882a593Smuzhiyun out:
824*4882a593Smuzhiyun 	if (curr_gw)
825*4882a593Smuzhiyun 		batadv_gw_node_put(curr_gw);
826*4882a593Smuzhiyun 	if (orig_gw)
827*4882a593Smuzhiyun 		batadv_gw_node_put(orig_gw);
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	return ret;
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_DEBUGFS
833*4882a593Smuzhiyun /* fails if orig_node has no router */
batadv_v_gw_write_buffer_text(struct batadv_priv * bat_priv,struct seq_file * seq,const struct batadv_gw_node * gw_node)834*4882a593Smuzhiyun static int batadv_v_gw_write_buffer_text(struct batadv_priv *bat_priv,
835*4882a593Smuzhiyun 					 struct seq_file *seq,
836*4882a593Smuzhiyun 					 const struct batadv_gw_node *gw_node)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun 	struct batadv_gw_node *curr_gw;
839*4882a593Smuzhiyun 	struct batadv_neigh_node *router;
840*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
841*4882a593Smuzhiyun 	int ret = -1;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
844*4882a593Smuzhiyun 	if (!router)
845*4882a593Smuzhiyun 		goto out;
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
848*4882a593Smuzhiyun 	if (!router_ifinfo)
849*4882a593Smuzhiyun 		goto out;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	seq_printf(seq, "%s %pM (%9u.%1u) %pM [%10s]: %u.%u/%u.%u MBit\n",
854*4882a593Smuzhiyun 		   (curr_gw == gw_node ? "=>" : "  "),
855*4882a593Smuzhiyun 		   gw_node->orig_node->orig,
856*4882a593Smuzhiyun 		   router_ifinfo->bat_v.throughput / 10,
857*4882a593Smuzhiyun 		   router_ifinfo->bat_v.throughput % 10, router->addr,
858*4882a593Smuzhiyun 		   router->if_incoming->net_dev->name,
859*4882a593Smuzhiyun 		   gw_node->bandwidth_down / 10,
860*4882a593Smuzhiyun 		   gw_node->bandwidth_down % 10,
861*4882a593Smuzhiyun 		   gw_node->bandwidth_up / 10,
862*4882a593Smuzhiyun 		   gw_node->bandwidth_up % 10);
863*4882a593Smuzhiyun 	ret = seq_has_overflowed(seq) ? -1 : 0;
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	if (curr_gw)
866*4882a593Smuzhiyun 		batadv_gw_node_put(curr_gw);
867*4882a593Smuzhiyun out:
868*4882a593Smuzhiyun 	if (router_ifinfo)
869*4882a593Smuzhiyun 		batadv_neigh_ifinfo_put(router_ifinfo);
870*4882a593Smuzhiyun 	if (router)
871*4882a593Smuzhiyun 		batadv_neigh_node_put(router);
872*4882a593Smuzhiyun 	return ret;
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun /**
876*4882a593Smuzhiyun  * batadv_v_gw_print() - print the gateway list
877*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
878*4882a593Smuzhiyun  * @seq: gateway table seq_file struct
879*4882a593Smuzhiyun  */
batadv_v_gw_print(struct batadv_priv * bat_priv,struct seq_file * seq)880*4882a593Smuzhiyun static void batadv_v_gw_print(struct batadv_priv *bat_priv,
881*4882a593Smuzhiyun 			      struct seq_file *seq)
882*4882a593Smuzhiyun {
883*4882a593Smuzhiyun 	struct batadv_gw_node *gw_node;
884*4882a593Smuzhiyun 	int gw_count = 0;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	seq_puts(seq,
887*4882a593Smuzhiyun 		 "      Gateway        ( throughput)           Nexthop [outgoingIF]: advertised uplink bandwidth\n");
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	rcu_read_lock();
890*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
891*4882a593Smuzhiyun 		/* fails if orig_node has no router */
892*4882a593Smuzhiyun 		if (batadv_v_gw_write_buffer_text(bat_priv, seq, gw_node) < 0)
893*4882a593Smuzhiyun 			continue;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 		gw_count++;
896*4882a593Smuzhiyun 	}
897*4882a593Smuzhiyun 	rcu_read_unlock();
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	if (gw_count == 0)
900*4882a593Smuzhiyun 		seq_puts(seq, "No gateways in range ...\n");
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun #endif
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun /**
905*4882a593Smuzhiyun  * batadv_v_gw_dump_entry() - Dump a gateway into a message
906*4882a593Smuzhiyun  * @msg: Netlink message to dump into
907*4882a593Smuzhiyun  * @portid: Port making netlink request
908*4882a593Smuzhiyun  * @cb: Control block containing additional options
909*4882a593Smuzhiyun  * @bat_priv: The bat priv with all the soft interface information
910*4882a593Smuzhiyun  * @gw_node: Gateway to be dumped
911*4882a593Smuzhiyun  *
912*4882a593Smuzhiyun  * Return: Error code, or 0 on success
913*4882a593Smuzhiyun  */
batadv_v_gw_dump_entry(struct sk_buff * msg,u32 portid,struct netlink_callback * cb,struct batadv_priv * bat_priv,struct batadv_gw_node * gw_node)914*4882a593Smuzhiyun static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid,
915*4882a593Smuzhiyun 				  struct netlink_callback *cb,
916*4882a593Smuzhiyun 				  struct batadv_priv *bat_priv,
917*4882a593Smuzhiyun 				  struct batadv_gw_node *gw_node)
918*4882a593Smuzhiyun {
919*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *router_ifinfo = NULL;
920*4882a593Smuzhiyun 	struct batadv_neigh_node *router;
921*4882a593Smuzhiyun 	struct batadv_gw_node *curr_gw = NULL;
922*4882a593Smuzhiyun 	int ret = 0;
923*4882a593Smuzhiyun 	void *hdr;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
926*4882a593Smuzhiyun 	if (!router)
927*4882a593Smuzhiyun 		goto out;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
930*4882a593Smuzhiyun 	if (!router_ifinfo)
931*4882a593Smuzhiyun 		goto out;
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
936*4882a593Smuzhiyun 			  &batadv_netlink_family, NLM_F_MULTI,
937*4882a593Smuzhiyun 			  BATADV_CMD_GET_GATEWAYS);
938*4882a593Smuzhiyun 	if (!hdr) {
939*4882a593Smuzhiyun 		ret = -ENOBUFS;
940*4882a593Smuzhiyun 		goto out;
941*4882a593Smuzhiyun 	}
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	genl_dump_check_consistent(cb, hdr);
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	ret = -EMSGSIZE;
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	if (curr_gw == gw_node) {
948*4882a593Smuzhiyun 		if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) {
949*4882a593Smuzhiyun 			genlmsg_cancel(msg, hdr);
950*4882a593Smuzhiyun 			goto out;
951*4882a593Smuzhiyun 		}
952*4882a593Smuzhiyun 	}
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
955*4882a593Smuzhiyun 		    gw_node->orig_node->orig)) {
956*4882a593Smuzhiyun 		genlmsg_cancel(msg, hdr);
957*4882a593Smuzhiyun 		goto out;
958*4882a593Smuzhiyun 	}
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT,
961*4882a593Smuzhiyun 			router_ifinfo->bat_v.throughput)) {
962*4882a593Smuzhiyun 		genlmsg_cancel(msg, hdr);
963*4882a593Smuzhiyun 		goto out;
964*4882a593Smuzhiyun 	}
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	if (nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN, router->addr)) {
967*4882a593Smuzhiyun 		genlmsg_cancel(msg, hdr);
968*4882a593Smuzhiyun 		goto out;
969*4882a593Smuzhiyun 	}
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	if (nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
972*4882a593Smuzhiyun 			   router->if_incoming->net_dev->name)) {
973*4882a593Smuzhiyun 		genlmsg_cancel(msg, hdr);
974*4882a593Smuzhiyun 		goto out;
975*4882a593Smuzhiyun 	}
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 	if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
978*4882a593Smuzhiyun 			gw_node->bandwidth_down)) {
979*4882a593Smuzhiyun 		genlmsg_cancel(msg, hdr);
980*4882a593Smuzhiyun 		goto out;
981*4882a593Smuzhiyun 	}
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP, gw_node->bandwidth_up)) {
984*4882a593Smuzhiyun 		genlmsg_cancel(msg, hdr);
985*4882a593Smuzhiyun 		goto out;
986*4882a593Smuzhiyun 	}
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	genlmsg_end(msg, hdr);
989*4882a593Smuzhiyun 	ret = 0;
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun out:
992*4882a593Smuzhiyun 	if (curr_gw)
993*4882a593Smuzhiyun 		batadv_gw_node_put(curr_gw);
994*4882a593Smuzhiyun 	if (router_ifinfo)
995*4882a593Smuzhiyun 		batadv_neigh_ifinfo_put(router_ifinfo);
996*4882a593Smuzhiyun 	if (router)
997*4882a593Smuzhiyun 		batadv_neigh_node_put(router);
998*4882a593Smuzhiyun 	return ret;
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun /**
1002*4882a593Smuzhiyun  * batadv_v_gw_dump() - Dump gateways into a message
1003*4882a593Smuzhiyun  * @msg: Netlink message to dump into
1004*4882a593Smuzhiyun  * @cb: Control block containing additional options
1005*4882a593Smuzhiyun  * @bat_priv: The bat priv with all the soft interface information
1006*4882a593Smuzhiyun  */
batadv_v_gw_dump(struct sk_buff * msg,struct netlink_callback * cb,struct batadv_priv * bat_priv)1007*4882a593Smuzhiyun static void batadv_v_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
1008*4882a593Smuzhiyun 			     struct batadv_priv *bat_priv)
1009*4882a593Smuzhiyun {
1010*4882a593Smuzhiyun 	int portid = NETLINK_CB(cb->skb).portid;
1011*4882a593Smuzhiyun 	struct batadv_gw_node *gw_node;
1012*4882a593Smuzhiyun 	int idx_skip = cb->args[0];
1013*4882a593Smuzhiyun 	int idx = 0;
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	spin_lock_bh(&bat_priv->gw.list_lock);
1016*4882a593Smuzhiyun 	cb->seq = bat_priv->gw.generation << 1 | 1;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	hlist_for_each_entry(gw_node, &bat_priv->gw.gateway_list, list) {
1019*4882a593Smuzhiyun 		if (idx++ < idx_skip)
1020*4882a593Smuzhiyun 			continue;
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 		if (batadv_v_gw_dump_entry(msg, portid, cb, bat_priv,
1023*4882a593Smuzhiyun 					   gw_node)) {
1024*4882a593Smuzhiyun 			idx_skip = idx - 1;
1025*4882a593Smuzhiyun 			goto unlock;
1026*4882a593Smuzhiyun 		}
1027*4882a593Smuzhiyun 	}
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 	idx_skip = idx;
1030*4882a593Smuzhiyun unlock:
1031*4882a593Smuzhiyun 	spin_unlock_bh(&bat_priv->gw.list_lock);
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	cb->args[0] = idx_skip;
1034*4882a593Smuzhiyun }
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun static struct batadv_algo_ops batadv_batman_v __read_mostly = {
1037*4882a593Smuzhiyun 	.name = "BATMAN_V",
1038*4882a593Smuzhiyun 	.iface = {
1039*4882a593Smuzhiyun 		.activate = batadv_v_iface_activate,
1040*4882a593Smuzhiyun 		.enable = batadv_v_iface_enable,
1041*4882a593Smuzhiyun 		.disable = batadv_v_iface_disable,
1042*4882a593Smuzhiyun 		.update_mac = batadv_v_iface_update_mac,
1043*4882a593Smuzhiyun 		.primary_set = batadv_v_primary_iface_set,
1044*4882a593Smuzhiyun 	},
1045*4882a593Smuzhiyun 	.neigh = {
1046*4882a593Smuzhiyun 		.hardif_init = batadv_v_hardif_neigh_init,
1047*4882a593Smuzhiyun 		.cmp = batadv_v_neigh_cmp,
1048*4882a593Smuzhiyun 		.is_similar_or_better = batadv_v_neigh_is_sob,
1049*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_DEBUGFS
1050*4882a593Smuzhiyun 		.print = batadv_v_neigh_print,
1051*4882a593Smuzhiyun #endif
1052*4882a593Smuzhiyun 		.dump = batadv_v_neigh_dump,
1053*4882a593Smuzhiyun 	},
1054*4882a593Smuzhiyun 	.orig = {
1055*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_DEBUGFS
1056*4882a593Smuzhiyun 		.print = batadv_v_orig_print,
1057*4882a593Smuzhiyun #endif
1058*4882a593Smuzhiyun 		.dump = batadv_v_orig_dump,
1059*4882a593Smuzhiyun 	},
1060*4882a593Smuzhiyun 	.gw = {
1061*4882a593Smuzhiyun 		.init_sel_class = batadv_v_init_sel_class,
1062*4882a593Smuzhiyun 		.store_sel_class = batadv_v_store_sel_class,
1063*4882a593Smuzhiyun 		.show_sel_class = batadv_v_show_sel_class,
1064*4882a593Smuzhiyun 		.get_best_gw_node = batadv_v_gw_get_best_gw_node,
1065*4882a593Smuzhiyun 		.is_eligible = batadv_v_gw_is_eligible,
1066*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_DEBUGFS
1067*4882a593Smuzhiyun 		.print = batadv_v_gw_print,
1068*4882a593Smuzhiyun #endif
1069*4882a593Smuzhiyun 		.dump = batadv_v_gw_dump,
1070*4882a593Smuzhiyun 	},
1071*4882a593Smuzhiyun };
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun /**
1074*4882a593Smuzhiyun  * batadv_v_hardif_init() - initialize the algorithm specific fields in the
1075*4882a593Smuzhiyun  *  hard-interface object
1076*4882a593Smuzhiyun  * @hard_iface: the hard-interface to initialize
1077*4882a593Smuzhiyun  */
batadv_v_hardif_init(struct batadv_hard_iface * hard_iface)1078*4882a593Smuzhiyun void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface)
1079*4882a593Smuzhiyun {
1080*4882a593Smuzhiyun 	/* enable link throughput auto-detection by setting the throughput
1081*4882a593Smuzhiyun 	 * override to zero
1082*4882a593Smuzhiyun 	 */
1083*4882a593Smuzhiyun 	atomic_set(&hard_iface->bat_v.throughput_override, 0);
1084*4882a593Smuzhiyun 	atomic_set(&hard_iface->bat_v.elp_interval, 500);
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	hard_iface->bat_v.aggr_len = 0;
1087*4882a593Smuzhiyun 	skb_queue_head_init(&hard_iface->bat_v.aggr_list);
1088*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&hard_iface->bat_v.aggr_wq,
1089*4882a593Smuzhiyun 			  batadv_v_ogm_aggr_work);
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun /**
1093*4882a593Smuzhiyun  * batadv_v_mesh_init() - initialize the B.A.T.M.A.N. V private resources for a
1094*4882a593Smuzhiyun  *  mesh
1095*4882a593Smuzhiyun  * @bat_priv: the object representing the mesh interface to initialise
1096*4882a593Smuzhiyun  *
1097*4882a593Smuzhiyun  * Return: 0 on success or a negative error code otherwise
1098*4882a593Smuzhiyun  */
batadv_v_mesh_init(struct batadv_priv * bat_priv)1099*4882a593Smuzhiyun int batadv_v_mesh_init(struct batadv_priv *bat_priv)
1100*4882a593Smuzhiyun {
1101*4882a593Smuzhiyun 	int ret = 0;
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun 	ret = batadv_v_ogm_init(bat_priv);
1104*4882a593Smuzhiyun 	if (ret < 0)
1105*4882a593Smuzhiyun 		return ret;
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	return 0;
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun /**
1111*4882a593Smuzhiyun  * batadv_v_mesh_free() - free the B.A.T.M.A.N. V private resources for a mesh
1112*4882a593Smuzhiyun  * @bat_priv: the object representing the mesh interface to free
1113*4882a593Smuzhiyun  */
batadv_v_mesh_free(struct batadv_priv * bat_priv)1114*4882a593Smuzhiyun void batadv_v_mesh_free(struct batadv_priv *bat_priv)
1115*4882a593Smuzhiyun {
1116*4882a593Smuzhiyun 	batadv_v_ogm_free(bat_priv);
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun /**
1120*4882a593Smuzhiyun  * batadv_v_init() - B.A.T.M.A.N. V initialization function
1121*4882a593Smuzhiyun  *
1122*4882a593Smuzhiyun  * Description: Takes care of initializing all the subcomponents.
1123*4882a593Smuzhiyun  * It is invoked upon module load only.
1124*4882a593Smuzhiyun  *
1125*4882a593Smuzhiyun  * Return: 0 on success or a negative error code otherwise
1126*4882a593Smuzhiyun  */
batadv_v_init(void)1127*4882a593Smuzhiyun int __init batadv_v_init(void)
1128*4882a593Smuzhiyun {
1129*4882a593Smuzhiyun 	int ret;
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 	/* B.A.T.M.A.N. V echo location protocol packet  */
1132*4882a593Smuzhiyun 	ret = batadv_recv_handler_register(BATADV_ELP,
1133*4882a593Smuzhiyun 					   batadv_v_elp_packet_recv);
1134*4882a593Smuzhiyun 	if (ret < 0)
1135*4882a593Smuzhiyun 		return ret;
1136*4882a593Smuzhiyun 
1137*4882a593Smuzhiyun 	ret = batadv_recv_handler_register(BATADV_OGM2,
1138*4882a593Smuzhiyun 					   batadv_v_ogm_packet_recv);
1139*4882a593Smuzhiyun 	if (ret < 0)
1140*4882a593Smuzhiyun 		goto elp_unregister;
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	ret = batadv_algo_register(&batadv_batman_v);
1143*4882a593Smuzhiyun 	if (ret < 0)
1144*4882a593Smuzhiyun 		goto ogm_unregister;
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 	return ret;
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun ogm_unregister:
1149*4882a593Smuzhiyun 	batadv_recv_handler_unregister(BATADV_OGM2);
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun elp_unregister:
1152*4882a593Smuzhiyun 	batadv_recv_handler_unregister(BATADV_ELP);
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 	return ret;
1155*4882a593Smuzhiyun }
1156