~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/batman-adv/originator.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php