blob: 45db798a7297d9f6d4be2d9c061bd2f37377c120 [file] [log] [blame]
Sven Eckelmann7db7d9f2017-11-19 15:05:11 +01001// SPDX-License-Identifier: GPL-2.0
Sven Eckelmann7a79d712018-12-31 23:59:59 +01002/* Copyright (C) 2009-2019 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00003 *
4 * Marek Lindner, Simon Wunderlich
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00005 */
6
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00007#include "originator.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +02008#include "main.h"
9
Sven Eckelmann7c124392016-01-16 10:29:56 +010010#include <linux/atomic.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020011#include <linux/errno.h>
12#include <linux/etherdevice.h>
Sven Eckelmannb92b94a2017-11-19 17:12:02 +010013#include <linux/gfp.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020014#include <linux/jiffies.h>
15#include <linux/kernel.h>
Sven Eckelmann90f564d2016-01-16 10:29:40 +010016#include <linux/kref.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020017#include <linux/list.h>
18#include <linux/lockdep.h>
19#include <linux/netdevice.h>
Matthias Schiffer85cf8c82016-07-03 13:31:39 +020020#include <linux/netlink.h>
Marek Lindnerd0fa4f32015-06-22 00:30:22 +080021#include <linux/rculist.h>
Denys Vlasenko3326afe2017-11-19 17:59:13 +010022#include <linux/rcupdate.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020023#include <linux/seq_file.h>
Matthias Schiffer85cf8c82016-07-03 13:31:39 +020024#include <linux/skbuff.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020025#include <linux/slab.h>
26#include <linux/spinlock.h>
Denys Vlasenko3326afe2017-11-19 17:59:13 +010027#include <linux/stddef.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020028#include <linux/workqueue.h>
Matthias Schiffer85cf8c82016-07-03 13:31:39 +020029#include <net/sock.h>
30#include <uapi/linux/batman_adv.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020031
Sven Eckelmann01d350d2016-05-15 11:07:44 +020032#include "bat_algo.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020033#include "distributed-arp-table.h"
34#include "fragmentation.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000035#include "gateway_client.h"
36#include "hard-interface.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020037#include "hash.h"
Sven Eckelmannba412082016-05-15 23:48:31 +020038#include "log.h"
Linus Lüssing60432d72014-02-15 17:47:51 +010039#include "multicast.h"
Matthias Schiffer85cf8c82016-07-03 13:31:39 +020040#include "netlink.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020041#include "network-coding.h"
42#include "routing.h"
Matthias Schiffer85cf8c82016-07-03 13:31:39 +020043#include "soft-interface.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020044#include "translation-table.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000045
Antonio Quartullidec05072012-11-10 11:00:32 +010046/* hash class keys */
47static struct lock_class_key batadv_orig_hash_lock_class_key;
48
Sven Eckelmannff15c272017-12-02 19:51:53 +010049/**
50 * batadv_orig_hash_find() - Find and return originator from orig_hash
51 * @bat_priv: the bat priv with all the soft interface information
52 * @data: mac address of the originator
53 *
54 * Return: orig_node (with increased refcnt), NULL on errors
55 */
Denys Vlasenko3326afe2017-11-19 17:59:13 +010056struct batadv_orig_node *
57batadv_orig_hash_find(struct batadv_priv *bat_priv, const void *data)
58{
59 struct batadv_hashtable *hash = bat_priv->orig_hash;
60 struct hlist_head *head;
61 struct batadv_orig_node *orig_node, *orig_node_tmp = NULL;
62 int index;
63
64 if (!hash)
65 return NULL;
66
67 index = batadv_choose_orig(data, hash->size);
68 head = &hash->table[index];
69
70 rcu_read_lock();
71 hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
72 if (!batadv_compare_eth(orig_node, data))
73 continue;
74
75 if (!kref_get_unless_zero(&orig_node->refcount))
76 continue;
77
78 orig_node_tmp = orig_node;
79 break;
80 }
81 rcu_read_unlock();
82
83 return orig_node_tmp;
84}
85
Sven Eckelmann03fc7f82012-05-12 18:34:00 +020086static void batadv_purge_orig(struct work_struct *work);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000087
Sven Eckelmann62fe7102015-09-15 19:00:48 +020088/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +010089 * batadv_compare_orig() - comparing function used in the originator hash table
Sven Eckelmann7afcbbe2015-10-31 12:29:29 +010090 * @node: node in the local table
91 * @data2: second object to compare the node to
Sven Eckelmann62fe7102015-09-15 19:00:48 +020092 *
Sven Eckelmann4b426b12016-02-22 21:02:39 +010093 * Return: true if they are the same originator
Sven Eckelmann62fe7102015-09-15 19:00:48 +020094 */
Sven Eckelmann4b426b12016-02-22 21:02:39 +010095bool batadv_compare_orig(const struct hlist_node *node, const void *data2)
Sven Eckelmannb8e2dd12011-06-15 15:08:59 +020096{
Sven Eckelmann56303d32012-06-05 22:31:31 +020097 const void *data1 = container_of(node, struct batadv_orig_node,
98 hash_entry);
Sven Eckelmannb8e2dd12011-06-15 15:08:59 +020099
dingtianhong323813e2013-12-26 19:40:39 +0800100 return batadv_compare_eth(data1, data2);
Sven Eckelmannb8e2dd12011-06-15 15:08:59 +0200101}
102
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200103/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100104 * batadv_orig_node_vlan_get() - get an orig_node_vlan object
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200105 * @orig_node: the originator serving the VLAN
106 * @vid: the VLAN identifier
107 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200108 * Return: the vlan object identified by vid and belonging to orig_node or NULL
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200109 * if it does not exist.
110 */
111struct batadv_orig_node_vlan *
112batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,
113 unsigned short vid)
114{
115 struct batadv_orig_node_vlan *vlan = NULL, *tmp;
116
117 rcu_read_lock();
Marek Lindnerd0fa4f32015-06-22 00:30:22 +0800118 hlist_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200119 if (tmp->vid != vid)
120 continue;
121
Sven Eckelmann161a3be2016-01-16 10:29:55 +0100122 if (!kref_get_unless_zero(&tmp->refcount))
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200123 continue;
124
125 vlan = tmp;
126
127 break;
128 }
129 rcu_read_unlock();
130
131 return vlan;
132}
133
134/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100135 * batadv_orig_node_vlan_new() - search and possibly create an orig_node_vlan
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200136 * object
137 * @orig_node: the originator serving the VLAN
138 * @vid: the VLAN identifier
139 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200140 * Return: NULL in case of failure or the vlan object identified by vid and
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200141 * belonging to orig_node otherwise. The object is created and added to the list
142 * if it does not exist.
143 *
144 * The object is returned with refcounter increased by 1.
145 */
146struct batadv_orig_node_vlan *
147batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
148 unsigned short vid)
149{
150 struct batadv_orig_node_vlan *vlan;
151
152 spin_lock_bh(&orig_node->vlan_list_lock);
153
154 /* first look if an object for this vid already exists */
155 vlan = batadv_orig_node_vlan_get(orig_node, vid);
156 if (vlan)
157 goto out;
158
159 vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
160 if (!vlan)
161 goto out;
162
Sven Eckelmann161a3be2016-01-16 10:29:55 +0100163 kref_init(&vlan->refcount);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200164 vlan->vid = vid;
165
Sven Eckelmann09537d12016-07-15 17:39:16 +0200166 kref_get(&vlan->refcount);
Marek Lindnerd0fa4f32015-06-22 00:30:22 +0800167 hlist_add_head_rcu(&vlan->list, &orig_node->vlan_list);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200168
169out:
170 spin_unlock_bh(&orig_node->vlan_list_lock);
171
172 return vlan;
173}
174
175/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100176 * batadv_orig_node_vlan_release() - release originator-vlan object from lists
Sven Eckelmann161a3be2016-01-16 10:29:55 +0100177 * and queue for free after rcu grace period
178 * @ref: kref pointer of the originator-vlan object
179 */
180static void batadv_orig_node_vlan_release(struct kref *ref)
181{
182 struct batadv_orig_node_vlan *orig_vlan;
183
184 orig_vlan = container_of(ref, struct batadv_orig_node_vlan, refcount);
185
186 kfree_rcu(orig_vlan, rcu);
187}
188
189/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100190 * batadv_orig_node_vlan_put() - decrement the refcounter and possibly release
Sven Eckelmann21754e22016-01-17 11:01:24 +0100191 * the originator-vlan object
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200192 * @orig_vlan: the originator-vlan object to release
193 */
Sven Eckelmann21754e22016-01-17 11:01:24 +0100194void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan)
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200195{
Sven Eckelmann161a3be2016-01-16 10:29:55 +0100196 kref_put(&orig_vlan->refcount, batadv_orig_node_vlan_release);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200197}
198
Sven Eckelmannff15c272017-12-02 19:51:53 +0100199/**
200 * batadv_originator_init() - Initialize all originator structures
201 * @bat_priv: the bat priv with all the soft interface information
202 *
203 * Return: 0 on success or negative error number in case of failure
204 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200205int batadv_originator_init(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000206{
207 if (bat_priv->orig_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200208 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000209
Sven Eckelmann1a8eaf02012-05-12 02:09:32 +0200210 bat_priv->orig_hash = batadv_hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000211
212 if (!bat_priv->orig_hash)
213 goto err;
214
Antonio Quartullidec05072012-11-10 11:00:32 +0100215 batadv_hash_set_lock_class(bat_priv->orig_hash,
216 &batadv_orig_hash_lock_class_key);
217
Antonio Quartulli72414442012-12-25 13:14:37 +0100218 INIT_DELAYED_WORK(&bat_priv->orig_work, batadv_purge_orig);
219 queue_delayed_work(batadv_event_workqueue,
220 &bat_priv->orig_work,
221 msecs_to_jiffies(BATADV_ORIG_WORK_PERIOD));
222
Sven Eckelmann5346c352012-05-05 13:27:28 +0200223 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000224
225err:
Sven Eckelmann5346c352012-05-05 13:27:28 +0200226 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000227}
228
Simon Wunderlich89652332013-11-13 19:14:46 +0100229/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100230 * batadv_neigh_ifinfo_release() - release neigh_ifinfo from lists and queue for
Sven Eckelmannae3e1e32016-01-05 12:06:24 +0100231 * free after rcu grace period
Sven Eckelmann962c6832016-01-16 10:29:51 +0100232 * @ref: kref pointer of the neigh_ifinfo
Simon Wunderlich89652332013-11-13 19:14:46 +0100233 */
Sven Eckelmann962c6832016-01-16 10:29:51 +0100234static void batadv_neigh_ifinfo_release(struct kref *ref)
Simon Wunderlich89652332013-11-13 19:14:46 +0100235{
Sven Eckelmann962c6832016-01-16 10:29:51 +0100236 struct batadv_neigh_ifinfo *neigh_ifinfo;
237
238 neigh_ifinfo = container_of(ref, struct batadv_neigh_ifinfo, refcount);
239
Sven Eckelmannae3e1e32016-01-05 12:06:24 +0100240 if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
Sven Eckelmann82047ad2016-01-17 11:01:10 +0100241 batadv_hardif_put(neigh_ifinfo->if_outgoing);
Sven Eckelmannae3e1e32016-01-05 12:06:24 +0100242
243 kfree_rcu(neigh_ifinfo, rcu);
Simon Wunderlich89652332013-11-13 19:14:46 +0100244}
245
246/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100247 * batadv_neigh_ifinfo_put() - decrement the refcounter and possibly release
Simon Wunderlich89652332013-11-13 19:14:46 +0100248 * the neigh_ifinfo
249 * @neigh_ifinfo: the neigh_ifinfo object to release
250 */
Sven Eckelmann044fa3a2016-01-17 11:01:12 +0100251void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo)
Simon Wunderlich89652332013-11-13 19:14:46 +0100252{
Sven Eckelmann962c6832016-01-16 10:29:51 +0100253 kref_put(&neigh_ifinfo->refcount, batadv_neigh_ifinfo_release);
Simon Wunderlich89652332013-11-13 19:14:46 +0100254}
255
256/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100257 * batadv_hardif_neigh_release() - release hardif neigh node from lists and
Sven Eckelmannf6389692016-01-05 12:06:23 +0100258 * queue for free after rcu grace period
Sven Eckelmann90f564d2016-01-16 10:29:40 +0100259 * @ref: kref pointer of the neigh_node
Marek Lindnercef63412015-08-04 21:09:55 +0800260 */
Sven Eckelmann90f564d2016-01-16 10:29:40 +0100261static void batadv_hardif_neigh_release(struct kref *ref)
Marek Lindnercef63412015-08-04 21:09:55 +0800262{
Sven Eckelmann90f564d2016-01-16 10:29:40 +0100263 struct batadv_hardif_neigh_node *hardif_neigh;
264
265 hardif_neigh = container_of(ref, struct batadv_hardif_neigh_node,
266 refcount);
267
Sven Eckelmannf6389692016-01-05 12:06:23 +0100268 spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
269 hlist_del_init_rcu(&hardif_neigh->list);
270 spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
Sven Eckelmannbab7c6c2016-01-05 12:06:17 +0100271
Sven Eckelmann82047ad2016-01-17 11:01:10 +0100272 batadv_hardif_put(hardif_neigh->if_incoming);
Sven Eckelmannf6389692016-01-05 12:06:23 +0100273 kfree_rcu(hardif_neigh, rcu);
Marek Lindnercef63412015-08-04 21:09:55 +0800274}
275
276/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100277 * batadv_hardif_neigh_put() - decrement the hardif neighbors refcounter
Sven Eckelmannf6389692016-01-05 12:06:23 +0100278 * and possibly release it
Marek Lindnercef63412015-08-04 21:09:55 +0800279 * @hardif_neigh: hardif neigh neighbor to free
280 */
Sven Eckelmannaccadc32016-01-17 11:01:14 +0100281void batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh)
Marek Lindnercef63412015-08-04 21:09:55 +0800282{
Sven Eckelmann90f564d2016-01-16 10:29:40 +0100283 kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release);
Marek Lindnercef63412015-08-04 21:09:55 +0800284}
285
286/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100287 * batadv_neigh_node_release() - release neigh_node from lists and queue for
Sven Eckelmannb4d922c2016-01-05 12:06:25 +0100288 * free after rcu grace period
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100289 * @ref: kref pointer of the neigh_node
Simon Wunderlich89652332013-11-13 19:14:46 +0100290 */
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100291static void batadv_neigh_node_release(struct kref *ref)
Simon Wunderlich89652332013-11-13 19:14:46 +0100292{
293 struct hlist_node *node_tmp;
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100294 struct batadv_neigh_node *neigh_node;
Simon Wunderlich89652332013-11-13 19:14:46 +0100295 struct batadv_neigh_ifinfo *neigh_ifinfo;
296
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100297 neigh_node = container_of(ref, struct batadv_neigh_node, refcount);
Simon Wunderlich89652332013-11-13 19:14:46 +0100298
299 hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
300 &neigh_node->ifinfo_list, list) {
Sven Eckelmann044fa3a2016-01-17 11:01:12 +0100301 batadv_neigh_ifinfo_put(neigh_ifinfo);
Simon Wunderlich89652332013-11-13 19:14:46 +0100302 }
Antonio Quartullibcef1f32015-03-01 00:50:17 +0800303
Sven Eckelmannabe59c62016-03-11 16:44:06 +0100304 batadv_hardif_neigh_put(neigh_node->hardif_neigh);
Marek Lindnercef63412015-08-04 21:09:55 +0800305
Sven Eckelmann82047ad2016-01-17 11:01:10 +0100306 batadv_hardif_put(neigh_node->if_incoming);
Simon Wunderlich89652332013-11-13 19:14:46 +0100307
Sven Eckelmannb4d922c2016-01-05 12:06:25 +0100308 kfree_rcu(neigh_node, rcu);
Simon Wunderlich89652332013-11-13 19:14:46 +0100309}
310
311/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100312 * batadv_neigh_node_put() - decrement the neighbors refcounter and possibly
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100313 * release it
Simon Wunderlich89652332013-11-13 19:14:46 +0100314 * @neigh_node: neigh neighbor to free
315 */
Sven Eckelmann25bb2502016-01-17 11:01:11 +0100316void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node)
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000317{
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100318 kref_put(&neigh_node->refcount, batadv_neigh_node_release);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000319}
320
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100321/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100322 * batadv_orig_router_get() - router to the originator depending on iface
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100323 * @orig_node: the orig node for the router
324 * @if_outgoing: the interface where the payload packet has been received or
325 * the OGM should be sent to
326 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200327 * Return: the neighbor which should be router for this orig_node/iface.
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100328 *
329 * The object is returned with refcounter increased by 1.
330 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200331struct batadv_neigh_node *
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100332batadv_orig_router_get(struct batadv_orig_node *orig_node,
333 const struct batadv_hard_iface *if_outgoing)
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000334{
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100335 struct batadv_orig_ifinfo *orig_ifinfo;
336 struct batadv_neigh_node *router = NULL;
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000337
338 rcu_read_lock();
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100339 hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) {
340 if (orig_ifinfo->if_outgoing != if_outgoing)
341 continue;
342
343 router = rcu_dereference(orig_ifinfo->router);
344 break;
345 }
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000346
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100347 if (router && !kref_get_unless_zero(&router->refcount))
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000348 router = NULL;
349
350 rcu_read_unlock();
351 return router;
352}
353
Antonio Quartulli0538f752013-09-02 12:15:01 +0200354/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100355 * batadv_orig_ifinfo_get() - find the ifinfo from an orig_node
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100356 * @orig_node: the orig node to be queried
357 * @if_outgoing: the interface for which the ifinfo should be acquired
358 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200359 * Return: the requested orig_ifinfo or NULL if not found.
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100360 *
361 * The object is returned with refcounter increased by 1.
362 */
363struct batadv_orig_ifinfo *
364batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
365 struct batadv_hard_iface *if_outgoing)
366{
367 struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL;
368
369 rcu_read_lock();
370 hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list,
371 list) {
372 if (tmp->if_outgoing != if_outgoing)
373 continue;
374
Sven Eckelmanna6ba0d32016-01-16 10:29:52 +0100375 if (!kref_get_unless_zero(&tmp->refcount))
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100376 continue;
377
378 orig_ifinfo = tmp;
379 break;
380 }
381 rcu_read_unlock();
382
383 return orig_ifinfo;
384}
385
386/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100387 * batadv_orig_ifinfo_new() - search and possibly create an orig_ifinfo object
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100388 * @orig_node: the orig node to be queried
389 * @if_outgoing: the interface for which the ifinfo should be acquired
390 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200391 * Return: NULL in case of failure or the orig_ifinfo object for the if_outgoing
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100392 * interface otherwise. The object is created and added to the list
393 * if it does not exist.
394 *
395 * The object is returned with refcounter increased by 1.
396 */
397struct batadv_orig_ifinfo *
398batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
399 struct batadv_hard_iface *if_outgoing)
400{
Sven Eckelmann422d2f72016-07-25 00:42:44 +0200401 struct batadv_orig_ifinfo *orig_ifinfo;
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100402 unsigned long reset_time;
403
404 spin_lock_bh(&orig_node->neigh_list_lock);
405
406 orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing);
407 if (orig_ifinfo)
408 goto out;
409
410 orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC);
411 if (!orig_ifinfo)
412 goto out;
413
Sven Eckelmann17a86912016-04-11 13:06:40 +0200414 if (if_outgoing != BATADV_IF_DEFAULT)
415 kref_get(&if_outgoing->refcount);
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100416
417 reset_time = jiffies - 1;
418 reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
419 orig_ifinfo->batman_seqno_reset = reset_time;
420 orig_ifinfo->if_outgoing = if_outgoing;
421 INIT_HLIST_NODE(&orig_ifinfo->list);
Sven Eckelmanna6ba0d32016-01-16 10:29:52 +0100422 kref_init(&orig_ifinfo->refcount);
Sven Eckelmannf257b992016-07-15 17:39:17 +0200423
Sven Eckelmanna6ba0d32016-01-16 10:29:52 +0100424 kref_get(&orig_ifinfo->refcount);
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100425 hlist_add_head_rcu(&orig_ifinfo->list,
426 &orig_node->ifinfo_list);
427out:
428 spin_unlock_bh(&orig_node->neigh_list_lock);
429 return orig_ifinfo;
430}
431
432/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100433 * batadv_neigh_ifinfo_get() - find the ifinfo from an neigh_node
Sven Eckelmanne51f0392015-09-06 21:38:51 +0200434 * @neigh: the neigh node to be queried
Simon Wunderlich89652332013-11-13 19:14:46 +0100435 * @if_outgoing: the interface for which the ifinfo should be acquired
436 *
437 * The object is returned with refcounter increased by 1.
438 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200439 * Return: the requested neigh_ifinfo or NULL if not found
Simon Wunderlich89652332013-11-13 19:14:46 +0100440 */
441struct batadv_neigh_ifinfo *
442batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
443 struct batadv_hard_iface *if_outgoing)
444{
445 struct batadv_neigh_ifinfo *neigh_ifinfo = NULL,
446 *tmp_neigh_ifinfo;
447
448 rcu_read_lock();
449 hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list,
450 list) {
451 if (tmp_neigh_ifinfo->if_outgoing != if_outgoing)
452 continue;
453
Sven Eckelmann962c6832016-01-16 10:29:51 +0100454 if (!kref_get_unless_zero(&tmp_neigh_ifinfo->refcount))
Simon Wunderlich89652332013-11-13 19:14:46 +0100455 continue;
456
457 neigh_ifinfo = tmp_neigh_ifinfo;
458 break;
459 }
460 rcu_read_unlock();
461
462 return neigh_ifinfo;
463}
464
465/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100466 * batadv_neigh_ifinfo_new() - search and possibly create an neigh_ifinfo object
Sven Eckelmanne51f0392015-09-06 21:38:51 +0200467 * @neigh: the neigh node to be queried
Simon Wunderlich89652332013-11-13 19:14:46 +0100468 * @if_outgoing: the interface for which the ifinfo should be acquired
469 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200470 * Return: NULL in case of failure or the neigh_ifinfo object for the
Simon Wunderlich89652332013-11-13 19:14:46 +0100471 * if_outgoing interface otherwise. The object is created and added to the list
472 * if it does not exist.
473 *
474 * The object is returned with refcounter increased by 1.
475 */
476struct batadv_neigh_ifinfo *
477batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
478 struct batadv_hard_iface *if_outgoing)
479{
480 struct batadv_neigh_ifinfo *neigh_ifinfo;
481
482 spin_lock_bh(&neigh->ifinfo_lock);
483
484 neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing);
485 if (neigh_ifinfo)
486 goto out;
487
488 neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC);
489 if (!neigh_ifinfo)
490 goto out;
491
Sven Eckelmann17a86912016-04-11 13:06:40 +0200492 if (if_outgoing)
493 kref_get(&if_outgoing->refcount);
Simon Wunderlich89652332013-11-13 19:14:46 +0100494
495 INIT_HLIST_NODE(&neigh_ifinfo->list);
Sven Eckelmann962c6832016-01-16 10:29:51 +0100496 kref_init(&neigh_ifinfo->refcount);
Simon Wunderlich89652332013-11-13 19:14:46 +0100497 neigh_ifinfo->if_outgoing = if_outgoing;
498
Sven Eckelmann2e774ac2016-07-15 17:39:19 +0200499 kref_get(&neigh_ifinfo->refcount);
Simon Wunderlich89652332013-11-13 19:14:46 +0100500 hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list);
501
502out:
503 spin_unlock_bh(&neigh->ifinfo_lock);
504
505 return neigh_ifinfo;
506}
507
508/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100509 * batadv_neigh_node_get() - retrieve a neighbour from the list
Marek Lindnered292662015-08-04 23:31:44 +0800510 * @orig_node: originator which the neighbour belongs to
511 * @hard_iface: the interface where this neighbour is connected to
512 * @addr: the address of the neighbour
513 *
514 * Looks for and possibly returns a neighbour belonging to this originator list
515 * which is connected through the provided hard interface.
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200516 *
517 * Return: neighbor when found. Othwerwise NULL
Marek Lindnered292662015-08-04 23:31:44 +0800518 */
519static struct batadv_neigh_node *
520batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
521 const struct batadv_hard_iface *hard_iface,
522 const u8 *addr)
523{
524 struct batadv_neigh_node *tmp_neigh_node, *res = NULL;
525
526 rcu_read_lock();
527 hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) {
528 if (!batadv_compare_eth(tmp_neigh_node->addr, addr))
529 continue;
530
531 if (tmp_neigh_node->if_incoming != hard_iface)
532 continue;
533
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100534 if (!kref_get_unless_zero(&tmp_neigh_node->refcount))
Marek Lindnered292662015-08-04 23:31:44 +0800535 continue;
536
537 res = tmp_neigh_node;
538 break;
539 }
540 rcu_read_unlock();
541
542 return res;
543}
544
545/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100546 * batadv_hardif_neigh_create() - create a hardif neighbour node
Marek Lindnercef63412015-08-04 21:09:55 +0800547 * @hard_iface: the interface this neighbour is connected to
548 * @neigh_addr: the interface address of the neighbour to retrieve
Linus Lüssing3111bee2016-08-07 12:34:19 +0200549 * @orig_node: originator object representing the neighbour
Marek Lindnercef63412015-08-04 21:09:55 +0800550 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200551 * Return: the hardif neighbour node if found or created or NULL otherwise.
Marek Lindnercef63412015-08-04 21:09:55 +0800552 */
553static struct batadv_hardif_neigh_node *
554batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
Linus Lüssing3111bee2016-08-07 12:34:19 +0200555 const u8 *neigh_addr,
556 struct batadv_orig_node *orig_node)
Marek Lindnercef63412015-08-04 21:09:55 +0800557{
Marek Lindner8248a4c2015-08-04 21:09:56 +0800558 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
Sven Eckelmann422d2f72016-07-25 00:42:44 +0200559 struct batadv_hardif_neigh_node *hardif_neigh;
Marek Lindnercef63412015-08-04 21:09:55 +0800560
561 spin_lock_bh(&hard_iface->neigh_list_lock);
562
563 /* check if neighbor hasn't been added in the meantime */
564 hardif_neigh = batadv_hardif_neigh_get(hard_iface, neigh_addr);
565 if (hardif_neigh)
566 goto out;
567
Marek Lindnercef63412015-08-04 21:09:55 +0800568 hardif_neigh = kzalloc(sizeof(*hardif_neigh), GFP_ATOMIC);
Sven Eckelmann17a86912016-04-11 13:06:40 +0200569 if (!hardif_neigh)
Marek Lindnercef63412015-08-04 21:09:55 +0800570 goto out;
Marek Lindnercef63412015-08-04 21:09:55 +0800571
Sven Eckelmann17a86912016-04-11 13:06:40 +0200572 kref_get(&hard_iface->refcount);
Marek Lindnercef63412015-08-04 21:09:55 +0800573 INIT_HLIST_NODE(&hardif_neigh->list);
574 ether_addr_copy(hardif_neigh->addr, neigh_addr);
Linus Lüssing3111bee2016-08-07 12:34:19 +0200575 ether_addr_copy(hardif_neigh->orig, orig_node->orig);
Marek Lindnercef63412015-08-04 21:09:55 +0800576 hardif_neigh->if_incoming = hard_iface;
577 hardif_neigh->last_seen = jiffies;
578
Sven Eckelmann90f564d2016-01-16 10:29:40 +0100579 kref_init(&hardif_neigh->refcount);
Marek Lindnercef63412015-08-04 21:09:55 +0800580
Antonio Quartulli29824a52016-05-25 23:27:31 +0800581 if (bat_priv->algo_ops->neigh.hardif_init)
582 bat_priv->algo_ops->neigh.hardif_init(hardif_neigh);
Marek Lindner8248a4c2015-08-04 21:09:56 +0800583
Sven Eckelmann9ca488d2016-09-29 17:22:58 +0200584 hlist_add_head_rcu(&hardif_neigh->list, &hard_iface->neigh_list);
Marek Lindnercef63412015-08-04 21:09:55 +0800585
586out:
587 spin_unlock_bh(&hard_iface->neigh_list_lock);
588 return hardif_neigh;
589}
590
591/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100592 * batadv_hardif_neigh_get_or_create() - retrieve or create a hardif neighbour
Marek Lindnercef63412015-08-04 21:09:55 +0800593 * node
594 * @hard_iface: the interface this neighbour is connected to
595 * @neigh_addr: the interface address of the neighbour to retrieve
Linus Lüssing3111bee2016-08-07 12:34:19 +0200596 * @orig_node: originator object representing the neighbour
Marek Lindnercef63412015-08-04 21:09:55 +0800597 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200598 * Return: the hardif neighbour node if found or created or NULL otherwise.
Marek Lindnercef63412015-08-04 21:09:55 +0800599 */
600static struct batadv_hardif_neigh_node *
601batadv_hardif_neigh_get_or_create(struct batadv_hard_iface *hard_iface,
Linus Lüssing3111bee2016-08-07 12:34:19 +0200602 const u8 *neigh_addr,
603 struct batadv_orig_node *orig_node)
Marek Lindnercef63412015-08-04 21:09:55 +0800604{
Sven Eckelmann422d2f72016-07-25 00:42:44 +0200605 struct batadv_hardif_neigh_node *hardif_neigh;
Marek Lindnercef63412015-08-04 21:09:55 +0800606
607 /* first check without locking to avoid the overhead */
608 hardif_neigh = batadv_hardif_neigh_get(hard_iface, neigh_addr);
609 if (hardif_neigh)
610 return hardif_neigh;
611
Linus Lüssing3111bee2016-08-07 12:34:19 +0200612 return batadv_hardif_neigh_create(hard_iface, neigh_addr, orig_node);
Marek Lindnercef63412015-08-04 21:09:55 +0800613}
614
615/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100616 * batadv_hardif_neigh_get() - retrieve a hardif neighbour from the list
Marek Lindnercef63412015-08-04 21:09:55 +0800617 * @hard_iface: the interface where this neighbour is connected to
618 * @neigh_addr: the address of the neighbour
619 *
620 * Looks for and possibly returns a neighbour belonging to this hard interface.
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200621 *
622 * Return: neighbor when found. Othwerwise NULL
Marek Lindnercef63412015-08-04 21:09:55 +0800623 */
624struct batadv_hardif_neigh_node *
625batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface,
626 const u8 *neigh_addr)
627{
628 struct batadv_hardif_neigh_node *tmp_hardif_neigh, *hardif_neigh = NULL;
629
630 rcu_read_lock();
631 hlist_for_each_entry_rcu(tmp_hardif_neigh,
632 &hard_iface->neigh_list, list) {
633 if (!batadv_compare_eth(tmp_hardif_neigh->addr, neigh_addr))
634 continue;
635
Sven Eckelmann90f564d2016-01-16 10:29:40 +0100636 if (!kref_get_unless_zero(&tmp_hardif_neigh->refcount))
Marek Lindnercef63412015-08-04 21:09:55 +0800637 continue;
638
639 hardif_neigh = tmp_hardif_neigh;
640 break;
641 }
642 rcu_read_unlock();
643
644 return hardif_neigh;
645}
646
647/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100648 * batadv_neigh_node_create() - create a neigh node object
Marek Lindner3f32f8a2015-07-26 04:59:15 +0800649 * @orig_node: originator object representing the neighbour
Antonio Quartulli0538f752013-09-02 12:15:01 +0200650 * @hard_iface: the interface where the neighbour is connected to
651 * @neigh_addr: the mac address of the neighbour interface
Antonio Quartulli0538f752013-09-02 12:15:01 +0200652 *
653 * Allocates a new neigh_node object and initialises all the generic fields.
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200654 *
Marek Lindner6f0a6b52016-05-03 01:52:08 +0800655 * Return: the neighbour node if found or created or NULL otherwise.
Antonio Quartulli0538f752013-09-02 12:15:01 +0200656 */
Marek Lindner6f0a6b52016-05-03 01:52:08 +0800657static struct batadv_neigh_node *
658batadv_neigh_node_create(struct batadv_orig_node *orig_node,
659 struct batadv_hard_iface *hard_iface,
660 const u8 *neigh_addr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000661{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200662 struct batadv_neigh_node *neigh_node;
Marek Lindnercef63412015-08-04 21:09:55 +0800663 struct batadv_hardif_neigh_node *hardif_neigh = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000664
Linus Lüssinge1237052016-01-07 08:11:12 +0100665 spin_lock_bh(&orig_node->neigh_list_lock);
666
Marek Lindner741aa062015-07-26 04:57:43 +0800667 neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
668 if (neigh_node)
669 goto out;
670
Marek Lindnercef63412015-08-04 21:09:55 +0800671 hardif_neigh = batadv_hardif_neigh_get_or_create(hard_iface,
Linus Lüssing3111bee2016-08-07 12:34:19 +0200672 neigh_addr, orig_node);
Marek Lindnercef63412015-08-04 21:09:55 +0800673 if (!hardif_neigh)
674 goto out;
675
Sven Eckelmann704509b2011-05-14 23:14:54 +0200676 neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000677 if (!neigh_node)
Marek Lindner7ae8b282012-03-01 15:35:21 +0800678 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000679
Marek Lindner9591a792010-12-12 21:57:11 +0000680 INIT_HLIST_NODE(&neigh_node->list);
Simon Wunderlich89652332013-11-13 19:14:46 +0100681 INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
682 spin_lock_init(&neigh_node->ifinfo_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000683
Sven Eckelmann17a86912016-04-11 13:06:40 +0200684 kref_get(&hard_iface->refcount);
Antonio Quartulli8fdd0152014-01-22 00:42:11 +0100685 ether_addr_copy(neigh_node->addr, neigh_addr);
Antonio Quartulli0538f752013-09-02 12:15:01 +0200686 neigh_node->if_incoming = hard_iface;
687 neigh_node->orig_node = orig_node;
Marek Lindnere48474e2016-03-11 16:01:09 +0100688 neigh_node->last_seen = jiffies;
Antonio Quartulli0538f752013-09-02 12:15:01 +0200689
Sven Eckelmannabe59c62016-03-11 16:44:06 +0100690 /* increment unique neighbor refcount */
691 kref_get(&hardif_neigh->refcount);
692 neigh_node->hardif_neigh = hardif_neigh;
693
Marek Lindner1605d0d2011-02-18 12:28:11 +0000694 /* extra reference for return */
Sven Eckelmann77ae32e2016-01-16 10:29:53 +0100695 kref_init(&neigh_node->refcount);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000696
Sven Eckelmann84274452016-07-15 17:39:20 +0200697 kref_get(&neigh_node->refcount);
Marek Lindner741aa062015-07-26 04:57:43 +0800698 hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
Marek Lindner741aa062015-07-26 04:57:43 +0800699
700 batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv,
701 "Creating new neighbor %pM for orig_node %pM on interface %s\n",
702 neigh_addr, orig_node->orig, hard_iface->net_dev->name);
703
Marek Lindner7ae8b282012-03-01 15:35:21 +0800704out:
Linus Lüssinge1237052016-01-07 08:11:12 +0100705 spin_unlock_bh(&orig_node->neigh_list_lock);
706
Marek Lindnercef63412015-08-04 21:09:55 +0800707 if (hardif_neigh)
Sven Eckelmannaccadc32016-01-17 11:01:14 +0100708 batadv_hardif_neigh_put(hardif_neigh);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000709 return neigh_node;
710}
711
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100712/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100713 * batadv_neigh_node_get_or_create() - retrieve or create a neigh node object
Marek Lindner6f0a6b52016-05-03 01:52:08 +0800714 * @orig_node: originator object representing the neighbour
715 * @hard_iface: the interface where the neighbour is connected to
716 * @neigh_addr: the mac address of the neighbour interface
717 *
718 * Return: the neighbour node if found or created or NULL otherwise.
719 */
720struct batadv_neigh_node *
721batadv_neigh_node_get_or_create(struct batadv_orig_node *orig_node,
722 struct batadv_hard_iface *hard_iface,
723 const u8 *neigh_addr)
724{
Sven Eckelmann422d2f72016-07-25 00:42:44 +0200725 struct batadv_neigh_node *neigh_node;
Marek Lindner6f0a6b52016-05-03 01:52:08 +0800726
727 /* first check without locking to avoid the overhead */
728 neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
729 if (neigh_node)
730 return neigh_node;
731
732 return batadv_neigh_node_create(orig_node, hard_iface, neigh_addr);
733}
734
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +0200735#ifdef CONFIG_BATMAN_ADV_DEBUGFS
Marek Lindner6f0a6b52016-05-03 01:52:08 +0800736/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100737 * batadv_hardif_neigh_seq_print_text() - print the single hop neighbour list
Marek Lindner75874052015-08-04 21:09:57 +0800738 * @seq: neighbour table seq_file struct
739 * @offset: not used
740 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200741 * Return: always 0
Marek Lindner75874052015-08-04 21:09:57 +0800742 */
743int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset)
744{
745 struct net_device *net_dev = (struct net_device *)seq->private;
746 struct batadv_priv *bat_priv = netdev_priv(net_dev);
747 struct batadv_hard_iface *primary_if;
748
749 primary_if = batadv_seq_print_text_primary_if_get(seq);
750 if (!primary_if)
751 return 0;
752
753 seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s %s)]\n",
754 BATADV_SOURCE_VERSION, primary_if->net_dev->name,
755 primary_if->net_dev->dev_addr, net_dev->name,
Antonio Quartulli29824a52016-05-25 23:27:31 +0800756 bat_priv->algo_ops->name);
Marek Lindner75874052015-08-04 21:09:57 +0800757
Sven Eckelmann82047ad2016-01-17 11:01:10 +0100758 batadv_hardif_put(primary_if);
Marek Lindner75874052015-08-04 21:09:57 +0800759
Antonio Quartulli29824a52016-05-25 23:27:31 +0800760 if (!bat_priv->algo_ops->neigh.print) {
Marek Lindner75874052015-08-04 21:09:57 +0800761 seq_puts(seq,
762 "No printing function for this routing protocol\n");
763 return 0;
764 }
765
Antonio Quartulli29824a52016-05-25 23:27:31 +0800766 bat_priv->algo_ops->neigh.print(bat_priv, seq);
Marek Lindner75874052015-08-04 21:09:57 +0800767 return 0;
768}
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +0200769#endif
Marek Lindner75874052015-08-04 21:09:57 +0800770
771/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100772 * batadv_hardif_neigh_dump() - Dump to netlink the neighbor infos for a
773 * specific outgoing interface
Matthias Schiffer85cf8c82016-07-03 13:31:39 +0200774 * @msg: message to dump into
775 * @cb: parameters for the dump
776 *
777 * Return: 0 or error value
778 */
779int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb)
780{
781 struct net *net = sock_net(cb->skb->sk);
782 struct net_device *soft_iface;
783 struct net_device *hard_iface = NULL;
784 struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT;
785 struct batadv_priv *bat_priv;
786 struct batadv_hard_iface *primary_if = NULL;
787 int ret;
788 int ifindex, hard_ifindex;
789
790 ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
791 if (!ifindex)
792 return -EINVAL;
793
794 soft_iface = dev_get_by_index(net, ifindex);
795 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
796 ret = -ENODEV;
797 goto out;
798 }
799
800 bat_priv = netdev_priv(soft_iface);
801
802 primary_if = batadv_primary_if_get_selected(bat_priv);
803 if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
804 ret = -ENOENT;
805 goto out;
806 }
807
808 hard_ifindex = batadv_netlink_get_ifindex(cb->nlh,
809 BATADV_ATTR_HARD_IFINDEX);
810 if (hard_ifindex) {
811 hard_iface = dev_get_by_index(net, hard_ifindex);
812 if (hard_iface)
813 hardif = batadv_hardif_get_by_netdev(hard_iface);
814
815 if (!hardif) {
816 ret = -ENODEV;
817 goto out;
818 }
819
820 if (hardif->soft_iface != soft_iface) {
821 ret = -ENOENT;
822 goto out;
823 }
824 }
825
826 if (!bat_priv->algo_ops->neigh.dump) {
827 ret = -EOPNOTSUPP;
828 goto out;
829 }
830
831 bat_priv->algo_ops->neigh.dump(msg, cb, bat_priv, hardif);
832
833 ret = msg->len;
834
835 out:
836 if (hardif)
837 batadv_hardif_put(hardif);
838 if (hard_iface)
839 dev_put(hard_iface);
840 if (primary_if)
841 batadv_hardif_put(primary_if);
842 if (soft_iface)
843 dev_put(soft_iface);
844
845 return ret;
846}
847
848/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100849 * batadv_orig_ifinfo_release() - release orig_ifinfo from lists and queue for
Sven Eckelmann2baa7532016-01-05 12:06:22 +0100850 * free after rcu grace period
Sven Eckelmanna6ba0d32016-01-16 10:29:52 +0100851 * @ref: kref pointer of the orig_ifinfo
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100852 */
Sven Eckelmanna6ba0d32016-01-16 10:29:52 +0100853static void batadv_orig_ifinfo_release(struct kref *ref)
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100854{
Sven Eckelmanna6ba0d32016-01-16 10:29:52 +0100855 struct batadv_orig_ifinfo *orig_ifinfo;
Simon Wunderlich000c8df2014-03-26 15:46:22 +0100856 struct batadv_neigh_node *router;
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100857
Sven Eckelmanna6ba0d32016-01-16 10:29:52 +0100858 orig_ifinfo = container_of(ref, struct batadv_orig_ifinfo, refcount);
859
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100860 if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
Sven Eckelmann82047ad2016-01-17 11:01:10 +0100861 batadv_hardif_put(orig_ifinfo->if_outgoing);
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100862
Simon Wunderlich000c8df2014-03-26 15:46:22 +0100863 /* this is the last reference to this object */
864 router = rcu_dereference_protected(orig_ifinfo->router, true);
865 if (router)
Sven Eckelmann25bb2502016-01-17 11:01:11 +0100866 batadv_neigh_node_put(router);
Sven Eckelmann2baa7532016-01-05 12:06:22 +0100867
868 kfree_rcu(orig_ifinfo, rcu);
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100869}
870
871/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100872 * batadv_orig_ifinfo_put() - decrement the refcounter and possibly release
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100873 * the orig_ifinfo
874 * @orig_ifinfo: the orig_ifinfo object to release
875 */
Sven Eckelmann35f94772016-01-17 11:01:13 +0100876void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo)
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100877{
Sven Eckelmanna6ba0d32016-01-16 10:29:52 +0100878 kref_put(&orig_ifinfo->refcount, batadv_orig_ifinfo_release);
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100879}
880
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100881/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100882 * batadv_orig_node_free_rcu() - free the orig_node
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100883 * @rcu: rcu pointer of the orig_node
884 */
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200885static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000886{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200887 struct batadv_orig_node *orig_node;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000888
Sven Eckelmann56303d32012-06-05 22:31:31 +0200889 orig_node = container_of(rcu, struct batadv_orig_node, rcu);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000890
Linus Lüssing60432d72014-02-15 17:47:51 +0100891 batadv_mcast_purge_orig(orig_node);
892
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +0200893 batadv_frag_purge_orig(orig_node, NULL);
894
Antonio Quartullia73105b2011-04-27 14:27:44 +0200895 kfree(orig_node->tt_buff);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000896 kfree(orig_node);
897}
898
Linus Lüssing72822222013-04-15 21:43:29 +0800899/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100900 * batadv_orig_node_release() - release orig_node from lists and queue for
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100901 * free after rcu grace period
Sven Eckelmann7c124392016-01-16 10:29:56 +0100902 * @ref: kref pointer of the orig_node
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100903 */
Sven Eckelmann7c124392016-01-16 10:29:56 +0100904static void batadv_orig_node_release(struct kref *ref)
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100905{
906 struct hlist_node *node_tmp;
907 struct batadv_neigh_node *neigh_node;
Sven Eckelmann7c124392016-01-16 10:29:56 +0100908 struct batadv_orig_node *orig_node;
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100909 struct batadv_orig_ifinfo *orig_ifinfo;
Sven Eckelmann33fbb1f2016-06-30 20:10:46 +0200910 struct batadv_orig_node_vlan *vlan;
Sven Eckelmanncbef1e12016-06-30 21:41:13 +0200911 struct batadv_orig_ifinfo *last_candidate;
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100912
Sven Eckelmann7c124392016-01-16 10:29:56 +0100913 orig_node = container_of(ref, struct batadv_orig_node, refcount);
914
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100915 spin_lock_bh(&orig_node->neigh_list_lock);
916
917 /* for all neighbors towards this originator ... */
918 hlist_for_each_entry_safe(neigh_node, node_tmp,
919 &orig_node->neigh_list, list) {
920 hlist_del_rcu(&neigh_node->list);
Sven Eckelmann25bb2502016-01-17 11:01:11 +0100921 batadv_neigh_node_put(neigh_node);
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100922 }
923
924 hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
925 &orig_node->ifinfo_list, list) {
926 hlist_del_rcu(&orig_ifinfo->list);
Sven Eckelmann35f94772016-01-17 11:01:13 +0100927 batadv_orig_ifinfo_put(orig_ifinfo);
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100928 }
Sven Eckelmanncbef1e12016-06-30 21:41:13 +0200929
930 last_candidate = orig_node->last_bonding_candidate;
931 orig_node->last_bonding_candidate = NULL;
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100932 spin_unlock_bh(&orig_node->neigh_list_lock);
933
Sven Eckelmanncbef1e12016-06-30 21:41:13 +0200934 if (last_candidate)
935 batadv_orig_ifinfo_put(last_candidate);
936
Sven Eckelmann33fbb1f2016-06-30 20:10:46 +0200937 spin_lock_bh(&orig_node->vlan_list_lock);
938 hlist_for_each_entry_safe(vlan, node_tmp, &orig_node->vlan_list, list) {
939 hlist_del_rcu(&vlan->list);
940 batadv_orig_node_vlan_put(vlan);
941 }
942 spin_unlock_bh(&orig_node->vlan_list_lock);
943
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100944 /* Free nc_nodes */
945 batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
946
947 call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu);
948}
949
950/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100951 * batadv_orig_node_put() - decrement the orig node refcounter and possibly
Sven Eckelmanndeed9662016-01-05 12:06:21 +0100952 * release it
Linus Lüssing72822222013-04-15 21:43:29 +0800953 * @orig_node: the orig node to free
954 */
Sven Eckelmann5d967312016-01-17 11:01:09 +0100955void batadv_orig_node_put(struct batadv_orig_node *orig_node)
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000956{
Sven Eckelmann7c124392016-01-16 10:29:56 +0100957 kref_put(&orig_node->refcount, batadv_orig_node_release);
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000958}
959
Sven Eckelmannff15c272017-12-02 19:51:53 +0100960/**
961 * batadv_originator_free() - Free all originator structures
962 * @bat_priv: the bat priv with all the soft interface information
963 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200964void batadv_originator_free(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000965{
Sven Eckelmann5bf74e92012-06-05 22:31:28 +0200966 struct batadv_hashtable *hash = bat_priv->orig_hash;
Sasha Levinb67bfe02013-02-27 17:06:00 -0800967 struct hlist_node *node_tmp;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000968 struct hlist_head *head;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000969 spinlock_t *list_lock; /* spinlock to protect write access */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200970 struct batadv_orig_node *orig_node;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200971 u32 i;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000972
973 if (!hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000974 return;
975
976 cancel_delayed_work_sync(&bat_priv->orig_work);
977
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000978 bat_priv->orig_hash = NULL;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000979
980 for (i = 0; i < hash->size; i++) {
981 head = &hash->table[i];
982 list_lock = &hash->list_locks[i];
983
984 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -0800985 hlist_for_each_entry_safe(orig_node, node_tmp,
Marek Lindner7aadf882011-02-18 12:28:09 +0000986 head, hash_entry) {
Sasha Levinb67bfe02013-02-27 17:06:00 -0800987 hlist_del_rcu(&orig_node->hash_entry);
Sven Eckelmann5d967312016-01-17 11:01:09 +0100988 batadv_orig_node_put(orig_node);
Marek Lindner16b1aba2011-01-19 20:01:42 +0000989 }
990 spin_unlock_bh(list_lock);
991 }
992
Sven Eckelmann1a8eaf02012-05-12 02:09:32 +0200993 batadv_hash_destroy(hash);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000994}
995
Antonio Quartullibbad0a52013-09-02 12:15:02 +0200996/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100997 * batadv_orig_node_new() - creates a new orig_node
Antonio Quartullibbad0a52013-09-02 12:15:02 +0200998 * @bat_priv: the bat priv with all the soft interface information
999 * @addr: the mac address of the originator
1000 *
1001 * Creates a new originator object and initialise all the generic fields.
1002 * The new object is not added to the originator list.
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001003 *
1004 * Return: the newly created object or NULL on failure.
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02001005 */
Antonio Quartullibbad0a52013-09-02 12:15:02 +02001006struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001007 const u8 *addr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001008{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001009 struct batadv_orig_node *orig_node;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001010 struct batadv_orig_node_vlan *vlan;
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001011 unsigned long reset_time;
Antonio Quartullibbad0a52013-09-02 12:15:02 +02001012 int i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001013
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001014 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1015 "Creating new originator: %pM\n", addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001016
Sven Eckelmann704509b2011-05-14 23:14:54 +02001017 orig_node = kzalloc(sizeof(*orig_node), GFP_ATOMIC);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001018 if (!orig_node)
1019 return NULL;
1020
Marek Lindner9591a792010-12-12 21:57:11 +00001021 INIT_HLIST_HEAD(&orig_node->neigh_list);
Marek Lindnerd0fa4f32015-06-22 00:30:22 +08001022 INIT_HLIST_HEAD(&orig_node->vlan_list);
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001023 INIT_HLIST_HEAD(&orig_node->ifinfo_list);
Marek Lindnerf3e00082011-01-25 21:52:11 +00001024 spin_lock_init(&orig_node->bcast_seqno_lock);
Marek Lindnerf987ed62010-12-12 21:57:12 +00001025 spin_lock_init(&orig_node->neigh_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001026 spin_lock_init(&orig_node->tt_buff_lock);
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02001027 spin_lock_init(&orig_node->tt_lock);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001028 spin_lock_init(&orig_node->vlan_list_lock);
Marek Lindner7b36e8e2011-02-18 12:28:10 +00001029
Martin Hundebølld56b1702013-01-25 11:12:39 +01001030 batadv_nc_init_orig(orig_node);
1031
Marek Lindner7b36e8e2011-02-18 12:28:10 +00001032 /* extra reference for return */
Sven Eckelmann7c124392016-01-16 10:29:56 +01001033 kref_init(&orig_node->refcount);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001034
Marek Lindner16b1aba2011-01-19 20:01:42 +00001035 orig_node->bat_priv = bat_priv;
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01001036 ether_addr_copy(orig_node->orig, addr);
Antonio Quartulli785ea112011-11-23 11:35:44 +01001037 batadv_dat_init_orig_node_addr(orig_node);
Antonio Quartullic8c991b2011-07-07 01:40:57 +02001038 atomic_set(&orig_node->last_ttvn, 0);
Antonio Quartulli2dafb492011-05-05 08:42:45 +02001039 orig_node->tt_buff = NULL;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001040 orig_node->tt_buff_len = 0;
Linus Lüssing2c667a32014-10-30 06:23:40 +01001041 orig_node->last_seen = jiffies;
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001042 reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
1043 orig_node->bcast_seqno_reset = reset_time;
Linus Lüssing8a4023c2015-06-16 17:10:26 +02001044
Linus Lüssing60432d72014-02-15 17:47:51 +01001045#ifdef CONFIG_BATMAN_ADV_MCAST
1046 orig_node->mcast_flags = BATADV_NO_FLAGS;
Linus Lüssing8a4023c2015-06-16 17:10:26 +02001047 INIT_HLIST_NODE(&orig_node->mcast_want_all_unsnoopables_node);
1048 INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv4_node);
1049 INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv6_node);
1050 spin_lock_init(&orig_node->mcast_handler_lock);
Linus Lüssing60432d72014-02-15 17:47:51 +01001051#endif
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001052
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001053 /* create a vlan object for the "untagged" LAN */
1054 vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
1055 if (!vlan)
1056 goto free_orig_node;
1057 /* batadv_orig_node_vlan_new() increases the refcounter.
1058 * Immediately release vlan since it is not needed anymore in this
1059 * context
1060 */
Sven Eckelmann21754e22016-01-17 11:01:24 +01001061 batadv_orig_node_vlan_put(vlan);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001062
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +02001063 for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) {
Sven Eckelmann176e5b72016-07-27 12:31:07 +02001064 INIT_HLIST_HEAD(&orig_node->fragments[i].fragment_list);
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +02001065 spin_lock_init(&orig_node->fragments[i].lock);
1066 orig_node->fragments[i].size = 0;
1067 }
1068
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001069 return orig_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001070free_orig_node:
1071 kfree(orig_node);
1072 return NULL;
1073}
1074
Simon Wunderlich89652332013-11-13 19:14:46 +01001075/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +01001076 * batadv_purge_neigh_ifinfo() - purge obsolete ifinfo entries from neighbor
Simon Wunderlich709de132014-03-26 15:46:24 +01001077 * @bat_priv: the bat priv with all the soft interface information
1078 * @neigh: orig node which is to be checked
1079 */
1080static void
1081batadv_purge_neigh_ifinfo(struct batadv_priv *bat_priv,
1082 struct batadv_neigh_node *neigh)
1083{
1084 struct batadv_neigh_ifinfo *neigh_ifinfo;
1085 struct batadv_hard_iface *if_outgoing;
1086 struct hlist_node *node_tmp;
1087
1088 spin_lock_bh(&neigh->ifinfo_lock);
1089
1090 /* for all ifinfo objects for this neighinator */
1091 hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
1092 &neigh->ifinfo_list, list) {
1093 if_outgoing = neigh_ifinfo->if_outgoing;
1094
1095 /* always keep the default interface */
1096 if (if_outgoing == BATADV_IF_DEFAULT)
1097 continue;
1098
1099 /* don't purge if the interface is not (going) down */
Sven Eckelmann825ffe12017-08-23 21:52:13 +02001100 if (if_outgoing->if_status != BATADV_IF_INACTIVE &&
1101 if_outgoing->if_status != BATADV_IF_NOT_IN_USE &&
1102 if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)
Simon Wunderlich709de132014-03-26 15:46:24 +01001103 continue;
1104
1105 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1106 "neighbor/ifinfo purge: neighbor %pM, iface: %s\n",
1107 neigh->addr, if_outgoing->net_dev->name);
1108
1109 hlist_del_rcu(&neigh_ifinfo->list);
Sven Eckelmann044fa3a2016-01-17 11:01:12 +01001110 batadv_neigh_ifinfo_put(neigh_ifinfo);
Simon Wunderlich709de132014-03-26 15:46:24 +01001111 }
1112
1113 spin_unlock_bh(&neigh->ifinfo_lock);
1114}
1115
1116/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +01001117 * batadv_purge_orig_ifinfo() - purge obsolete ifinfo entries from originator
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001118 * @bat_priv: the bat priv with all the soft interface information
1119 * @orig_node: orig node which is to be checked
1120 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001121 * Return: true if any ifinfo entry was purged, false otherwise.
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001122 */
1123static bool
1124batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
1125 struct batadv_orig_node *orig_node)
1126{
1127 struct batadv_orig_ifinfo *orig_ifinfo;
1128 struct batadv_hard_iface *if_outgoing;
1129 struct hlist_node *node_tmp;
1130 bool ifinfo_purged = false;
1131
1132 spin_lock_bh(&orig_node->neigh_list_lock);
1133
1134 /* for all ifinfo objects for this originator */
1135 hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
1136 &orig_node->ifinfo_list, list) {
1137 if_outgoing = orig_ifinfo->if_outgoing;
1138
1139 /* always keep the default interface */
1140 if (if_outgoing == BATADV_IF_DEFAULT)
1141 continue;
1142
1143 /* don't purge if the interface is not (going) down */
Sven Eckelmann825ffe12017-08-23 21:52:13 +02001144 if (if_outgoing->if_status != BATADV_IF_INACTIVE &&
1145 if_outgoing->if_status != BATADV_IF_NOT_IN_USE &&
1146 if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001147 continue;
1148
1149 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1150 "router/ifinfo purge: originator %pM, iface: %s\n",
1151 orig_node->orig, if_outgoing->net_dev->name);
1152
1153 ifinfo_purged = true;
1154
1155 hlist_del_rcu(&orig_ifinfo->list);
Sven Eckelmann35f94772016-01-17 11:01:13 +01001156 batadv_orig_ifinfo_put(orig_ifinfo);
Simon Wunderlichf3b3d902013-11-13 19:14:50 +01001157 if (orig_node->last_bonding_candidate == orig_ifinfo) {
1158 orig_node->last_bonding_candidate = NULL;
Sven Eckelmann35f94772016-01-17 11:01:13 +01001159 batadv_orig_ifinfo_put(orig_ifinfo);
Simon Wunderlichf3b3d902013-11-13 19:14:50 +01001160 }
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001161 }
1162
1163 spin_unlock_bh(&orig_node->neigh_list_lock);
1164
1165 return ifinfo_purged;
1166}
1167
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001168/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +01001169 * batadv_purge_orig_neighbors() - purges neighbors from originator
Simon Wunderlich89652332013-11-13 19:14:46 +01001170 * @bat_priv: the bat priv with all the soft interface information
1171 * @orig_node: orig node which is to be checked
1172 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001173 * Return: true if any neighbor was purged, false otherwise
Simon Wunderlich89652332013-11-13 19:14:46 +01001174 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001175static bool
1176batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
Simon Wunderlich89652332013-11-13 19:14:46 +01001177 struct batadv_orig_node *orig_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001178{
Sasha Levinb67bfe02013-02-27 17:06:00 -08001179 struct hlist_node *node_tmp;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001180 struct batadv_neigh_node *neigh_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001181 bool neigh_purged = false;
Marek Lindner0b0094e2012-03-01 15:35:20 +08001182 unsigned long last_seen;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001183 struct batadv_hard_iface *if_incoming;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001184
Marek Lindnerf987ed62010-12-12 21:57:12 +00001185 spin_lock_bh(&orig_node->neigh_list_lock);
1186
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001187 /* for all neighbors towards this originator ... */
Sasha Levinb67bfe02013-02-27 17:06:00 -08001188 hlist_for_each_entry_safe(neigh_node, node_tmp,
Marek Lindner9591a792010-12-12 21:57:11 +00001189 &orig_node->neigh_list, list) {
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02001190 last_seen = neigh_node->last_seen;
1191 if_incoming = neigh_node->if_incoming;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001192
Sven Eckelmann825ffe12017-08-23 21:52:13 +02001193 if (batadv_has_timed_out(last_seen, BATADV_PURGE_TIMEOUT) ||
1194 if_incoming->if_status == BATADV_IF_INACTIVE ||
1195 if_incoming->if_status == BATADV_IF_NOT_IN_USE ||
1196 if_incoming->if_status == BATADV_IF_TO_BE_REMOVED) {
1197 if (if_incoming->if_status == BATADV_IF_INACTIVE ||
1198 if_incoming->if_status == BATADV_IF_NOT_IN_USE ||
1199 if_incoming->if_status == BATADV_IF_TO_BE_REMOVED)
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001200 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02001201 "neighbor purge: originator %pM, neighbor: %pM, iface: %s\n",
1202 orig_node->orig, neigh_node->addr,
1203 if_incoming->net_dev->name);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001204 else
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001205 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02001206 "neighbor timeout: originator %pM, neighbor: %pM, last_seen: %u\n",
1207 orig_node->orig, neigh_node->addr,
1208 jiffies_to_msecs(last_seen));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001209
1210 neigh_purged = true;
Marek Lindner9591a792010-12-12 21:57:11 +00001211
Marek Lindnerf987ed62010-12-12 21:57:12 +00001212 hlist_del_rcu(&neigh_node->list);
Sven Eckelmann25bb2502016-01-17 11:01:11 +01001213 batadv_neigh_node_put(neigh_node);
Simon Wunderlich709de132014-03-26 15:46:24 +01001214 } else {
1215 /* only necessary if not the whole neighbor is to be
1216 * deleted, but some interface has been removed.
1217 */
1218 batadv_purge_neigh_ifinfo(bat_priv, neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001219 }
1220 }
Marek Lindnerf987ed62010-12-12 21:57:12 +00001221
1222 spin_unlock_bh(&orig_node->neigh_list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001223 return neigh_purged;
1224}
1225
Simon Wunderlich89652332013-11-13 19:14:46 +01001226/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +01001227 * batadv_find_best_neighbor() - finds the best neighbor after purging
Simon Wunderlich89652332013-11-13 19:14:46 +01001228 * @bat_priv: the bat priv with all the soft interface information
1229 * @orig_node: orig node which is to be checked
1230 * @if_outgoing: the interface for which the metric should be compared
1231 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001232 * Return: the current best neighbor, with refcount increased.
Simon Wunderlich89652332013-11-13 19:14:46 +01001233 */
1234static struct batadv_neigh_node *
1235batadv_find_best_neighbor(struct batadv_priv *bat_priv,
1236 struct batadv_orig_node *orig_node,
1237 struct batadv_hard_iface *if_outgoing)
1238{
1239 struct batadv_neigh_node *best = NULL, *neigh;
Antonio Quartulli29824a52016-05-25 23:27:31 +08001240 struct batadv_algo_ops *bao = bat_priv->algo_ops;
Simon Wunderlich89652332013-11-13 19:14:46 +01001241
1242 rcu_read_lock();
1243 hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list) {
Antonio Quartulli29824a52016-05-25 23:27:31 +08001244 if (best && (bao->neigh.cmp(neigh, if_outgoing, best,
1245 if_outgoing) <= 0))
Simon Wunderlich89652332013-11-13 19:14:46 +01001246 continue;
1247
Sven Eckelmann77ae32e2016-01-16 10:29:53 +01001248 if (!kref_get_unless_zero(&neigh->refcount))
Simon Wunderlich89652332013-11-13 19:14:46 +01001249 continue;
1250
1251 if (best)
Sven Eckelmann25bb2502016-01-17 11:01:11 +01001252 batadv_neigh_node_put(best);
Simon Wunderlich89652332013-11-13 19:14:46 +01001253
1254 best = neigh;
1255 }
1256 rcu_read_unlock();
1257
1258 return best;
1259}
1260
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001261/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +01001262 * batadv_purge_orig_node() - purges obsolete information from an orig_node
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001263 * @bat_priv: the bat priv with all the soft interface information
1264 * @orig_node: orig node which is to be checked
1265 *
1266 * This function checks if the orig_node or substructures of it have become
1267 * obsolete, and purges this information if that's the case.
1268 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001269 * Return: true if the orig_node is to be removed, false otherwise.
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001270 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001271static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
1272 struct batadv_orig_node *orig_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001273{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001274 struct batadv_neigh_node *best_neigh_node;
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001275 struct batadv_hard_iface *hard_iface;
Simon Wunderlich7b955a92014-03-26 15:46:23 +01001276 bool changed_ifinfo, changed_neigh;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001277
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001278 if (batadv_has_timed_out(orig_node->last_seen,
1279 2 * BATADV_PURGE_TIMEOUT)) {
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001280 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02001281 "Originator timeout: originator %pM, last_seen %u\n",
1282 orig_node->orig,
1283 jiffies_to_msecs(orig_node->last_seen));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001284 return true;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001285 }
Simon Wunderlich7b955a92014-03-26 15:46:23 +01001286 changed_ifinfo = batadv_purge_orig_ifinfo(bat_priv, orig_node);
1287 changed_neigh = batadv_purge_orig_neighbors(bat_priv, orig_node);
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001288
Simon Wunderlich7b955a92014-03-26 15:46:23 +01001289 if (!changed_ifinfo && !changed_neigh)
Simon Wunderlich89652332013-11-13 19:14:46 +01001290 return false;
1291
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001292 /* first for NULL ... */
Simon Wunderlich89652332013-11-13 19:14:46 +01001293 best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node,
1294 BATADV_IF_DEFAULT);
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001295 batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
1296 best_neigh_node);
Simon Wunderlich89652332013-11-13 19:14:46 +01001297 if (best_neigh_node)
Sven Eckelmann25bb2502016-01-17 11:01:11 +01001298 batadv_neigh_node_put(best_neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001299
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001300 /* ... then for all other interfaces. */
1301 rcu_read_lock();
1302 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
1303 if (hard_iface->if_status != BATADV_IF_ACTIVE)
1304 continue;
1305
1306 if (hard_iface->soft_iface != bat_priv->soft_iface)
1307 continue;
1308
Sven Eckelmann27353442016-03-05 16:09:16 +01001309 if (!kref_get_unless_zero(&hard_iface->refcount))
1310 continue;
1311
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001312 best_neigh_node = batadv_find_best_neighbor(bat_priv,
1313 orig_node,
1314 hard_iface);
1315 batadv_update_route(bat_priv, orig_node, hard_iface,
1316 best_neigh_node);
1317 if (best_neigh_node)
Sven Eckelmann25bb2502016-01-17 11:01:11 +01001318 batadv_neigh_node_put(best_neigh_node);
Sven Eckelmann27353442016-03-05 16:09:16 +01001319
1320 batadv_hardif_put(hard_iface);
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001321 }
1322 rcu_read_unlock();
1323
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001324 return false;
1325}
1326
Sven Eckelmann3b1709d2018-07-07 21:46:11 +02001327/**
1328 * batadv_purge_orig_ref() - Purge all outdated originators
1329 * @bat_priv: the bat priv with all the soft interface information
1330 */
1331void batadv_purge_orig_ref(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001332{
Sven Eckelmann5bf74e92012-06-05 22:31:28 +02001333 struct batadv_hashtable *hash = bat_priv->orig_hash;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001334 struct hlist_node *node_tmp;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001335 struct hlist_head *head;
Marek Lindnerfb778ea2011-01-19 20:01:40 +00001336 spinlock_t *list_lock; /* spinlock to protect write access */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001337 struct batadv_orig_node *orig_node;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001338 u32 i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001339
1340 if (!hash)
1341 return;
1342
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001343 /* for all origins... */
1344 for (i = 0; i < hash->size; i++) {
1345 head = &hash->table[i];
Marek Lindnerfb778ea2011-01-19 20:01:40 +00001346 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001347
Marek Lindnerfb778ea2011-01-19 20:01:40 +00001348 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001349 hlist_for_each_entry_safe(orig_node, node_tmp,
Marek Lindner7aadf882011-02-18 12:28:09 +00001350 head, hash_entry) {
Sven Eckelmann03fc7f82012-05-12 18:34:00 +02001351 if (batadv_purge_orig_node(bat_priv, orig_node)) {
Marek Lindner414254e2013-04-23 21:39:58 +08001352 batadv_gw_node_delete(bat_priv, orig_node);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001353 hlist_del_rcu(&orig_node->hash_entry);
Linus Lüssing9d31b3c2014-12-13 23:32:15 +01001354 batadv_tt_global_del_orig(orig_node->bat_priv,
1355 orig_node, -1,
1356 "originator timed out");
Sven Eckelmann5d967312016-01-17 11:01:09 +01001357 batadv_orig_node_put(orig_node);
Marek Lindnerfb778ea2011-01-19 20:01:40 +00001358 continue;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001359 }
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +02001360
1361 batadv_frag_purge_orig(orig_node,
1362 batadv_frag_check_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001363 }
Marek Lindnerfb778ea2011-01-19 20:01:40 +00001364 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001365 }
1366
Sven Eckelmann7cf06bc2012-05-12 02:09:29 +02001367 batadv_gw_election(bat_priv);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001368}
1369
Sven Eckelmann03fc7f82012-05-12 18:34:00 +02001370static void batadv_purge_orig(struct work_struct *work)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001371{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001372 struct delayed_work *delayed_work;
1373 struct batadv_priv *bat_priv;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001374
Geliang Tang4ba4bc02015-12-28 23:43:37 +08001375 delayed_work = to_delayed_work(work);
Sven Eckelmann56303d32012-06-05 22:31:31 +02001376 bat_priv = container_of(delayed_work, struct batadv_priv, orig_work);
Sven Eckelmann3b1709d2018-07-07 21:46:11 +02001377 batadv_purge_orig_ref(bat_priv);
Antonio Quartulli72414442012-12-25 13:14:37 +01001378 queue_delayed_work(batadv_event_workqueue,
1379 &bat_priv->orig_work,
1380 msecs_to_jiffies(BATADV_ORIG_WORK_PERIOD));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001381}
1382
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +02001383#ifdef CONFIG_BATMAN_ADV_DEBUGFS
Sven Eckelmannff15c272017-12-02 19:51:53 +01001384
1385/**
1386 * batadv_orig_seq_print_text() - Print the originator table in a seq file
1387 * @seq: seq file to print on
1388 * @offset: not used
1389 *
1390 * Return: always 0
1391 */
Sven Eckelmann7d211ef2012-05-12 02:09:34 +02001392int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001393{
1394 struct net_device *net_dev = (struct net_device *)seq->private;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001395 struct batadv_priv *bat_priv = netdev_priv(net_dev);
Sven Eckelmann56303d32012-06-05 22:31:31 +02001396 struct batadv_hard_iface *primary_if;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001397
Marek Lindner30da63a2012-08-03 17:15:46 +02001398 primary_if = batadv_seq_print_text_primary_if_get(seq);
1399 if (!primary_if)
Antonio Quartulli737a2a222013-09-02 12:15:03 +02001400 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001401
Antonio Quartulli737a2a222013-09-02 12:15:03 +02001402 seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s %s)]\n",
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001403 BATADV_SOURCE_VERSION, primary_if->net_dev->name,
Antonio Quartulli737a2a222013-09-02 12:15:03 +02001404 primary_if->net_dev->dev_addr, net_dev->name,
Antonio Quartulli29824a52016-05-25 23:27:31 +08001405 bat_priv->algo_ops->name);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001406
Sven Eckelmann82047ad2016-01-17 11:01:10 +01001407 batadv_hardif_put(primary_if);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001408
Antonio Quartulli29824a52016-05-25 23:27:31 +08001409 if (!bat_priv->algo_ops->orig.print) {
Antonio Quartulli737a2a222013-09-02 12:15:03 +02001410 seq_puts(seq,
1411 "No printing function for this routing protocol\n");
1412 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001413 }
1414
Antonio Quartulli29824a52016-05-25 23:27:31 +08001415 bat_priv->algo_ops->orig.print(bat_priv, seq, BATADV_IF_DEFAULT);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001416
Marek Lindner30da63a2012-08-03 17:15:46 +02001417 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001418}
1419
Simon Wunderlichcb1c92e2013-11-21 11:52:16 +01001420/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +01001421 * batadv_orig_hardif_seq_print_text() - writes originator infos for a specific
Simon Wunderlichcb1c92e2013-11-21 11:52:16 +01001422 * outgoing interface
1423 * @seq: debugfs table seq_file struct
1424 * @offset: not used
1425 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001426 * Return: 0
Simon Wunderlichcb1c92e2013-11-21 11:52:16 +01001427 */
1428int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset)
1429{
1430 struct net_device *net_dev = (struct net_device *)seq->private;
1431 struct batadv_hard_iface *hard_iface;
1432 struct batadv_priv *bat_priv;
1433
1434 hard_iface = batadv_hardif_get_by_netdev(net_dev);
1435
1436 if (!hard_iface || !hard_iface->soft_iface) {
1437 seq_puts(seq, "Interface not known to B.A.T.M.A.N.\n");
1438 goto out;
1439 }
1440
1441 bat_priv = netdev_priv(hard_iface->soft_iface);
Antonio Quartulli29824a52016-05-25 23:27:31 +08001442 if (!bat_priv->algo_ops->orig.print) {
Simon Wunderlichcb1c92e2013-11-21 11:52:16 +01001443 seq_puts(seq,
1444 "No printing function for this routing protocol\n");
1445 goto out;
1446 }
1447
1448 if (hard_iface->if_status != BATADV_IF_ACTIVE) {
1449 seq_puts(seq, "Interface not active\n");
1450 goto out;
1451 }
1452
1453 seq_printf(seq, "[B.A.T.M.A.N. adv %s, IF/MAC: %s/%pM (%s %s)]\n",
1454 BATADV_SOURCE_VERSION, hard_iface->net_dev->name,
1455 hard_iface->net_dev->dev_addr,
Antonio Quartulli29824a52016-05-25 23:27:31 +08001456 hard_iface->soft_iface->name, bat_priv->algo_ops->name);
Simon Wunderlichcb1c92e2013-11-21 11:52:16 +01001457
Antonio Quartulli29824a52016-05-25 23:27:31 +08001458 bat_priv->algo_ops->orig.print(bat_priv, seq, hard_iface);
Simon Wunderlichcb1c92e2013-11-21 11:52:16 +01001459
1460out:
Marek Lindner16a41422014-04-24 03:44:25 +08001461 if (hard_iface)
Sven Eckelmann82047ad2016-01-17 11:01:10 +01001462 batadv_hardif_put(hard_iface);
Simon Wunderlichcb1c92e2013-11-21 11:52:16 +01001463 return 0;
1464}
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +02001465#endif
Simon Wunderlichcb1c92e2013-11-21 11:52:16 +01001466
Matthias Schiffer85cf8c82016-07-03 13:31:39 +02001467/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +01001468 * batadv_orig_dump() - Dump to netlink the originator infos for a specific
Matthias Schiffer85cf8c82016-07-03 13:31:39 +02001469 * outgoing interface
1470 * @msg: message to dump into
1471 * @cb: parameters for the dump
1472 *
1473 * Return: 0 or error value
1474 */
1475int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb)
1476{
1477 struct net *net = sock_net(cb->skb->sk);
1478 struct net_device *soft_iface;
1479 struct net_device *hard_iface = NULL;
1480 struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT;
1481 struct batadv_priv *bat_priv;
1482 struct batadv_hard_iface *primary_if = NULL;
1483 int ret;
1484 int ifindex, hard_ifindex;
1485
1486 ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
1487 if (!ifindex)
1488 return -EINVAL;
1489
1490 soft_iface = dev_get_by_index(net, ifindex);
1491 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
1492 ret = -ENODEV;
1493 goto out;
1494 }
1495
1496 bat_priv = netdev_priv(soft_iface);
1497
1498 primary_if = batadv_primary_if_get_selected(bat_priv);
1499 if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
1500 ret = -ENOENT;
1501 goto out;
1502 }
1503
1504 hard_ifindex = batadv_netlink_get_ifindex(cb->nlh,
1505 BATADV_ATTR_HARD_IFINDEX);
1506 if (hard_ifindex) {
1507 hard_iface = dev_get_by_index(net, hard_ifindex);
1508 if (hard_iface)
1509 hardif = batadv_hardif_get_by_netdev(hard_iface);
1510
1511 if (!hardif) {
1512 ret = -ENODEV;
1513 goto out;
1514 }
1515
1516 if (hardif->soft_iface != soft_iface) {
1517 ret = -ENOENT;
1518 goto out;
1519 }
1520 }
1521
1522 if (!bat_priv->algo_ops->orig.dump) {
1523 ret = -EOPNOTSUPP;
1524 goto out;
1525 }
1526
1527 bat_priv->algo_ops->orig.dump(msg, cb, bat_priv, hardif);
1528
1529 ret = msg->len;
1530
1531 out:
1532 if (hardif)
1533 batadv_hardif_put(hardif);
1534 if (hard_iface)
1535 dev_put(hard_iface);
1536 if (primary_if)
1537 batadv_hardif_put(primary_if);
1538 if (soft_iface)
1539 dev_put(soft_iface);
1540
1541 return ret;
1542}