xref: /OK3568_Linux_fs/kernel/net/batman-adv/originator.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (C) 2009-2020  B.A.T.M.A.N. contributors:
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Marek Lindner, Simon Wunderlich
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include "originator.h"
8*4882a593Smuzhiyun #include "main.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/atomic.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/etherdevice.h>
13*4882a593Smuzhiyun #include <linux/gfp.h>
14*4882a593Smuzhiyun #include <linux/jiffies.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/kref.h>
17*4882a593Smuzhiyun #include <linux/list.h>
18*4882a593Smuzhiyun #include <linux/lockdep.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/slab.h>
26*4882a593Smuzhiyun #include <linux/spinlock.h>
27*4882a593Smuzhiyun #include <linux/stddef.h>
28*4882a593Smuzhiyun #include <linux/workqueue.h>
29*4882a593Smuzhiyun #include <net/sock.h>
30*4882a593Smuzhiyun #include <uapi/linux/batadv_packet.h>
31*4882a593Smuzhiyun #include <uapi/linux/batman_adv.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include "bat_algo.h"
34*4882a593Smuzhiyun #include "distributed-arp-table.h"
35*4882a593Smuzhiyun #include "fragmentation.h"
36*4882a593Smuzhiyun #include "gateway_client.h"
37*4882a593Smuzhiyun #include "hard-interface.h"
38*4882a593Smuzhiyun #include "hash.h"
39*4882a593Smuzhiyun #include "log.h"
40*4882a593Smuzhiyun #include "multicast.h"
41*4882a593Smuzhiyun #include "netlink.h"
42*4882a593Smuzhiyun #include "network-coding.h"
43*4882a593Smuzhiyun #include "routing.h"
44*4882a593Smuzhiyun #include "soft-interface.h"
45*4882a593Smuzhiyun #include "translation-table.h"
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /* hash class keys */
48*4882a593Smuzhiyun static struct lock_class_key batadv_orig_hash_lock_class_key;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /**
51*4882a593Smuzhiyun  * batadv_orig_hash_find() - Find and return originator from orig_hash
52*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
53*4882a593Smuzhiyun  * @data: mac address of the originator
54*4882a593Smuzhiyun  *
55*4882a593Smuzhiyun  * Return: orig_node (with increased refcnt), NULL on errors
56*4882a593Smuzhiyun  */
57*4882a593Smuzhiyun struct batadv_orig_node *
batadv_orig_hash_find(struct batadv_priv * bat_priv,const void * data)58*4882a593Smuzhiyun batadv_orig_hash_find(struct batadv_priv *bat_priv, const void *data)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	struct batadv_hashtable *hash = bat_priv->orig_hash;
61*4882a593Smuzhiyun 	struct hlist_head *head;
62*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node, *orig_node_tmp = NULL;
63*4882a593Smuzhiyun 	int index;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	if (!hash)
66*4882a593Smuzhiyun 		return NULL;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	index = batadv_choose_orig(data, hash->size);
69*4882a593Smuzhiyun 	head = &hash->table[index];
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	rcu_read_lock();
72*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
73*4882a593Smuzhiyun 		if (!batadv_compare_eth(orig_node, data))
74*4882a593Smuzhiyun 			continue;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&orig_node->refcount))
77*4882a593Smuzhiyun 			continue;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		orig_node_tmp = orig_node;
80*4882a593Smuzhiyun 		break;
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun 	rcu_read_unlock();
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	return orig_node_tmp;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun static void batadv_purge_orig(struct work_struct *work);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun /**
90*4882a593Smuzhiyun  * batadv_compare_orig() - comparing function used in the originator hash table
91*4882a593Smuzhiyun  * @node: node in the local table
92*4882a593Smuzhiyun  * @data2: second object to compare the node to
93*4882a593Smuzhiyun  *
94*4882a593Smuzhiyun  * Return: true if they are the same originator
95*4882a593Smuzhiyun  */
batadv_compare_orig(const struct hlist_node * node,const void * data2)96*4882a593Smuzhiyun bool batadv_compare_orig(const struct hlist_node *node, const void *data2)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	const void *data1 = container_of(node, struct batadv_orig_node,
99*4882a593Smuzhiyun 					 hash_entry);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	return batadv_compare_eth(data1, data2);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /**
105*4882a593Smuzhiyun  * batadv_orig_node_vlan_get() - get an orig_node_vlan object
106*4882a593Smuzhiyun  * @orig_node: the originator serving the VLAN
107*4882a593Smuzhiyun  * @vid: the VLAN identifier
108*4882a593Smuzhiyun  *
109*4882a593Smuzhiyun  * Return: the vlan object identified by vid and belonging to orig_node or NULL
110*4882a593Smuzhiyun  * if it does not exist.
111*4882a593Smuzhiyun  */
112*4882a593Smuzhiyun struct batadv_orig_node_vlan *
batadv_orig_node_vlan_get(struct batadv_orig_node * orig_node,unsigned short vid)113*4882a593Smuzhiyun batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,
114*4882a593Smuzhiyun 			  unsigned short vid)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	struct batadv_orig_node_vlan *vlan = NULL, *tmp;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	rcu_read_lock();
119*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) {
120*4882a593Smuzhiyun 		if (tmp->vid != vid)
121*4882a593Smuzhiyun 			continue;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&tmp->refcount))
124*4882a593Smuzhiyun 			continue;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 		vlan = tmp;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 		break;
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 	rcu_read_unlock();
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return vlan;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun /**
136*4882a593Smuzhiyun  * batadv_orig_node_vlan_new() - search and possibly create an orig_node_vlan
137*4882a593Smuzhiyun  *  object
138*4882a593Smuzhiyun  * @orig_node: the originator serving the VLAN
139*4882a593Smuzhiyun  * @vid: the VLAN identifier
140*4882a593Smuzhiyun  *
141*4882a593Smuzhiyun  * Return: NULL in case of failure or the vlan object identified by vid and
142*4882a593Smuzhiyun  * belonging to orig_node otherwise. The object is created and added to the list
143*4882a593Smuzhiyun  * if it does not exist.
144*4882a593Smuzhiyun  *
145*4882a593Smuzhiyun  * The object is returned with refcounter increased by 1.
146*4882a593Smuzhiyun  */
147*4882a593Smuzhiyun struct batadv_orig_node_vlan *
batadv_orig_node_vlan_new(struct batadv_orig_node * orig_node,unsigned short vid)148*4882a593Smuzhiyun batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
149*4882a593Smuzhiyun 			  unsigned short vid)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	struct batadv_orig_node_vlan *vlan;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	spin_lock_bh(&orig_node->vlan_list_lock);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	/* first look if an object for this vid already exists */
156*4882a593Smuzhiyun 	vlan = batadv_orig_node_vlan_get(orig_node, vid);
157*4882a593Smuzhiyun 	if (vlan)
158*4882a593Smuzhiyun 		goto out;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
161*4882a593Smuzhiyun 	if (!vlan)
162*4882a593Smuzhiyun 		goto out;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	kref_init(&vlan->refcount);
165*4882a593Smuzhiyun 	vlan->vid = vid;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	kref_get(&vlan->refcount);
168*4882a593Smuzhiyun 	hlist_add_head_rcu(&vlan->list, &orig_node->vlan_list);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun out:
171*4882a593Smuzhiyun 	spin_unlock_bh(&orig_node->vlan_list_lock);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	return vlan;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun /**
177*4882a593Smuzhiyun  * batadv_orig_node_vlan_release() - release originator-vlan object from lists
178*4882a593Smuzhiyun  *  and queue for free after rcu grace period
179*4882a593Smuzhiyun  * @ref: kref pointer of the originator-vlan object
180*4882a593Smuzhiyun  */
batadv_orig_node_vlan_release(struct kref * ref)181*4882a593Smuzhiyun void batadv_orig_node_vlan_release(struct kref *ref)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct batadv_orig_node_vlan *orig_vlan;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	orig_vlan = container_of(ref, struct batadv_orig_node_vlan, refcount);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	kfree_rcu(orig_vlan, rcu);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun /**
191*4882a593Smuzhiyun  * batadv_originator_init() - Initialize all originator structures
192*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
193*4882a593Smuzhiyun  *
194*4882a593Smuzhiyun  * Return: 0 on success or negative error number in case of failure
195*4882a593Smuzhiyun  */
batadv_originator_init(struct batadv_priv * bat_priv)196*4882a593Smuzhiyun int batadv_originator_init(struct batadv_priv *bat_priv)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	if (bat_priv->orig_hash)
199*4882a593Smuzhiyun 		return 0;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	bat_priv->orig_hash = batadv_hash_new(1024);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (!bat_priv->orig_hash)
204*4882a593Smuzhiyun 		goto err;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	batadv_hash_set_lock_class(bat_priv->orig_hash,
207*4882a593Smuzhiyun 				   &batadv_orig_hash_lock_class_key);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&bat_priv->orig_work, batadv_purge_orig);
210*4882a593Smuzhiyun 	queue_delayed_work(batadv_event_workqueue,
211*4882a593Smuzhiyun 			   &bat_priv->orig_work,
212*4882a593Smuzhiyun 			   msecs_to_jiffies(BATADV_ORIG_WORK_PERIOD));
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	return 0;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun err:
217*4882a593Smuzhiyun 	return -ENOMEM;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun /**
221*4882a593Smuzhiyun  * batadv_neigh_ifinfo_release() - release neigh_ifinfo from lists and queue for
222*4882a593Smuzhiyun  *  free after rcu grace period
223*4882a593Smuzhiyun  * @ref: kref pointer of the neigh_ifinfo
224*4882a593Smuzhiyun  */
batadv_neigh_ifinfo_release(struct kref * ref)225*4882a593Smuzhiyun void batadv_neigh_ifinfo_release(struct kref *ref)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *neigh_ifinfo;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	neigh_ifinfo = container_of(ref, struct batadv_neigh_ifinfo, refcount);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
232*4882a593Smuzhiyun 		batadv_hardif_put(neigh_ifinfo->if_outgoing);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	kfree_rcu(neigh_ifinfo, rcu);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun /**
238*4882a593Smuzhiyun  * batadv_hardif_neigh_release() - release hardif neigh node from lists and
239*4882a593Smuzhiyun  *  queue for free after rcu grace period
240*4882a593Smuzhiyun  * @ref: kref pointer of the neigh_node
241*4882a593Smuzhiyun  */
batadv_hardif_neigh_release(struct kref * ref)242*4882a593Smuzhiyun void batadv_hardif_neigh_release(struct kref *ref)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	struct batadv_hardif_neigh_node *hardif_neigh;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	hardif_neigh = container_of(ref, struct batadv_hardif_neigh_node,
247*4882a593Smuzhiyun 				    refcount);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
250*4882a593Smuzhiyun 	hlist_del_init_rcu(&hardif_neigh->list);
251*4882a593Smuzhiyun 	spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	batadv_hardif_put(hardif_neigh->if_incoming);
254*4882a593Smuzhiyun 	kfree_rcu(hardif_neigh, rcu);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun /**
258*4882a593Smuzhiyun  * batadv_neigh_node_release() - release neigh_node from lists and queue for
259*4882a593Smuzhiyun  *  free after rcu grace period
260*4882a593Smuzhiyun  * @ref: kref pointer of the neigh_node
261*4882a593Smuzhiyun  */
batadv_neigh_node_release(struct kref * ref)262*4882a593Smuzhiyun void batadv_neigh_node_release(struct kref *ref)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	struct hlist_node *node_tmp;
265*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node;
266*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *neigh_ifinfo;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	neigh_node = container_of(ref, struct batadv_neigh_node, refcount);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
271*4882a593Smuzhiyun 				  &neigh_node->ifinfo_list, list) {
272*4882a593Smuzhiyun 		batadv_neigh_ifinfo_put(neigh_ifinfo);
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	batadv_hardif_neigh_put(neigh_node->hardif_neigh);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	batadv_hardif_put(neigh_node->if_incoming);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	kfree_rcu(neigh_node, rcu);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun /**
283*4882a593Smuzhiyun  * batadv_orig_router_get() - router to the originator depending on iface
284*4882a593Smuzhiyun  * @orig_node: the orig node for the router
285*4882a593Smuzhiyun  * @if_outgoing: the interface where the payload packet has been received or
286*4882a593Smuzhiyun  *  the OGM should be sent to
287*4882a593Smuzhiyun  *
288*4882a593Smuzhiyun  * Return: the neighbor which should be the router for this orig_node/iface.
289*4882a593Smuzhiyun  *
290*4882a593Smuzhiyun  * The object is returned with refcounter increased by 1.
291*4882a593Smuzhiyun  */
292*4882a593Smuzhiyun struct batadv_neigh_node *
batadv_orig_router_get(struct batadv_orig_node * orig_node,const struct batadv_hard_iface * if_outgoing)293*4882a593Smuzhiyun batadv_orig_router_get(struct batadv_orig_node *orig_node,
294*4882a593Smuzhiyun 		       const struct batadv_hard_iface *if_outgoing)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct batadv_orig_ifinfo *orig_ifinfo;
297*4882a593Smuzhiyun 	struct batadv_neigh_node *router = NULL;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	rcu_read_lock();
300*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) {
301*4882a593Smuzhiyun 		if (orig_ifinfo->if_outgoing != if_outgoing)
302*4882a593Smuzhiyun 			continue;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		router = rcu_dereference(orig_ifinfo->router);
305*4882a593Smuzhiyun 		break;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (router && !kref_get_unless_zero(&router->refcount))
309*4882a593Smuzhiyun 		router = NULL;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	rcu_read_unlock();
312*4882a593Smuzhiyun 	return router;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun /**
316*4882a593Smuzhiyun  * batadv_orig_ifinfo_get() - find the ifinfo from an orig_node
317*4882a593Smuzhiyun  * @orig_node: the orig node to be queried
318*4882a593Smuzhiyun  * @if_outgoing: the interface for which the ifinfo should be acquired
319*4882a593Smuzhiyun  *
320*4882a593Smuzhiyun  * Return: the requested orig_ifinfo or NULL if not found.
321*4882a593Smuzhiyun  *
322*4882a593Smuzhiyun  * The object is returned with refcounter increased by 1.
323*4882a593Smuzhiyun  */
324*4882a593Smuzhiyun struct batadv_orig_ifinfo *
batadv_orig_ifinfo_get(struct batadv_orig_node * orig_node,struct batadv_hard_iface * if_outgoing)325*4882a593Smuzhiyun batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
326*4882a593Smuzhiyun 		       struct batadv_hard_iface *if_outgoing)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	rcu_read_lock();
331*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list,
332*4882a593Smuzhiyun 				 list) {
333*4882a593Smuzhiyun 		if (tmp->if_outgoing != if_outgoing)
334*4882a593Smuzhiyun 			continue;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&tmp->refcount))
337*4882a593Smuzhiyun 			continue;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 		orig_ifinfo = tmp;
340*4882a593Smuzhiyun 		break;
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 	rcu_read_unlock();
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	return orig_ifinfo;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun /**
348*4882a593Smuzhiyun  * batadv_orig_ifinfo_new() - search and possibly create an orig_ifinfo object
349*4882a593Smuzhiyun  * @orig_node: the orig node to be queried
350*4882a593Smuzhiyun  * @if_outgoing: the interface for which the ifinfo should be acquired
351*4882a593Smuzhiyun  *
352*4882a593Smuzhiyun  * Return: NULL in case of failure or the orig_ifinfo object for the if_outgoing
353*4882a593Smuzhiyun  * interface otherwise. The object is created and added to the list
354*4882a593Smuzhiyun  * if it does not exist.
355*4882a593Smuzhiyun  *
356*4882a593Smuzhiyun  * The object is returned with refcounter increased by 1.
357*4882a593Smuzhiyun  */
358*4882a593Smuzhiyun struct batadv_orig_ifinfo *
batadv_orig_ifinfo_new(struct batadv_orig_node * orig_node,struct batadv_hard_iface * if_outgoing)359*4882a593Smuzhiyun batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
360*4882a593Smuzhiyun 		       struct batadv_hard_iface *if_outgoing)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	struct batadv_orig_ifinfo *orig_ifinfo;
363*4882a593Smuzhiyun 	unsigned long reset_time;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	spin_lock_bh(&orig_node->neigh_list_lock);
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing);
368*4882a593Smuzhiyun 	if (orig_ifinfo)
369*4882a593Smuzhiyun 		goto out;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC);
372*4882a593Smuzhiyun 	if (!orig_ifinfo)
373*4882a593Smuzhiyun 		goto out;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (if_outgoing != BATADV_IF_DEFAULT)
376*4882a593Smuzhiyun 		kref_get(&if_outgoing->refcount);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	reset_time = jiffies - 1;
379*4882a593Smuzhiyun 	reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
380*4882a593Smuzhiyun 	orig_ifinfo->batman_seqno_reset = reset_time;
381*4882a593Smuzhiyun 	orig_ifinfo->if_outgoing = if_outgoing;
382*4882a593Smuzhiyun 	INIT_HLIST_NODE(&orig_ifinfo->list);
383*4882a593Smuzhiyun 	kref_init(&orig_ifinfo->refcount);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	kref_get(&orig_ifinfo->refcount);
386*4882a593Smuzhiyun 	hlist_add_head_rcu(&orig_ifinfo->list,
387*4882a593Smuzhiyun 			   &orig_node->ifinfo_list);
388*4882a593Smuzhiyun out:
389*4882a593Smuzhiyun 	spin_unlock_bh(&orig_node->neigh_list_lock);
390*4882a593Smuzhiyun 	return orig_ifinfo;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun /**
394*4882a593Smuzhiyun  * batadv_neigh_ifinfo_get() - find the ifinfo from an neigh_node
395*4882a593Smuzhiyun  * @neigh: the neigh node to be queried
396*4882a593Smuzhiyun  * @if_outgoing: the interface for which the ifinfo should be acquired
397*4882a593Smuzhiyun  *
398*4882a593Smuzhiyun  * The object is returned with refcounter increased by 1.
399*4882a593Smuzhiyun  *
400*4882a593Smuzhiyun  * Return: the requested neigh_ifinfo or NULL if not found
401*4882a593Smuzhiyun  */
402*4882a593Smuzhiyun struct batadv_neigh_ifinfo *
batadv_neigh_ifinfo_get(struct batadv_neigh_node * neigh,struct batadv_hard_iface * if_outgoing)403*4882a593Smuzhiyun batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
404*4882a593Smuzhiyun 			struct batadv_hard_iface *if_outgoing)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *neigh_ifinfo = NULL,
407*4882a593Smuzhiyun 				   *tmp_neigh_ifinfo;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	rcu_read_lock();
410*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list,
411*4882a593Smuzhiyun 				 list) {
412*4882a593Smuzhiyun 		if (tmp_neigh_ifinfo->if_outgoing != if_outgoing)
413*4882a593Smuzhiyun 			continue;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&tmp_neigh_ifinfo->refcount))
416*4882a593Smuzhiyun 			continue;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 		neigh_ifinfo = tmp_neigh_ifinfo;
419*4882a593Smuzhiyun 		break;
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 	rcu_read_unlock();
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	return neigh_ifinfo;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun /**
427*4882a593Smuzhiyun  * batadv_neigh_ifinfo_new() - search and possibly create an neigh_ifinfo object
428*4882a593Smuzhiyun  * @neigh: the neigh node to be queried
429*4882a593Smuzhiyun  * @if_outgoing: the interface for which the ifinfo should be acquired
430*4882a593Smuzhiyun  *
431*4882a593Smuzhiyun  * Return: NULL in case of failure or the neigh_ifinfo object for the
432*4882a593Smuzhiyun  * if_outgoing interface otherwise. The object is created and added to the list
433*4882a593Smuzhiyun  * if it does not exist.
434*4882a593Smuzhiyun  *
435*4882a593Smuzhiyun  * The object is returned with refcounter increased by 1.
436*4882a593Smuzhiyun  */
437*4882a593Smuzhiyun struct batadv_neigh_ifinfo *
batadv_neigh_ifinfo_new(struct batadv_neigh_node * neigh,struct batadv_hard_iface * if_outgoing)438*4882a593Smuzhiyun batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
439*4882a593Smuzhiyun 			struct batadv_hard_iface *if_outgoing)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *neigh_ifinfo;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	spin_lock_bh(&neigh->ifinfo_lock);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing);
446*4882a593Smuzhiyun 	if (neigh_ifinfo)
447*4882a593Smuzhiyun 		goto out;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC);
450*4882a593Smuzhiyun 	if (!neigh_ifinfo)
451*4882a593Smuzhiyun 		goto out;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	if (if_outgoing)
454*4882a593Smuzhiyun 		kref_get(&if_outgoing->refcount);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	INIT_HLIST_NODE(&neigh_ifinfo->list);
457*4882a593Smuzhiyun 	kref_init(&neigh_ifinfo->refcount);
458*4882a593Smuzhiyun 	neigh_ifinfo->if_outgoing = if_outgoing;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	kref_get(&neigh_ifinfo->refcount);
461*4882a593Smuzhiyun 	hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun out:
464*4882a593Smuzhiyun 	spin_unlock_bh(&neigh->ifinfo_lock);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	return neigh_ifinfo;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun /**
470*4882a593Smuzhiyun  * batadv_neigh_node_get() - retrieve a neighbour from the list
471*4882a593Smuzhiyun  * @orig_node: originator which the neighbour belongs to
472*4882a593Smuzhiyun  * @hard_iface: the interface where this neighbour is connected to
473*4882a593Smuzhiyun  * @addr: the address of the neighbour
474*4882a593Smuzhiyun  *
475*4882a593Smuzhiyun  * Looks for and possibly returns a neighbour belonging to this originator list
476*4882a593Smuzhiyun  * which is connected through the provided hard interface.
477*4882a593Smuzhiyun  *
478*4882a593Smuzhiyun  * Return: neighbor when found. Otherwise NULL
479*4882a593Smuzhiyun  */
480*4882a593Smuzhiyun static struct batadv_neigh_node *
batadv_neigh_node_get(const struct batadv_orig_node * orig_node,const struct batadv_hard_iface * hard_iface,const u8 * addr)481*4882a593Smuzhiyun batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
482*4882a593Smuzhiyun 		      const struct batadv_hard_iface *hard_iface,
483*4882a593Smuzhiyun 		      const u8 *addr)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	struct batadv_neigh_node *tmp_neigh_node, *res = NULL;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	rcu_read_lock();
488*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) {
489*4882a593Smuzhiyun 		if (!batadv_compare_eth(tmp_neigh_node->addr, addr))
490*4882a593Smuzhiyun 			continue;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 		if (tmp_neigh_node->if_incoming != hard_iface)
493*4882a593Smuzhiyun 			continue;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&tmp_neigh_node->refcount))
496*4882a593Smuzhiyun 			continue;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 		res = tmp_neigh_node;
499*4882a593Smuzhiyun 		break;
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 	rcu_read_unlock();
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	return res;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun /**
507*4882a593Smuzhiyun  * batadv_hardif_neigh_create() - create a hardif neighbour node
508*4882a593Smuzhiyun  * @hard_iface: the interface this neighbour is connected to
509*4882a593Smuzhiyun  * @neigh_addr: the interface address of the neighbour to retrieve
510*4882a593Smuzhiyun  * @orig_node: originator object representing the neighbour
511*4882a593Smuzhiyun  *
512*4882a593Smuzhiyun  * Return: the hardif neighbour node if found or created or NULL otherwise.
513*4882a593Smuzhiyun  */
514*4882a593Smuzhiyun static struct batadv_hardif_neigh_node *
batadv_hardif_neigh_create(struct batadv_hard_iface * hard_iface,const u8 * neigh_addr,struct batadv_orig_node * orig_node)515*4882a593Smuzhiyun batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
516*4882a593Smuzhiyun 			   const u8 *neigh_addr,
517*4882a593Smuzhiyun 			   struct batadv_orig_node *orig_node)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
520*4882a593Smuzhiyun 	struct batadv_hardif_neigh_node *hardif_neigh;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	spin_lock_bh(&hard_iface->neigh_list_lock);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	/* check if neighbor hasn't been added in the meantime */
525*4882a593Smuzhiyun 	hardif_neigh = batadv_hardif_neigh_get(hard_iface, neigh_addr);
526*4882a593Smuzhiyun 	if (hardif_neigh)
527*4882a593Smuzhiyun 		goto out;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	hardif_neigh = kzalloc(sizeof(*hardif_neigh), GFP_ATOMIC);
530*4882a593Smuzhiyun 	if (!hardif_neigh)
531*4882a593Smuzhiyun 		goto out;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	kref_get(&hard_iface->refcount);
534*4882a593Smuzhiyun 	INIT_HLIST_NODE(&hardif_neigh->list);
535*4882a593Smuzhiyun 	ether_addr_copy(hardif_neigh->addr, neigh_addr);
536*4882a593Smuzhiyun 	ether_addr_copy(hardif_neigh->orig, orig_node->orig);
537*4882a593Smuzhiyun 	hardif_neigh->if_incoming = hard_iface;
538*4882a593Smuzhiyun 	hardif_neigh->last_seen = jiffies;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	kref_init(&hardif_neigh->refcount);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (bat_priv->algo_ops->neigh.hardif_init)
543*4882a593Smuzhiyun 		bat_priv->algo_ops->neigh.hardif_init(hardif_neigh);
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	hlist_add_head_rcu(&hardif_neigh->list, &hard_iface->neigh_list);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun out:
548*4882a593Smuzhiyun 	spin_unlock_bh(&hard_iface->neigh_list_lock);
549*4882a593Smuzhiyun 	return hardif_neigh;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun /**
553*4882a593Smuzhiyun  * batadv_hardif_neigh_get_or_create() - retrieve or create a hardif neighbour
554*4882a593Smuzhiyun  *  node
555*4882a593Smuzhiyun  * @hard_iface: the interface this neighbour is connected to
556*4882a593Smuzhiyun  * @neigh_addr: the interface address of the neighbour to retrieve
557*4882a593Smuzhiyun  * @orig_node: originator object representing the neighbour
558*4882a593Smuzhiyun  *
559*4882a593Smuzhiyun  * Return: the hardif neighbour node if found or created or NULL otherwise.
560*4882a593Smuzhiyun  */
561*4882a593Smuzhiyun static struct batadv_hardif_neigh_node *
batadv_hardif_neigh_get_or_create(struct batadv_hard_iface * hard_iface,const u8 * neigh_addr,struct batadv_orig_node * orig_node)562*4882a593Smuzhiyun batadv_hardif_neigh_get_or_create(struct batadv_hard_iface *hard_iface,
563*4882a593Smuzhiyun 				  const u8 *neigh_addr,
564*4882a593Smuzhiyun 				  struct batadv_orig_node *orig_node)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun 	struct batadv_hardif_neigh_node *hardif_neigh;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	/* first check without locking to avoid the overhead */
569*4882a593Smuzhiyun 	hardif_neigh = batadv_hardif_neigh_get(hard_iface, neigh_addr);
570*4882a593Smuzhiyun 	if (hardif_neigh)
571*4882a593Smuzhiyun 		return hardif_neigh;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	return batadv_hardif_neigh_create(hard_iface, neigh_addr, orig_node);
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun /**
577*4882a593Smuzhiyun  * batadv_hardif_neigh_get() - retrieve a hardif neighbour from the list
578*4882a593Smuzhiyun  * @hard_iface: the interface where this neighbour is connected to
579*4882a593Smuzhiyun  * @neigh_addr: the address of the neighbour
580*4882a593Smuzhiyun  *
581*4882a593Smuzhiyun  * Looks for and possibly returns a neighbour belonging to this hard interface.
582*4882a593Smuzhiyun  *
583*4882a593Smuzhiyun  * Return: neighbor when found. Otherwise NULL
584*4882a593Smuzhiyun  */
585*4882a593Smuzhiyun struct batadv_hardif_neigh_node *
batadv_hardif_neigh_get(const struct batadv_hard_iface * hard_iface,const u8 * neigh_addr)586*4882a593Smuzhiyun batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface,
587*4882a593Smuzhiyun 			const u8 *neigh_addr)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	struct batadv_hardif_neigh_node *tmp_hardif_neigh, *hardif_neigh = NULL;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	rcu_read_lock();
592*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(tmp_hardif_neigh,
593*4882a593Smuzhiyun 				 &hard_iface->neigh_list, list) {
594*4882a593Smuzhiyun 		if (!batadv_compare_eth(tmp_hardif_neigh->addr, neigh_addr))
595*4882a593Smuzhiyun 			continue;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&tmp_hardif_neigh->refcount))
598*4882a593Smuzhiyun 			continue;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 		hardif_neigh = tmp_hardif_neigh;
601*4882a593Smuzhiyun 		break;
602*4882a593Smuzhiyun 	}
603*4882a593Smuzhiyun 	rcu_read_unlock();
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	return hardif_neigh;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun /**
609*4882a593Smuzhiyun  * batadv_neigh_node_create() - create a neigh node object
610*4882a593Smuzhiyun  * @orig_node: originator object representing the neighbour
611*4882a593Smuzhiyun  * @hard_iface: the interface where the neighbour is connected to
612*4882a593Smuzhiyun  * @neigh_addr: the mac address of the neighbour interface
613*4882a593Smuzhiyun  *
614*4882a593Smuzhiyun  * Allocates a new neigh_node object and initialises all the generic fields.
615*4882a593Smuzhiyun  *
616*4882a593Smuzhiyun  * Return: the neighbour node if found or created or NULL otherwise.
617*4882a593Smuzhiyun  */
618*4882a593Smuzhiyun static struct batadv_neigh_node *
batadv_neigh_node_create(struct batadv_orig_node * orig_node,struct batadv_hard_iface * hard_iface,const u8 * neigh_addr)619*4882a593Smuzhiyun batadv_neigh_node_create(struct batadv_orig_node *orig_node,
620*4882a593Smuzhiyun 			 struct batadv_hard_iface *hard_iface,
621*4882a593Smuzhiyun 			 const u8 *neigh_addr)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node;
624*4882a593Smuzhiyun 	struct batadv_hardif_neigh_node *hardif_neigh = NULL;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	spin_lock_bh(&orig_node->neigh_list_lock);
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
629*4882a593Smuzhiyun 	if (neigh_node)
630*4882a593Smuzhiyun 		goto out;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	hardif_neigh = batadv_hardif_neigh_get_or_create(hard_iface,
633*4882a593Smuzhiyun 							 neigh_addr, orig_node);
634*4882a593Smuzhiyun 	if (!hardif_neigh)
635*4882a593Smuzhiyun 		goto out;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
638*4882a593Smuzhiyun 	if (!neigh_node)
639*4882a593Smuzhiyun 		goto out;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	INIT_HLIST_NODE(&neigh_node->list);
642*4882a593Smuzhiyun 	INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
643*4882a593Smuzhiyun 	spin_lock_init(&neigh_node->ifinfo_lock);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	kref_get(&hard_iface->refcount);
646*4882a593Smuzhiyun 	ether_addr_copy(neigh_node->addr, neigh_addr);
647*4882a593Smuzhiyun 	neigh_node->if_incoming = hard_iface;
648*4882a593Smuzhiyun 	neigh_node->orig_node = orig_node;
649*4882a593Smuzhiyun 	neigh_node->last_seen = jiffies;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	/* increment unique neighbor refcount */
652*4882a593Smuzhiyun 	kref_get(&hardif_neigh->refcount);
653*4882a593Smuzhiyun 	neigh_node->hardif_neigh = hardif_neigh;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	/* extra reference for return */
656*4882a593Smuzhiyun 	kref_init(&neigh_node->refcount);
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	kref_get(&neigh_node->refcount);
659*4882a593Smuzhiyun 	hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv,
662*4882a593Smuzhiyun 		   "Creating new neighbor %pM for orig_node %pM on interface %s\n",
663*4882a593Smuzhiyun 		   neigh_addr, orig_node->orig, hard_iface->net_dev->name);
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun out:
666*4882a593Smuzhiyun 	spin_unlock_bh(&orig_node->neigh_list_lock);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	if (hardif_neigh)
669*4882a593Smuzhiyun 		batadv_hardif_neigh_put(hardif_neigh);
670*4882a593Smuzhiyun 	return neigh_node;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun /**
674*4882a593Smuzhiyun  * batadv_neigh_node_get_or_create() - retrieve or create a neigh node object
675*4882a593Smuzhiyun  * @orig_node: originator object representing the neighbour
676*4882a593Smuzhiyun  * @hard_iface: the interface where the neighbour is connected to
677*4882a593Smuzhiyun  * @neigh_addr: the mac address of the neighbour interface
678*4882a593Smuzhiyun  *
679*4882a593Smuzhiyun  * Return: the neighbour node if found or created or NULL otherwise.
680*4882a593Smuzhiyun  */
681*4882a593Smuzhiyun struct batadv_neigh_node *
batadv_neigh_node_get_or_create(struct batadv_orig_node * orig_node,struct batadv_hard_iface * hard_iface,const u8 * neigh_addr)682*4882a593Smuzhiyun batadv_neigh_node_get_or_create(struct batadv_orig_node *orig_node,
683*4882a593Smuzhiyun 				struct batadv_hard_iface *hard_iface,
684*4882a593Smuzhiyun 				const u8 *neigh_addr)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	/* first check without locking to avoid the overhead */
689*4882a593Smuzhiyun 	neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
690*4882a593Smuzhiyun 	if (neigh_node)
691*4882a593Smuzhiyun 		return neigh_node;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	return batadv_neigh_node_create(orig_node, hard_iface, neigh_addr);
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_DEBUGFS
697*4882a593Smuzhiyun /**
698*4882a593Smuzhiyun  * batadv_hardif_neigh_seq_print_text() - print the single hop neighbour list
699*4882a593Smuzhiyun  * @seq: neighbour table seq_file struct
700*4882a593Smuzhiyun  * @offset: not used
701*4882a593Smuzhiyun  *
702*4882a593Smuzhiyun  * Return: always 0
703*4882a593Smuzhiyun  */
batadv_hardif_neigh_seq_print_text(struct seq_file * seq,void * offset)704*4882a593Smuzhiyun int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	struct net_device *net_dev = (struct net_device *)seq->private;
707*4882a593Smuzhiyun 	struct batadv_priv *bat_priv = netdev_priv(net_dev);
708*4882a593Smuzhiyun 	struct batadv_hard_iface *primary_if;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	primary_if = batadv_seq_print_text_primary_if_get(seq);
711*4882a593Smuzhiyun 	if (!primary_if)
712*4882a593Smuzhiyun 		return 0;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s %s)]\n",
715*4882a593Smuzhiyun 		   BATADV_SOURCE_VERSION, primary_if->net_dev->name,
716*4882a593Smuzhiyun 		   primary_if->net_dev->dev_addr, net_dev->name,
717*4882a593Smuzhiyun 		   bat_priv->algo_ops->name);
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	batadv_hardif_put(primary_if);
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	if (!bat_priv->algo_ops->neigh.print) {
722*4882a593Smuzhiyun 		seq_puts(seq,
723*4882a593Smuzhiyun 			 "No printing function for this routing protocol\n");
724*4882a593Smuzhiyun 		return 0;
725*4882a593Smuzhiyun 	}
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	bat_priv->algo_ops->neigh.print(bat_priv, seq);
728*4882a593Smuzhiyun 	return 0;
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun #endif
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun /**
733*4882a593Smuzhiyun  * batadv_hardif_neigh_dump() - Dump to netlink the neighbor infos for a
734*4882a593Smuzhiyun  *  specific outgoing interface
735*4882a593Smuzhiyun  * @msg: message to dump into
736*4882a593Smuzhiyun  * @cb: parameters for the dump
737*4882a593Smuzhiyun  *
738*4882a593Smuzhiyun  * Return: 0 or error value
739*4882a593Smuzhiyun  */
batadv_hardif_neigh_dump(struct sk_buff * msg,struct netlink_callback * cb)740*4882a593Smuzhiyun int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb)
741*4882a593Smuzhiyun {
742*4882a593Smuzhiyun 	struct net *net = sock_net(cb->skb->sk);
743*4882a593Smuzhiyun 	struct net_device *soft_iface;
744*4882a593Smuzhiyun 	struct net_device *hard_iface = NULL;
745*4882a593Smuzhiyun 	struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT;
746*4882a593Smuzhiyun 	struct batadv_priv *bat_priv;
747*4882a593Smuzhiyun 	struct batadv_hard_iface *primary_if = NULL;
748*4882a593Smuzhiyun 	int ret;
749*4882a593Smuzhiyun 	int ifindex, hard_ifindex;
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
752*4882a593Smuzhiyun 	if (!ifindex)
753*4882a593Smuzhiyun 		return -EINVAL;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	soft_iface = dev_get_by_index(net, ifindex);
756*4882a593Smuzhiyun 	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
757*4882a593Smuzhiyun 		ret = -ENODEV;
758*4882a593Smuzhiyun 		goto out;
759*4882a593Smuzhiyun 	}
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	bat_priv = netdev_priv(soft_iface);
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	primary_if = batadv_primary_if_get_selected(bat_priv);
764*4882a593Smuzhiyun 	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
765*4882a593Smuzhiyun 		ret = -ENOENT;
766*4882a593Smuzhiyun 		goto out;
767*4882a593Smuzhiyun 	}
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	hard_ifindex = batadv_netlink_get_ifindex(cb->nlh,
770*4882a593Smuzhiyun 						  BATADV_ATTR_HARD_IFINDEX);
771*4882a593Smuzhiyun 	if (hard_ifindex) {
772*4882a593Smuzhiyun 		hard_iface = dev_get_by_index(net, hard_ifindex);
773*4882a593Smuzhiyun 		if (hard_iface)
774*4882a593Smuzhiyun 			hardif = batadv_hardif_get_by_netdev(hard_iface);
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 		if (!hardif) {
777*4882a593Smuzhiyun 			ret = -ENODEV;
778*4882a593Smuzhiyun 			goto out;
779*4882a593Smuzhiyun 		}
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 		if (hardif->soft_iface != soft_iface) {
782*4882a593Smuzhiyun 			ret = -ENOENT;
783*4882a593Smuzhiyun 			goto out;
784*4882a593Smuzhiyun 		}
785*4882a593Smuzhiyun 	}
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	if (!bat_priv->algo_ops->neigh.dump) {
788*4882a593Smuzhiyun 		ret = -EOPNOTSUPP;
789*4882a593Smuzhiyun 		goto out;
790*4882a593Smuzhiyun 	}
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	bat_priv->algo_ops->neigh.dump(msg, cb, bat_priv, hardif);
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	ret = msg->len;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun  out:
797*4882a593Smuzhiyun 	if (hardif)
798*4882a593Smuzhiyun 		batadv_hardif_put(hardif);
799*4882a593Smuzhiyun 	if (hard_iface)
800*4882a593Smuzhiyun 		dev_put(hard_iface);
801*4882a593Smuzhiyun 	if (primary_if)
802*4882a593Smuzhiyun 		batadv_hardif_put(primary_if);
803*4882a593Smuzhiyun 	if (soft_iface)
804*4882a593Smuzhiyun 		dev_put(soft_iface);
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	return ret;
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun /**
810*4882a593Smuzhiyun  * batadv_orig_ifinfo_release() - release orig_ifinfo from lists and queue for
811*4882a593Smuzhiyun  *  free after rcu grace period
812*4882a593Smuzhiyun  * @ref: kref pointer of the orig_ifinfo
813*4882a593Smuzhiyun  */
batadv_orig_ifinfo_release(struct kref * ref)814*4882a593Smuzhiyun void batadv_orig_ifinfo_release(struct kref *ref)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun 	struct batadv_orig_ifinfo *orig_ifinfo;
817*4882a593Smuzhiyun 	struct batadv_neigh_node *router;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	orig_ifinfo = container_of(ref, struct batadv_orig_ifinfo, refcount);
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
822*4882a593Smuzhiyun 		batadv_hardif_put(orig_ifinfo->if_outgoing);
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 	/* this is the last reference to this object */
825*4882a593Smuzhiyun 	router = rcu_dereference_protected(orig_ifinfo->router, true);
826*4882a593Smuzhiyun 	if (router)
827*4882a593Smuzhiyun 		batadv_neigh_node_put(router);
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	kfree_rcu(orig_ifinfo, rcu);
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun /**
833*4882a593Smuzhiyun  * batadv_orig_node_free_rcu() - free the orig_node
834*4882a593Smuzhiyun  * @rcu: rcu pointer of the orig_node
835*4882a593Smuzhiyun  */
batadv_orig_node_free_rcu(struct rcu_head * rcu)836*4882a593Smuzhiyun static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node;
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	orig_node = container_of(rcu, struct batadv_orig_node, rcu);
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	batadv_mcast_purge_orig(orig_node);
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	batadv_frag_purge_orig(orig_node, NULL);
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	kfree(orig_node->tt_buff);
847*4882a593Smuzhiyun 	kfree(orig_node);
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun /**
851*4882a593Smuzhiyun  * batadv_orig_node_release() - release orig_node from lists and queue for
852*4882a593Smuzhiyun  *  free after rcu grace period
853*4882a593Smuzhiyun  * @ref: kref pointer of the orig_node
854*4882a593Smuzhiyun  */
batadv_orig_node_release(struct kref * ref)855*4882a593Smuzhiyun void batadv_orig_node_release(struct kref *ref)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun 	struct hlist_node *node_tmp;
858*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node;
859*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node;
860*4882a593Smuzhiyun 	struct batadv_orig_ifinfo *orig_ifinfo;
861*4882a593Smuzhiyun 	struct batadv_orig_node_vlan *vlan;
862*4882a593Smuzhiyun 	struct batadv_orig_ifinfo *last_candidate;
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	orig_node = container_of(ref, struct batadv_orig_node, refcount);
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	spin_lock_bh(&orig_node->neigh_list_lock);
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	/* for all neighbors towards this originator ... */
869*4882a593Smuzhiyun 	hlist_for_each_entry_safe(neigh_node, node_tmp,
870*4882a593Smuzhiyun 				  &orig_node->neigh_list, list) {
871*4882a593Smuzhiyun 		hlist_del_rcu(&neigh_node->list);
872*4882a593Smuzhiyun 		batadv_neigh_node_put(neigh_node);
873*4882a593Smuzhiyun 	}
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
876*4882a593Smuzhiyun 				  &orig_node->ifinfo_list, list) {
877*4882a593Smuzhiyun 		hlist_del_rcu(&orig_ifinfo->list);
878*4882a593Smuzhiyun 		batadv_orig_ifinfo_put(orig_ifinfo);
879*4882a593Smuzhiyun 	}
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	last_candidate = orig_node->last_bonding_candidate;
882*4882a593Smuzhiyun 	orig_node->last_bonding_candidate = NULL;
883*4882a593Smuzhiyun 	spin_unlock_bh(&orig_node->neigh_list_lock);
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	if (last_candidate)
886*4882a593Smuzhiyun 		batadv_orig_ifinfo_put(last_candidate);
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	spin_lock_bh(&orig_node->vlan_list_lock);
889*4882a593Smuzhiyun 	hlist_for_each_entry_safe(vlan, node_tmp, &orig_node->vlan_list, list) {
890*4882a593Smuzhiyun 		hlist_del_rcu(&vlan->list);
891*4882a593Smuzhiyun 		batadv_orig_node_vlan_put(vlan);
892*4882a593Smuzhiyun 	}
893*4882a593Smuzhiyun 	spin_unlock_bh(&orig_node->vlan_list_lock);
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	/* Free nc_nodes */
896*4882a593Smuzhiyun 	batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu);
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun /**
902*4882a593Smuzhiyun  * batadv_originator_free() - Free all originator structures
903*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
904*4882a593Smuzhiyun  */
batadv_originator_free(struct batadv_priv * bat_priv)905*4882a593Smuzhiyun void batadv_originator_free(struct batadv_priv *bat_priv)
906*4882a593Smuzhiyun {
907*4882a593Smuzhiyun 	struct batadv_hashtable *hash = bat_priv->orig_hash;
908*4882a593Smuzhiyun 	struct hlist_node *node_tmp;
909*4882a593Smuzhiyun 	struct hlist_head *head;
910*4882a593Smuzhiyun 	spinlock_t *list_lock; /* spinlock to protect write access */
911*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node;
912*4882a593Smuzhiyun 	u32 i;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	if (!hash)
915*4882a593Smuzhiyun 		return;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	cancel_delayed_work_sync(&bat_priv->orig_work);
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	bat_priv->orig_hash = NULL;
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	for (i = 0; i < hash->size; i++) {
922*4882a593Smuzhiyun 		head = &hash->table[i];
923*4882a593Smuzhiyun 		list_lock = &hash->list_locks[i];
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 		spin_lock_bh(list_lock);
926*4882a593Smuzhiyun 		hlist_for_each_entry_safe(orig_node, node_tmp,
927*4882a593Smuzhiyun 					  head, hash_entry) {
928*4882a593Smuzhiyun 			hlist_del_rcu(&orig_node->hash_entry);
929*4882a593Smuzhiyun 			batadv_orig_node_put(orig_node);
930*4882a593Smuzhiyun 		}
931*4882a593Smuzhiyun 		spin_unlock_bh(list_lock);
932*4882a593Smuzhiyun 	}
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	batadv_hash_destroy(hash);
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun /**
938*4882a593Smuzhiyun  * batadv_orig_node_new() - creates a new orig_node
939*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
940*4882a593Smuzhiyun  * @addr: the mac address of the originator
941*4882a593Smuzhiyun  *
942*4882a593Smuzhiyun  * Creates a new originator object and initialises all the generic fields.
943*4882a593Smuzhiyun  * The new object is not added to the originator list.
944*4882a593Smuzhiyun  *
945*4882a593Smuzhiyun  * Return: the newly created object or NULL on failure.
946*4882a593Smuzhiyun  */
batadv_orig_node_new(struct batadv_priv * bat_priv,const u8 * addr)947*4882a593Smuzhiyun struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
948*4882a593Smuzhiyun 					      const u8 *addr)
949*4882a593Smuzhiyun {
950*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node;
951*4882a593Smuzhiyun 	struct batadv_orig_node_vlan *vlan;
952*4882a593Smuzhiyun 	unsigned long reset_time;
953*4882a593Smuzhiyun 	int i;
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
956*4882a593Smuzhiyun 		   "Creating new originator: %pM\n", addr);
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	orig_node = kzalloc(sizeof(*orig_node), GFP_ATOMIC);
959*4882a593Smuzhiyun 	if (!orig_node)
960*4882a593Smuzhiyun 		return NULL;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 	INIT_HLIST_HEAD(&orig_node->neigh_list);
963*4882a593Smuzhiyun 	INIT_HLIST_HEAD(&orig_node->vlan_list);
964*4882a593Smuzhiyun 	INIT_HLIST_HEAD(&orig_node->ifinfo_list);
965*4882a593Smuzhiyun 	spin_lock_init(&orig_node->bcast_seqno_lock);
966*4882a593Smuzhiyun 	spin_lock_init(&orig_node->neigh_list_lock);
967*4882a593Smuzhiyun 	spin_lock_init(&orig_node->tt_buff_lock);
968*4882a593Smuzhiyun 	spin_lock_init(&orig_node->tt_lock);
969*4882a593Smuzhiyun 	spin_lock_init(&orig_node->vlan_list_lock);
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	batadv_nc_init_orig(orig_node);
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 	/* extra reference for return */
974*4882a593Smuzhiyun 	kref_init(&orig_node->refcount);
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	orig_node->bat_priv = bat_priv;
977*4882a593Smuzhiyun 	ether_addr_copy(orig_node->orig, addr);
978*4882a593Smuzhiyun 	batadv_dat_init_orig_node_addr(orig_node);
979*4882a593Smuzhiyun 	atomic_set(&orig_node->last_ttvn, 0);
980*4882a593Smuzhiyun 	orig_node->tt_buff = NULL;
981*4882a593Smuzhiyun 	orig_node->tt_buff_len = 0;
982*4882a593Smuzhiyun 	orig_node->last_seen = jiffies;
983*4882a593Smuzhiyun 	reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
984*4882a593Smuzhiyun 	orig_node->bcast_seqno_reset = reset_time;
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_MCAST
987*4882a593Smuzhiyun 	orig_node->mcast_flags = BATADV_MCAST_WANT_NO_RTR4;
988*4882a593Smuzhiyun 	orig_node->mcast_flags |= BATADV_MCAST_WANT_NO_RTR6;
989*4882a593Smuzhiyun 	INIT_HLIST_NODE(&orig_node->mcast_want_all_unsnoopables_node);
990*4882a593Smuzhiyun 	INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv4_node);
991*4882a593Smuzhiyun 	INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv6_node);
992*4882a593Smuzhiyun 	spin_lock_init(&orig_node->mcast_handler_lock);
993*4882a593Smuzhiyun #endif
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	/* create a vlan object for the "untagged" LAN */
996*4882a593Smuzhiyun 	vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
997*4882a593Smuzhiyun 	if (!vlan)
998*4882a593Smuzhiyun 		goto free_orig_node;
999*4882a593Smuzhiyun 	/* batadv_orig_node_vlan_new() increases the refcounter.
1000*4882a593Smuzhiyun 	 * Immediately release vlan since it is not needed anymore in this
1001*4882a593Smuzhiyun 	 * context
1002*4882a593Smuzhiyun 	 */
1003*4882a593Smuzhiyun 	batadv_orig_node_vlan_put(vlan);
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) {
1006*4882a593Smuzhiyun 		INIT_HLIST_HEAD(&orig_node->fragments[i].fragment_list);
1007*4882a593Smuzhiyun 		spin_lock_init(&orig_node->fragments[i].lock);
1008*4882a593Smuzhiyun 		orig_node->fragments[i].size = 0;
1009*4882a593Smuzhiyun 	}
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	return orig_node;
1012*4882a593Smuzhiyun free_orig_node:
1013*4882a593Smuzhiyun 	kfree(orig_node);
1014*4882a593Smuzhiyun 	return NULL;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun /**
1018*4882a593Smuzhiyun  * batadv_purge_neigh_ifinfo() - purge obsolete ifinfo entries from neighbor
1019*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
1020*4882a593Smuzhiyun  * @neigh: orig node which is to be checked
1021*4882a593Smuzhiyun  */
1022*4882a593Smuzhiyun static void
batadv_purge_neigh_ifinfo(struct batadv_priv * bat_priv,struct batadv_neigh_node * neigh)1023*4882a593Smuzhiyun batadv_purge_neigh_ifinfo(struct batadv_priv *bat_priv,
1024*4882a593Smuzhiyun 			  struct batadv_neigh_node *neigh)
1025*4882a593Smuzhiyun {
1026*4882a593Smuzhiyun 	struct batadv_neigh_ifinfo *neigh_ifinfo;
1027*4882a593Smuzhiyun 	struct batadv_hard_iface *if_outgoing;
1028*4882a593Smuzhiyun 	struct hlist_node *node_tmp;
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	spin_lock_bh(&neigh->ifinfo_lock);
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	/* for all ifinfo objects for this neighinator */
1033*4882a593Smuzhiyun 	hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
1034*4882a593Smuzhiyun 				  &neigh->ifinfo_list, list) {
1035*4882a593Smuzhiyun 		if_outgoing = neigh_ifinfo->if_outgoing;
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun 		/* always keep the default interface */
1038*4882a593Smuzhiyun 		if (if_outgoing == BATADV_IF_DEFAULT)
1039*4882a593Smuzhiyun 			continue;
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 		/* don't purge if the interface is not (going) down */
1042*4882a593Smuzhiyun 		if (if_outgoing->if_status != BATADV_IF_INACTIVE &&
1043*4882a593Smuzhiyun 		    if_outgoing->if_status != BATADV_IF_NOT_IN_USE &&
1044*4882a593Smuzhiyun 		    if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)
1045*4882a593Smuzhiyun 			continue;
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1048*4882a593Smuzhiyun 			   "neighbor/ifinfo purge: neighbor %pM, iface: %s\n",
1049*4882a593Smuzhiyun 			   neigh->addr, if_outgoing->net_dev->name);
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 		hlist_del_rcu(&neigh_ifinfo->list);
1052*4882a593Smuzhiyun 		batadv_neigh_ifinfo_put(neigh_ifinfo);
1053*4882a593Smuzhiyun 	}
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	spin_unlock_bh(&neigh->ifinfo_lock);
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun /**
1059*4882a593Smuzhiyun  * batadv_purge_orig_ifinfo() - purge obsolete ifinfo entries from originator
1060*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
1061*4882a593Smuzhiyun  * @orig_node: orig node which is to be checked
1062*4882a593Smuzhiyun  *
1063*4882a593Smuzhiyun  * Return: true if any ifinfo entry was purged, false otherwise.
1064*4882a593Smuzhiyun  */
1065*4882a593Smuzhiyun static bool
batadv_purge_orig_ifinfo(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node)1066*4882a593Smuzhiyun batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
1067*4882a593Smuzhiyun 			 struct batadv_orig_node *orig_node)
1068*4882a593Smuzhiyun {
1069*4882a593Smuzhiyun 	struct batadv_orig_ifinfo *orig_ifinfo;
1070*4882a593Smuzhiyun 	struct batadv_hard_iface *if_outgoing;
1071*4882a593Smuzhiyun 	struct hlist_node *node_tmp;
1072*4882a593Smuzhiyun 	bool ifinfo_purged = false;
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	spin_lock_bh(&orig_node->neigh_list_lock);
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	/* for all ifinfo objects for this originator */
1077*4882a593Smuzhiyun 	hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
1078*4882a593Smuzhiyun 				  &orig_node->ifinfo_list, list) {
1079*4882a593Smuzhiyun 		if_outgoing = orig_ifinfo->if_outgoing;
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun 		/* always keep the default interface */
1082*4882a593Smuzhiyun 		if (if_outgoing == BATADV_IF_DEFAULT)
1083*4882a593Smuzhiyun 			continue;
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 		/* don't purge if the interface is not (going) down */
1086*4882a593Smuzhiyun 		if (if_outgoing->if_status != BATADV_IF_INACTIVE &&
1087*4882a593Smuzhiyun 		    if_outgoing->if_status != BATADV_IF_NOT_IN_USE &&
1088*4882a593Smuzhiyun 		    if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)
1089*4882a593Smuzhiyun 			continue;
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1092*4882a593Smuzhiyun 			   "router/ifinfo purge: originator %pM, iface: %s\n",
1093*4882a593Smuzhiyun 			   orig_node->orig, if_outgoing->net_dev->name);
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun 		ifinfo_purged = true;
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 		hlist_del_rcu(&orig_ifinfo->list);
1098*4882a593Smuzhiyun 		batadv_orig_ifinfo_put(orig_ifinfo);
1099*4882a593Smuzhiyun 		if (orig_node->last_bonding_candidate == orig_ifinfo) {
1100*4882a593Smuzhiyun 			orig_node->last_bonding_candidate = NULL;
1101*4882a593Smuzhiyun 			batadv_orig_ifinfo_put(orig_ifinfo);
1102*4882a593Smuzhiyun 		}
1103*4882a593Smuzhiyun 	}
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 	spin_unlock_bh(&orig_node->neigh_list_lock);
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	return ifinfo_purged;
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun /**
1111*4882a593Smuzhiyun  * batadv_purge_orig_neighbors() - purges neighbors from originator
1112*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
1113*4882a593Smuzhiyun  * @orig_node: orig node which is to be checked
1114*4882a593Smuzhiyun  *
1115*4882a593Smuzhiyun  * Return: true if any neighbor was purged, false otherwise
1116*4882a593Smuzhiyun  */
1117*4882a593Smuzhiyun static bool
batadv_purge_orig_neighbors(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node)1118*4882a593Smuzhiyun batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
1119*4882a593Smuzhiyun 			    struct batadv_orig_node *orig_node)
1120*4882a593Smuzhiyun {
1121*4882a593Smuzhiyun 	struct hlist_node *node_tmp;
1122*4882a593Smuzhiyun 	struct batadv_neigh_node *neigh_node;
1123*4882a593Smuzhiyun 	bool neigh_purged = false;
1124*4882a593Smuzhiyun 	unsigned long last_seen;
1125*4882a593Smuzhiyun 	struct batadv_hard_iface *if_incoming;
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 	spin_lock_bh(&orig_node->neigh_list_lock);
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 	/* for all neighbors towards this originator ... */
1130*4882a593Smuzhiyun 	hlist_for_each_entry_safe(neigh_node, node_tmp,
1131*4882a593Smuzhiyun 				  &orig_node->neigh_list, list) {
1132*4882a593Smuzhiyun 		last_seen = neigh_node->last_seen;
1133*4882a593Smuzhiyun 		if_incoming = neigh_node->if_incoming;
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 		if (batadv_has_timed_out(last_seen, BATADV_PURGE_TIMEOUT) ||
1136*4882a593Smuzhiyun 		    if_incoming->if_status == BATADV_IF_INACTIVE ||
1137*4882a593Smuzhiyun 		    if_incoming->if_status == BATADV_IF_NOT_IN_USE ||
1138*4882a593Smuzhiyun 		    if_incoming->if_status == BATADV_IF_TO_BE_REMOVED) {
1139*4882a593Smuzhiyun 			if (if_incoming->if_status == BATADV_IF_INACTIVE ||
1140*4882a593Smuzhiyun 			    if_incoming->if_status == BATADV_IF_NOT_IN_USE ||
1141*4882a593Smuzhiyun 			    if_incoming->if_status == BATADV_IF_TO_BE_REMOVED)
1142*4882a593Smuzhiyun 				batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1143*4882a593Smuzhiyun 					   "neighbor purge: originator %pM, neighbor: %pM, iface: %s\n",
1144*4882a593Smuzhiyun 					   orig_node->orig, neigh_node->addr,
1145*4882a593Smuzhiyun 					   if_incoming->net_dev->name);
1146*4882a593Smuzhiyun 			else
1147*4882a593Smuzhiyun 				batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1148*4882a593Smuzhiyun 					   "neighbor timeout: originator %pM, neighbor: %pM, last_seen: %u\n",
1149*4882a593Smuzhiyun 					   orig_node->orig, neigh_node->addr,
1150*4882a593Smuzhiyun 					   jiffies_to_msecs(last_seen));
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 			neigh_purged = true;
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 			hlist_del_rcu(&neigh_node->list);
1155*4882a593Smuzhiyun 			batadv_neigh_node_put(neigh_node);
1156*4882a593Smuzhiyun 		} else {
1157*4882a593Smuzhiyun 			/* only necessary if not the whole neighbor is to be
1158*4882a593Smuzhiyun 			 * deleted, but some interface has been removed.
1159*4882a593Smuzhiyun 			 */
1160*4882a593Smuzhiyun 			batadv_purge_neigh_ifinfo(bat_priv, neigh_node);
1161*4882a593Smuzhiyun 		}
1162*4882a593Smuzhiyun 	}
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	spin_unlock_bh(&orig_node->neigh_list_lock);
1165*4882a593Smuzhiyun 	return neigh_purged;
1166*4882a593Smuzhiyun }
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun /**
1169*4882a593Smuzhiyun  * batadv_find_best_neighbor() - finds the best neighbor after purging
1170*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
1171*4882a593Smuzhiyun  * @orig_node: orig node which is to be checked
1172*4882a593Smuzhiyun  * @if_outgoing: the interface for which the metric should be compared
1173*4882a593Smuzhiyun  *
1174*4882a593Smuzhiyun  * Return: the current best neighbor, with refcount increased.
1175*4882a593Smuzhiyun  */
1176*4882a593Smuzhiyun static struct batadv_neigh_node *
batadv_find_best_neighbor(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,struct batadv_hard_iface * if_outgoing)1177*4882a593Smuzhiyun batadv_find_best_neighbor(struct batadv_priv *bat_priv,
1178*4882a593Smuzhiyun 			  struct batadv_orig_node *orig_node,
1179*4882a593Smuzhiyun 			  struct batadv_hard_iface *if_outgoing)
1180*4882a593Smuzhiyun {
1181*4882a593Smuzhiyun 	struct batadv_neigh_node *best = NULL, *neigh;
1182*4882a593Smuzhiyun 	struct batadv_algo_ops *bao = bat_priv->algo_ops;
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	rcu_read_lock();
1185*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list) {
1186*4882a593Smuzhiyun 		if (best && (bao->neigh.cmp(neigh, if_outgoing, best,
1187*4882a593Smuzhiyun 					    if_outgoing) <= 0))
1188*4882a593Smuzhiyun 			continue;
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&neigh->refcount))
1191*4882a593Smuzhiyun 			continue;
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 		if (best)
1194*4882a593Smuzhiyun 			batadv_neigh_node_put(best);
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 		best = neigh;
1197*4882a593Smuzhiyun 	}
1198*4882a593Smuzhiyun 	rcu_read_unlock();
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 	return best;
1201*4882a593Smuzhiyun }
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun /**
1204*4882a593Smuzhiyun  * batadv_purge_orig_node() - purges obsolete information from an orig_node
1205*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
1206*4882a593Smuzhiyun  * @orig_node: orig node which is to be checked
1207*4882a593Smuzhiyun  *
1208*4882a593Smuzhiyun  * This function checks if the orig_node or substructures of it have become
1209*4882a593Smuzhiyun  * obsolete, and purges this information if that's the case.
1210*4882a593Smuzhiyun  *
1211*4882a593Smuzhiyun  * Return: true if the orig_node is to be removed, false otherwise.
1212*4882a593Smuzhiyun  */
batadv_purge_orig_node(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node)1213*4882a593Smuzhiyun static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
1214*4882a593Smuzhiyun 				   struct batadv_orig_node *orig_node)
1215*4882a593Smuzhiyun {
1216*4882a593Smuzhiyun 	struct batadv_neigh_node *best_neigh_node;
1217*4882a593Smuzhiyun 	struct batadv_hard_iface *hard_iface;
1218*4882a593Smuzhiyun 	bool changed_ifinfo, changed_neigh;
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun 	if (batadv_has_timed_out(orig_node->last_seen,
1221*4882a593Smuzhiyun 				 2 * BATADV_PURGE_TIMEOUT)) {
1222*4882a593Smuzhiyun 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1223*4882a593Smuzhiyun 			   "Originator timeout: originator %pM, last_seen %u\n",
1224*4882a593Smuzhiyun 			   orig_node->orig,
1225*4882a593Smuzhiyun 			   jiffies_to_msecs(orig_node->last_seen));
1226*4882a593Smuzhiyun 		return true;
1227*4882a593Smuzhiyun 	}
1228*4882a593Smuzhiyun 	changed_ifinfo = batadv_purge_orig_ifinfo(bat_priv, orig_node);
1229*4882a593Smuzhiyun 	changed_neigh = batadv_purge_orig_neighbors(bat_priv, orig_node);
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 	if (!changed_ifinfo && !changed_neigh)
1232*4882a593Smuzhiyun 		return false;
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	/* first for NULL ... */
1235*4882a593Smuzhiyun 	best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node,
1236*4882a593Smuzhiyun 						    BATADV_IF_DEFAULT);
1237*4882a593Smuzhiyun 	batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
1238*4882a593Smuzhiyun 			    best_neigh_node);
1239*4882a593Smuzhiyun 	if (best_neigh_node)
1240*4882a593Smuzhiyun 		batadv_neigh_node_put(best_neigh_node);
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 	/* ... then for all other interfaces. */
1243*4882a593Smuzhiyun 	rcu_read_lock();
1244*4882a593Smuzhiyun 	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
1245*4882a593Smuzhiyun 		if (hard_iface->if_status != BATADV_IF_ACTIVE)
1246*4882a593Smuzhiyun 			continue;
1247*4882a593Smuzhiyun 
1248*4882a593Smuzhiyun 		if (hard_iface->soft_iface != bat_priv->soft_iface)
1249*4882a593Smuzhiyun 			continue;
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 		if (!kref_get_unless_zero(&hard_iface->refcount))
1252*4882a593Smuzhiyun 			continue;
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 		best_neigh_node = batadv_find_best_neighbor(bat_priv,
1255*4882a593Smuzhiyun 							    orig_node,
1256*4882a593Smuzhiyun 							    hard_iface);
1257*4882a593Smuzhiyun 		batadv_update_route(bat_priv, orig_node, hard_iface,
1258*4882a593Smuzhiyun 				    best_neigh_node);
1259*4882a593Smuzhiyun 		if (best_neigh_node)
1260*4882a593Smuzhiyun 			batadv_neigh_node_put(best_neigh_node);
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 		batadv_hardif_put(hard_iface);
1263*4882a593Smuzhiyun 	}
1264*4882a593Smuzhiyun 	rcu_read_unlock();
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 	return false;
1267*4882a593Smuzhiyun }
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun /**
1270*4882a593Smuzhiyun  * batadv_purge_orig_ref() - Purge all outdated originators
1271*4882a593Smuzhiyun  * @bat_priv: the bat priv with all the soft interface information
1272*4882a593Smuzhiyun  */
batadv_purge_orig_ref(struct batadv_priv * bat_priv)1273*4882a593Smuzhiyun void batadv_purge_orig_ref(struct batadv_priv *bat_priv)
1274*4882a593Smuzhiyun {
1275*4882a593Smuzhiyun 	struct batadv_hashtable *hash = bat_priv->orig_hash;
1276*4882a593Smuzhiyun 	struct hlist_node *node_tmp;
1277*4882a593Smuzhiyun 	struct hlist_head *head;
1278*4882a593Smuzhiyun 	spinlock_t *list_lock; /* spinlock to protect write access */
1279*4882a593Smuzhiyun 	struct batadv_orig_node *orig_node;
1280*4882a593Smuzhiyun 	u32 i;
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	if (!hash)
1283*4882a593Smuzhiyun 		return;
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 	/* for all origins... */
1286*4882a593Smuzhiyun 	for (i = 0; i < hash->size; i++) {
1287*4882a593Smuzhiyun 		head = &hash->table[i];
1288*4882a593Smuzhiyun 		list_lock = &hash->list_locks[i];
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 		spin_lock_bh(list_lock);
1291*4882a593Smuzhiyun 		hlist_for_each_entry_safe(orig_node, node_tmp,
1292*4882a593Smuzhiyun 					  head, hash_entry) {
1293*4882a593Smuzhiyun 			if (batadv_purge_orig_node(bat_priv, orig_node)) {
1294*4882a593Smuzhiyun 				batadv_gw_node_delete(bat_priv, orig_node);
1295*4882a593Smuzhiyun 				hlist_del_rcu(&orig_node->hash_entry);
1296*4882a593Smuzhiyun 				batadv_tt_global_del_orig(orig_node->bat_priv,
1297*4882a593Smuzhiyun 							  orig_node, -1,
1298*4882a593Smuzhiyun 							  "originator timed out");
1299*4882a593Smuzhiyun 				batadv_orig_node_put(orig_node);
1300*4882a593Smuzhiyun 				continue;
1301*4882a593Smuzhiyun 			}
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 			batadv_frag_purge_orig(orig_node,
1304*4882a593Smuzhiyun 					       batadv_frag_check_entry);
1305*4882a593Smuzhiyun 		}
1306*4882a593Smuzhiyun 		spin_unlock_bh(list_lock);
1307*4882a593Smuzhiyun 	}
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	batadv_gw_election(bat_priv);
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun 
batadv_purge_orig(struct work_struct * work)1312*4882a593Smuzhiyun static void batadv_purge_orig(struct work_struct *work)
1313*4882a593Smuzhiyun {
1314*4882a593Smuzhiyun 	struct delayed_work *delayed_work;
1315*4882a593Smuzhiyun 	struct batadv_priv *bat_priv;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	delayed_work = to_delayed_work(work);
1318*4882a593Smuzhiyun 	bat_priv = container_of(delayed_work, struct batadv_priv, orig_work);
1319*4882a593Smuzhiyun 	batadv_purge_orig_ref(bat_priv);
1320*4882a593Smuzhiyun 	queue_delayed_work(batadv_event_workqueue,
1321*4882a593Smuzhiyun 			   &bat_priv->orig_work,
1322*4882a593Smuzhiyun 			   msecs_to_jiffies(BATADV_ORIG_WORK_PERIOD));
1323*4882a593Smuzhiyun }
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun #ifdef CONFIG_BATMAN_ADV_DEBUGFS
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun /**
1328*4882a593Smuzhiyun  * batadv_orig_seq_print_text() - Print the originator table in a seq file
1329*4882a593Smuzhiyun  * @seq: seq file to print on
1330*4882a593Smuzhiyun  * @offset: not used
1331*4882a593Smuzhiyun  *
1332*4882a593Smuzhiyun  * Return: always 0
1333*4882a593Smuzhiyun  */
batadv_orig_seq_print_text(struct seq_file * seq,void * offset)1334*4882a593Smuzhiyun int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
1335*4882a593Smuzhiyun {
1336*4882a593Smuzhiyun 	struct net_device *net_dev = (struct net_device *)seq->private;
1337*4882a593Smuzhiyun 	struct batadv_priv *bat_priv = netdev_priv(net_dev);
1338*4882a593Smuzhiyun 	struct batadv_hard_iface *primary_if;
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 	primary_if = batadv_seq_print_text_primary_if_get(seq);
1341*4882a593Smuzhiyun 	if (!primary_if)
1342*4882a593Smuzhiyun 		return 0;
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun 	seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s %s)]\n",
1345*4882a593Smuzhiyun 		   BATADV_SOURCE_VERSION, primary_if->net_dev->name,
1346*4882a593Smuzhiyun 		   primary_if->net_dev->dev_addr, net_dev->name,
1347*4882a593Smuzhiyun 		   bat_priv->algo_ops->name);
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	batadv_hardif_put(primary_if);
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun 	if (!bat_priv->algo_ops->orig.print) {
1352*4882a593Smuzhiyun 		seq_puts(seq,
1353*4882a593Smuzhiyun 			 "No printing function for this routing protocol\n");
1354*4882a593Smuzhiyun 		return 0;
1355*4882a593Smuzhiyun 	}
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 	bat_priv->algo_ops->orig.print(bat_priv, seq, BATADV_IF_DEFAULT);
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	return 0;
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun /**
1363*4882a593Smuzhiyun  * batadv_orig_hardif_seq_print_text() - writes originator infos for a specific
1364*4882a593Smuzhiyun  *  outgoing interface
1365*4882a593Smuzhiyun  * @seq: debugfs table seq_file struct
1366*4882a593Smuzhiyun  * @offset: not used
1367*4882a593Smuzhiyun  *
1368*4882a593Smuzhiyun  * Return: 0
1369*4882a593Smuzhiyun  */
batadv_orig_hardif_seq_print_text(struct seq_file * seq,void * offset)1370*4882a593Smuzhiyun int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset)
1371*4882a593Smuzhiyun {
1372*4882a593Smuzhiyun 	struct net_device *net_dev = (struct net_device *)seq->private;
1373*4882a593Smuzhiyun 	struct batadv_hard_iface *hard_iface;
1374*4882a593Smuzhiyun 	struct batadv_priv *bat_priv;
1375*4882a593Smuzhiyun 
1376*4882a593Smuzhiyun 	hard_iface = batadv_hardif_get_by_netdev(net_dev);
1377*4882a593Smuzhiyun 
1378*4882a593Smuzhiyun 	if (!hard_iface || !hard_iface->soft_iface) {
1379*4882a593Smuzhiyun 		seq_puts(seq, "Interface not known to B.A.T.M.A.N.\n");
1380*4882a593Smuzhiyun 		goto out;
1381*4882a593Smuzhiyun 	}
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun 	bat_priv = netdev_priv(hard_iface->soft_iface);
1384*4882a593Smuzhiyun 	if (!bat_priv->algo_ops->orig.print) {
1385*4882a593Smuzhiyun 		seq_puts(seq,
1386*4882a593Smuzhiyun 			 "No printing function for this routing protocol\n");
1387*4882a593Smuzhiyun 		goto out;
1388*4882a593Smuzhiyun 	}
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	if (hard_iface->if_status != BATADV_IF_ACTIVE) {
1391*4882a593Smuzhiyun 		seq_puts(seq, "Interface not active\n");
1392*4882a593Smuzhiyun 		goto out;
1393*4882a593Smuzhiyun 	}
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 	seq_printf(seq, "[B.A.T.M.A.N. adv %s, IF/MAC: %s/%pM (%s %s)]\n",
1396*4882a593Smuzhiyun 		   BATADV_SOURCE_VERSION, hard_iface->net_dev->name,
1397*4882a593Smuzhiyun 		   hard_iface->net_dev->dev_addr,
1398*4882a593Smuzhiyun 		   hard_iface->soft_iface->name, bat_priv->algo_ops->name);
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	bat_priv->algo_ops->orig.print(bat_priv, seq, hard_iface);
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun out:
1403*4882a593Smuzhiyun 	if (hard_iface)
1404*4882a593Smuzhiyun 		batadv_hardif_put(hard_iface);
1405*4882a593Smuzhiyun 	return 0;
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun #endif
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun /**
1410*4882a593Smuzhiyun  * batadv_orig_dump() - Dump to netlink the originator infos for a specific
1411*4882a593Smuzhiyun  *  outgoing interface
1412*4882a593Smuzhiyun  * @msg: message to dump into
1413*4882a593Smuzhiyun  * @cb: parameters for the dump
1414*4882a593Smuzhiyun  *
1415*4882a593Smuzhiyun  * Return: 0 or error value
1416*4882a593Smuzhiyun  */
batadv_orig_dump(struct sk_buff * msg,struct netlink_callback * cb)1417*4882a593Smuzhiyun int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb)
1418*4882a593Smuzhiyun {
1419*4882a593Smuzhiyun 	struct net *net = sock_net(cb->skb->sk);
1420*4882a593Smuzhiyun 	struct net_device *soft_iface;
1421*4882a593Smuzhiyun 	struct net_device *hard_iface = NULL;
1422*4882a593Smuzhiyun 	struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT;
1423*4882a593Smuzhiyun 	struct batadv_priv *bat_priv;
1424*4882a593Smuzhiyun 	struct batadv_hard_iface *primary_if = NULL;
1425*4882a593Smuzhiyun 	int ret;
1426*4882a593Smuzhiyun 	int ifindex, hard_ifindex;
1427*4882a593Smuzhiyun 
1428*4882a593Smuzhiyun 	ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
1429*4882a593Smuzhiyun 	if (!ifindex)
1430*4882a593Smuzhiyun 		return -EINVAL;
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun 	soft_iface = dev_get_by_index(net, ifindex);
1433*4882a593Smuzhiyun 	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
1434*4882a593Smuzhiyun 		ret = -ENODEV;
1435*4882a593Smuzhiyun 		goto out;
1436*4882a593Smuzhiyun 	}
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 	bat_priv = netdev_priv(soft_iface);
1439*4882a593Smuzhiyun 
1440*4882a593Smuzhiyun 	primary_if = batadv_primary_if_get_selected(bat_priv);
1441*4882a593Smuzhiyun 	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
1442*4882a593Smuzhiyun 		ret = -ENOENT;
1443*4882a593Smuzhiyun 		goto out;
1444*4882a593Smuzhiyun 	}
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 	hard_ifindex = batadv_netlink_get_ifindex(cb->nlh,
1447*4882a593Smuzhiyun 						  BATADV_ATTR_HARD_IFINDEX);
1448*4882a593Smuzhiyun 	if (hard_ifindex) {
1449*4882a593Smuzhiyun 		hard_iface = dev_get_by_index(net, hard_ifindex);
1450*4882a593Smuzhiyun 		if (hard_iface)
1451*4882a593Smuzhiyun 			hardif = batadv_hardif_get_by_netdev(hard_iface);
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun 		if (!hardif) {
1454*4882a593Smuzhiyun 			ret = -ENODEV;
1455*4882a593Smuzhiyun 			goto out;
1456*4882a593Smuzhiyun 		}
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 		if (hardif->soft_iface != soft_iface) {
1459*4882a593Smuzhiyun 			ret = -ENOENT;
1460*4882a593Smuzhiyun 			goto out;
1461*4882a593Smuzhiyun 		}
1462*4882a593Smuzhiyun 	}
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 	if (!bat_priv->algo_ops->orig.dump) {
1465*4882a593Smuzhiyun 		ret = -EOPNOTSUPP;
1466*4882a593Smuzhiyun 		goto out;
1467*4882a593Smuzhiyun 	}
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	bat_priv->algo_ops->orig.dump(msg, cb, bat_priv, hardif);
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	ret = msg->len;
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun  out:
1474*4882a593Smuzhiyun 	if (hardif)
1475*4882a593Smuzhiyun 		batadv_hardif_put(hardif);
1476*4882a593Smuzhiyun 	if (hard_iface)
1477*4882a593Smuzhiyun 		dev_put(hard_iface);
1478*4882a593Smuzhiyun 	if (primary_if)
1479*4882a593Smuzhiyun 		batadv_hardif_put(primary_if);
1480*4882a593Smuzhiyun 	if (soft_iface)
1481*4882a593Smuzhiyun 		dev_put(soft_iface);
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 	return ret;
1484*4882a593Smuzhiyun }
1485