blob: d003b523ae918c1d6f79bcdf8004bf672f407107 [file] [log] [blame]
Sven Eckelmann0046b042016-01-01 00:01:03 +01001/* Copyright (C) 2007-2016 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002 *
Antonio Quartulli35c133a2012-03-14 13:03:01 +01003 * Marek Lindner, Simon Wunderlich, Antonio Quartulli
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public
7 * License as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
Antonio Quartulliebf38fb2013-11-03 20:40:48 +010015 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000016 */
17
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000018#include "translation-table.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020019#include "main.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000020
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020021#include <linux/atomic.h>
Linus Lüssingac4eebd2015-06-16 17:10:24 +020022#include <linux/bitops.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020023#include <linux/bug.h>
24#include <linux/byteorder/generic.h>
Sven Eckelmann86452f82016-06-25 16:44:06 +020025#include <linux/cache.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020026#include <linux/compiler.h>
Antonio Quartulliced72932013-04-24 16:37:51 +020027#include <linux/crc32c.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020028#include <linux/errno.h>
29#include <linux/etherdevice.h>
30#include <linux/fs.h>
31#include <linux/if_ether.h>
Sven Eckelmann86452f82016-06-25 16:44:06 +020032#include <linux/init.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020033#include <linux/jhash.h>
34#include <linux/jiffies.h>
35#include <linux/kernel.h>
Sven Eckelmann6e8ef692016-01-16 10:29:50 +010036#include <linux/kref.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020037#include <linux/list.h>
38#include <linux/lockdep.h>
39#include <linux/netdevice.h>
Matthias Schifferd34f0552016-07-03 13:31:37 +020040#include <linux/netlink.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020041#include <linux/rculist.h>
42#include <linux/rcupdate.h>
43#include <linux/seq_file.h>
Matthias Schifferd34f0552016-07-03 13:31:37 +020044#include <linux/skbuff.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020045#include <linux/slab.h>
46#include <linux/spinlock.h>
47#include <linux/stddef.h>
48#include <linux/string.h>
49#include <linux/workqueue.h>
Matthias Schifferd34f0552016-07-03 13:31:37 +020050#include <net/genetlink.h>
51#include <net/netlink.h>
52#include <net/sock.h>
53#include <uapi/linux/batman_adv.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020054
55#include "bridge_loop_avoidance.h"
56#include "hard-interface.h"
57#include "hash.h"
Sven Eckelmannba412082016-05-15 23:48:31 +020058#include "log.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020059#include "multicast.h"
Matthias Schifferd34f0552016-07-03 13:31:37 +020060#include "netlink.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020061#include "originator.h"
62#include "packet.h"
63#include "soft-interface.h"
Markus Pargmann1f8dce42016-05-15 11:07:43 +020064#include "tvlv.h"
Antonio Quartullia73105b2011-04-27 14:27:44 +020065
Sven Eckelmann86452f82016-06-25 16:44:06 +020066static struct kmem_cache *batadv_tl_cache __read_mostly;
67static struct kmem_cache *batadv_tg_cache __read_mostly;
68static struct kmem_cache *batadv_tt_orig_cache __read_mostly;
69static struct kmem_cache *batadv_tt_change_cache __read_mostly;
70static struct kmem_cache *batadv_tt_req_cache __read_mostly;
71static struct kmem_cache *batadv_tt_roam_cache __read_mostly;
72
Antonio Quartullidec05072012-11-10 11:00:32 +010073/* hash class keys */
74static struct lock_class_key batadv_tt_local_hash_lock_class_key;
75static struct lock_class_key batadv_tt_global_hash_lock_class_key;
76
Sven Eckelmann6b5e9712015-05-26 18:34:26 +020077static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
Antonio Quartullic018ad32013-06-04 12:11:39 +020078 unsigned short vid,
Sven Eckelmann56303d32012-06-05 22:31:31 +020079 struct batadv_orig_node *orig_node);
Sven Eckelmanna5130882012-05-16 20:23:16 +020080static void batadv_tt_purge(struct work_struct *work);
81static void
Sven Eckelmann56303d32012-06-05 22:31:31 +020082batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
Antonio Quartulli30cfd022012-07-05 23:38:29 +020083static void batadv_tt_global_del(struct batadv_priv *bat_priv,
84 struct batadv_orig_node *orig_node,
85 const unsigned char *addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +020086 unsigned short vid, const char *message,
87 bool roaming);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000088
Sven Eckelmann62fe7102015-09-15 19:00:48 +020089/**
Antonio Quartullid15cd622015-11-17 16:40:52 +080090 * batadv_compare_tt - check if two TT entries are the same
91 * @node: the list element pointer of the first TT entry
92 * @data2: pointer to the tt_common_entry of the second TT entry
Sven Eckelmann62fe7102015-09-15 19:00:48 +020093 *
Antonio Quartullid15cd622015-11-17 16:40:52 +080094 * Compare the MAC address and the VLAN ID of the two TT entries and check if
95 * they are the same TT client.
Sven Eckelmann4b426b12016-02-22 21:02:39 +010096 * Return: true if the two TT clients are the same, false otherwise
Sven Eckelmann62fe7102015-09-15 19:00:48 +020097 */
Sven Eckelmann4b426b12016-02-22 21:02:39 +010098static bool batadv_compare_tt(const struct hlist_node *node, const void *data2)
Marek Lindner7aadf882011-02-18 12:28:09 +000099{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200100 const void *data1 = container_of(node, struct batadv_tt_common_entry,
Sven Eckelmann747e4222011-05-14 23:14:50 +0200101 hash_entry);
Marek Lindner4c718952015-08-06 10:38:54 +0200102 const struct batadv_tt_common_entry *tt1 = data1;
103 const struct batadv_tt_common_entry *tt2 = data2;
Marek Lindner7aadf882011-02-18 12:28:09 +0000104
Marek Lindner4c718952015-08-06 10:38:54 +0200105 return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
Marek Lindner7aadf882011-02-18 12:28:09 +0000106}
107
Antonio Quartullic018ad32013-06-04 12:11:39 +0200108/**
109 * batadv_choose_tt - return the index of the tt entry in the hash table
110 * @data: pointer to the tt_common_entry object to map
111 * @size: the size of the hash table
112 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200113 * Return: the hash index where the object represented by 'data' should be
Antonio Quartullic018ad32013-06-04 12:11:39 +0200114 * stored at.
115 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200116static inline u32 batadv_choose_tt(const void *data, u32 size)
Antonio Quartullic018ad32013-06-04 12:11:39 +0200117{
118 struct batadv_tt_common_entry *tt;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200119 u32 hash = 0;
Antonio Quartullic018ad32013-06-04 12:11:39 +0200120
121 tt = (struct batadv_tt_common_entry *)data;
Sven Eckelmann36fd61c2015-03-01 09:46:18 +0100122 hash = jhash(&tt->addr, ETH_ALEN, hash);
123 hash = jhash(&tt->vid, sizeof(tt->vid), hash);
Antonio Quartullic018ad32013-06-04 12:11:39 +0200124
125 return hash % size;
126}
127
128/**
129 * batadv_tt_hash_find - look for a client in the given hash table
130 * @hash: the hash table to search
131 * @addr: the mac address of the client to look for
132 * @vid: VLAN identifier
133 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200134 * Return: a pointer to the tt_common struct belonging to the searched client if
Antonio Quartullic018ad32013-06-04 12:11:39 +0200135 * found, NULL otherwise.
136 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200137static struct batadv_tt_common_entry *
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200138batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +0200139 unsigned short vid)
Marek Lindner7aadf882011-02-18 12:28:09 +0000140{
Marek Lindner7aadf882011-02-18 12:28:09 +0000141 struct hlist_head *head;
Antonio Quartullic018ad32013-06-04 12:11:39 +0200142 struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200143 u32 index;
Marek Lindner7aadf882011-02-18 12:28:09 +0000144
145 if (!hash)
146 return NULL;
147
Antonio Quartulli8fdd0152014-01-22 00:42:11 +0100148 ether_addr_copy(to_search.addr, addr);
Antonio Quartullic018ad32013-06-04 12:11:39 +0200149 to_search.vid = vid;
150
151 index = batadv_choose_tt(&to_search, hash->size);
Marek Lindner7aadf882011-02-18 12:28:09 +0000152 head = &hash->table[index];
153
154 rcu_read_lock();
Antonio Quartullic018ad32013-06-04 12:11:39 +0200155 hlist_for_each_entry_rcu(tt, head, hash_entry) {
156 if (!batadv_compare_eth(tt, addr))
Marek Lindner7aadf882011-02-18 12:28:09 +0000157 continue;
158
Antonio Quartullic018ad32013-06-04 12:11:39 +0200159 if (tt->vid != vid)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200160 continue;
161
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100162 if (!kref_get_unless_zero(&tt->refcount))
Antonio Quartullic018ad32013-06-04 12:11:39 +0200163 continue;
164
165 tt_tmp = tt;
Marek Lindner7aadf882011-02-18 12:28:09 +0000166 break;
167 }
168 rcu_read_unlock();
169
Antonio Quartullic018ad32013-06-04 12:11:39 +0200170 return tt_tmp;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100171}
172
Antonio Quartullic018ad32013-06-04 12:11:39 +0200173/**
174 * batadv_tt_local_hash_find - search the local table for a given client
175 * @bat_priv: the bat priv with all the soft interface information
176 * @addr: the mac address of the client to look for
177 * @vid: VLAN identifier
178 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200179 * Return: a pointer to the corresponding tt_local_entry struct if the client is
Antonio Quartullic018ad32013-06-04 12:11:39 +0200180 * found, NULL otherwise.
181 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200182static struct batadv_tt_local_entry *
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200183batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +0200184 unsigned short vid)
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100185{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200186 struct batadv_tt_common_entry *tt_common_entry;
187 struct batadv_tt_local_entry *tt_local_entry = NULL;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100188
Antonio Quartullic018ad32013-06-04 12:11:39 +0200189 tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr,
190 vid);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100191 if (tt_common_entry)
192 tt_local_entry = container_of(tt_common_entry,
Sven Eckelmann56303d32012-06-05 22:31:31 +0200193 struct batadv_tt_local_entry,
194 common);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100195 return tt_local_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000196}
197
Antonio Quartullic018ad32013-06-04 12:11:39 +0200198/**
199 * batadv_tt_global_hash_find - search the global table for a given client
200 * @bat_priv: the bat priv with all the soft interface information
201 * @addr: the mac address of the client to look for
202 * @vid: VLAN identifier
203 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200204 * Return: a pointer to the corresponding tt_global_entry struct if the client
Antonio Quartullic018ad32013-06-04 12:11:39 +0200205 * is found, NULL otherwise.
206 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200207static struct batadv_tt_global_entry *
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200208batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +0200209 unsigned short vid)
Marek Lindner7aadf882011-02-18 12:28:09 +0000210{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200211 struct batadv_tt_common_entry *tt_common_entry;
212 struct batadv_tt_global_entry *tt_global_entry = NULL;
Marek Lindner7aadf882011-02-18 12:28:09 +0000213
Antonio Quartullic018ad32013-06-04 12:11:39 +0200214 tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr,
215 vid);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100216 if (tt_common_entry)
217 tt_global_entry = container_of(tt_common_entry,
Sven Eckelmann56303d32012-06-05 22:31:31 +0200218 struct batadv_tt_global_entry,
219 common);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100220 return tt_global_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000221}
222
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100223/**
Sven Eckelmann86452f82016-06-25 16:44:06 +0200224 * batadv_tt_local_entry_free_rcu - free the tt_local_entry
225 * @rcu: rcu pointer of the tt_local_entry
226 */
227static void batadv_tt_local_entry_free_rcu(struct rcu_head *rcu)
228{
229 struct batadv_tt_local_entry *tt_local_entry;
230
231 tt_local_entry = container_of(rcu, struct batadv_tt_local_entry,
232 common.rcu);
233
234 kmem_cache_free(batadv_tl_cache, tt_local_entry);
235}
236
237/**
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100238 * batadv_tt_local_entry_release - release tt_local_entry from lists and queue
239 * for free after rcu grace period
240 * @ref: kref pointer of the nc_node
241 */
242static void batadv_tt_local_entry_release(struct kref *ref)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200243{
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100244 struct batadv_tt_local_entry *tt_local_entry;
245
246 tt_local_entry = container_of(ref, struct batadv_tt_local_entry,
247 common.refcount);
248
Sven Eckelmanna33d9702016-03-11 16:44:05 +0100249 batadv_softif_vlan_put(tt_local_entry->vlan);
250
Sven Eckelmann86452f82016-06-25 16:44:06 +0200251 call_rcu(&tt_local_entry->common.rcu, batadv_tt_local_entry_free_rcu);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200252}
253
Antonio Quartulli21026052013-05-07 00:29:22 +0200254/**
Sven Eckelmann95c0db92016-01-17 11:01:25 +0100255 * batadv_tt_local_entry_put - decrement the tt_local_entry refcounter and
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100256 * possibly release it
257 * @tt_local_entry: tt_local_entry to be free'd
258 */
259static void
Sven Eckelmann95c0db92016-01-17 11:01:25 +0100260batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry)
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100261{
262 kref_put(&tt_local_entry->common.refcount,
263 batadv_tt_local_entry_release);
264}
265
266/**
Sven Eckelmann86452f82016-06-25 16:44:06 +0200267 * batadv_tt_global_entry_free_rcu - free the tt_global_entry
268 * @rcu: rcu pointer of the tt_global_entry
269 */
270static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu)
271{
272 struct batadv_tt_global_entry *tt_global_entry;
273
274 tt_global_entry = container_of(rcu, struct batadv_tt_global_entry,
275 common.rcu);
276
277 kmem_cache_free(batadv_tg_cache, tt_global_entry);
278}
279
280/**
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100281 * batadv_tt_global_entry_release - release tt_global_entry from lists and queue
282 * for free after rcu grace period
283 * @ref: kref pointer of the nc_node
284 */
285static void batadv_tt_global_entry_release(struct kref *ref)
286{
287 struct batadv_tt_global_entry *tt_global_entry;
288
289 tt_global_entry = container_of(ref, struct batadv_tt_global_entry,
290 common.refcount);
291
292 batadv_tt_global_del_orig_list(tt_global_entry);
Sven Eckelmann86452f82016-06-25 16:44:06 +0200293
294 call_rcu(&tt_global_entry->common.rcu, batadv_tt_global_entry_free_rcu);
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100295}
296
297/**
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +0100298 * batadv_tt_global_entry_put - decrement the tt_global_entry refcounter and
299 * possibly release it
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100300 * @tt_global_entry: tt_global_entry to be free'd
Antonio Quartulli21026052013-05-07 00:29:22 +0200301 */
Sven Eckelmanna5130882012-05-16 20:23:16 +0200302static void
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +0100303batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200304{
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100305 kref_put(&tt_global_entry->common.refcount,
306 batadv_tt_global_entry_release);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200307}
308
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +0100309/**
310 * batadv_tt_global_hash_count - count the number of orig entries
Antonio Quartullid15cd622015-11-17 16:40:52 +0800311 * @bat_priv: the bat priv with all the soft interface information
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +0100312 * @addr: the mac address of the client to count entries for
313 * @vid: VLAN identifier
314 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200315 * Return: the number of originators advertising the given address/data
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +0100316 * (excluding ourself).
317 */
318int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200319 const u8 *addr, unsigned short vid)
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +0100320{
321 struct batadv_tt_global_entry *tt_global_entry;
322 int count;
323
324 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
325 if (!tt_global_entry)
326 return 0;
327
328 count = atomic_read(&tt_global_entry->orig_list_count);
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +0100329 batadv_tt_global_entry_put(tt_global_entry);
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +0100330
331 return count;
332}
333
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200334/**
335 * batadv_tt_local_size_mod - change the size by v of the local table identified
336 * by vid
337 * @bat_priv: the bat priv with all the soft interface information
338 * @vid: the VLAN identifier of the sub-table to change
339 * @v: the amount to sum to the local table size
340 */
341static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
342 unsigned short vid, int v)
343{
344 struct batadv_softif_vlan *vlan;
345
346 vlan = batadv_softif_vlan_get(bat_priv, vid);
347 if (!vlan)
348 return;
349
350 atomic_add(v, &vlan->tt.num_entries);
351
Sven Eckelmann9c3bf082016-01-17 11:01:21 +0100352 batadv_softif_vlan_put(vlan);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200353}
354
355/**
356 * batadv_tt_local_size_inc - increase by one the local table size for the given
357 * vid
358 * @bat_priv: the bat priv with all the soft interface information
359 * @vid: the VLAN identifier
360 */
361static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
362 unsigned short vid)
363{
364 batadv_tt_local_size_mod(bat_priv, vid, 1);
365}
366
367/**
368 * batadv_tt_local_size_dec - decrease by one the local table size for the given
369 * vid
370 * @bat_priv: the bat priv with all the soft interface information
371 * @vid: the VLAN identifier
372 */
373static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
374 unsigned short vid)
375{
376 batadv_tt_local_size_mod(bat_priv, vid, -1);
377}
378
379/**
Antonio Quartullid15cd622015-11-17 16:40:52 +0800380 * batadv_tt_global_size_mod - change the size by v of the global table
381 * for orig_node identified by vid
382 * @orig_node: the originator for which the table has to be modified
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200383 * @vid: the VLAN identifier
384 * @v: the amount to sum to the global table size
385 */
386static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node,
387 unsigned short vid, int v)
388{
389 struct batadv_orig_node_vlan *vlan;
390
391 vlan = batadv_orig_node_vlan_new(orig_node, vid);
392 if (!vlan)
393 return;
394
395 if (atomic_add_return(v, &vlan->tt.num_entries) == 0) {
396 spin_lock_bh(&orig_node->vlan_list_lock);
Sven Eckelmann3db15202016-01-31 13:28:00 +0100397 if (!hlist_unhashed(&vlan->list)) {
398 hlist_del_init_rcu(&vlan->list);
Sven Eckelmann21754e22016-01-17 11:01:24 +0100399 batadv_orig_node_vlan_put(vlan);
Sven Eckelmann3db15202016-01-31 13:28:00 +0100400 }
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200401 spin_unlock_bh(&orig_node->vlan_list_lock);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200402 }
403
Sven Eckelmann21754e22016-01-17 11:01:24 +0100404 batadv_orig_node_vlan_put(vlan);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200405}
406
407/**
408 * batadv_tt_global_size_inc - increase by one the global table size for the
409 * given vid
410 * @orig_node: the originator which global table size has to be decreased
411 * @vid: the vlan identifier
412 */
413static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node,
414 unsigned short vid)
415{
416 batadv_tt_global_size_mod(orig_node, vid, 1);
417}
418
419/**
420 * batadv_tt_global_size_dec - decrease by one the global table size for the
421 * given vid
422 * @orig_node: the originator which global table size has to be decreased
423 * @vid: the vlan identifier
424 */
425static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node,
426 unsigned short vid)
427{
428 batadv_tt_global_size_mod(orig_node, vid, -1);
429}
430
Sven Eckelmann42eff6a2016-01-05 12:06:20 +0100431/**
Sven Eckelmann86452f82016-06-25 16:44:06 +0200432 * batadv_tt_orig_list_entry_free_rcu - free the orig_entry
433 * @rcu: rcu pointer of the orig_entry
434 */
435static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
436{
437 struct batadv_tt_orig_list_entry *orig_entry;
438
439 orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu);
440
441 kmem_cache_free(batadv_tt_orig_cache, orig_entry);
442}
443
444/**
Sven Eckelmann42eff6a2016-01-05 12:06:20 +0100445 * batadv_tt_orig_list_entry_release - release tt orig entry from lists and
446 * queue for free after rcu grace period
Sven Eckelmann6e8ef692016-01-16 10:29:50 +0100447 * @ref: kref pointer of the tt orig entry
Sven Eckelmann42eff6a2016-01-05 12:06:20 +0100448 */
Sven Eckelmann6e8ef692016-01-16 10:29:50 +0100449static void batadv_tt_orig_list_entry_release(struct kref *ref)
Sven Eckelmann42eff6a2016-01-05 12:06:20 +0100450{
Sven Eckelmann6e8ef692016-01-16 10:29:50 +0100451 struct batadv_tt_orig_list_entry *orig_entry;
452
453 orig_entry = container_of(ref, struct batadv_tt_orig_list_entry,
454 refcount);
455
Sven Eckelmann5d967312016-01-17 11:01:09 +0100456 batadv_orig_node_put(orig_entry->orig_node);
Sven Eckelmann86452f82016-06-25 16:44:06 +0200457 call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
Sven Eckelmann42eff6a2016-01-05 12:06:20 +0100458}
459
Sven Eckelmann6e8ef692016-01-16 10:29:50 +0100460/**
Sven Eckelmann7e2366c2016-01-17 11:01:27 +0100461 * batadv_tt_orig_list_entry_put - decrement the tt orig entry refcounter and
462 * possibly release it
Sven Eckelmann6e8ef692016-01-16 10:29:50 +0100463 * @orig_entry: tt orig entry to be free'd
464 */
Sven Eckelmanna5130882012-05-16 20:23:16 +0200465static void
Sven Eckelmann7e2366c2016-01-17 11:01:27 +0100466batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200467{
Sven Eckelmann6e8ef692016-01-16 10:29:50 +0100468 kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200469}
470
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200471/**
472 * batadv_tt_local_event - store a local TT event (ADD/DEL)
473 * @bat_priv: the bat priv with all the soft interface information
474 * @tt_local_entry: the TT entry involved in the event
475 * @event_flags: flags to store in the event structure
476 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200477static void batadv_tt_local_event(struct batadv_priv *bat_priv,
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200478 struct batadv_tt_local_entry *tt_local_entry,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200479 u8 event_flags)
Antonio Quartullia73105b2011-04-27 14:27:44 +0200480{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200481 struct batadv_tt_change_node *tt_change_node, *entry, *safe;
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200482 struct batadv_tt_common_entry *common = &tt_local_entry->common;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200483 u8 flags = common->flags | event_flags;
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200484 bool event_removed = false;
485 bool del_op_requested, del_op_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200486
Sven Eckelmann86452f82016-06-25 16:44:06 +0200487 tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200488 if (!tt_change_node)
489 return;
490
Antonio Quartulliff66c972011-06-30 01:14:00 +0200491 tt_change_node->change.flags = flags;
Antonio Quartullica663042013-12-15 13:26:55 +0100492 memset(tt_change_node->change.reserved, 0,
493 sizeof(tt_change_node->change.reserved));
Antonio Quartulli8fdd0152014-01-22 00:42:11 +0100494 ether_addr_copy(tt_change_node->change.addr, common->addr);
Antonio Quartullic018ad32013-06-04 12:11:39 +0200495 tt_change_node->change.vid = htons(common->vid);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200496
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200497 del_op_requested = flags & BATADV_TT_CLIENT_DEL;
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200498
499 /* check for ADD+DEL or DEL+ADD events */
Sven Eckelmann807736f2012-07-15 22:26:51 +0200500 spin_lock_bh(&bat_priv->tt.changes_list_lock);
501 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200502 list) {
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200503 if (!batadv_compare_eth(entry->change.addr, common->addr))
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200504 continue;
505
506 /* DEL+ADD in the same orig interval have no effect and can be
507 * removed to avoid silly behaviour on the receiver side. The
508 * other way around (ADD+DEL) can happen in case of roaming of
509 * a client still in the NEW state. Roaming of NEW clients is
510 * now possible due to automatically recognition of "temporary"
511 * clients
512 */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200513 del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200514 if (!del_op_requested && del_op_entry)
515 goto del;
516 if (del_op_requested && !del_op_entry)
517 goto del;
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200518
519 /* this is a second add in the same originator interval. It
520 * means that flags have been changed: update them!
521 */
522 if (!del_op_requested && !del_op_entry)
523 entry->change.flags = flags;
524
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200525 continue;
526del:
527 list_del(&entry->list);
Sven Eckelmann86452f82016-06-25 16:44:06 +0200528 kmem_cache_free(batadv_tt_change_cache, entry);
529 kmem_cache_free(batadv_tt_change_cache, tt_change_node);
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200530 event_removed = true;
531 goto unlock;
532 }
533
Antonio Quartullia73105b2011-04-27 14:27:44 +0200534 /* track the change in the OGMinterval list */
Sven Eckelmann807736f2012-07-15 22:26:51 +0200535 list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list);
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200536
537unlock:
Sven Eckelmann807736f2012-07-15 22:26:51 +0200538 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200539
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200540 if (event_removed)
Sven Eckelmann807736f2012-07-15 22:26:51 +0200541 atomic_dec(&bat_priv->tt.local_changes);
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200542 else
Sven Eckelmann807736f2012-07-15 22:26:51 +0200543 atomic_inc(&bat_priv->tt.local_changes);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200544}
545
Marek Lindner335fbe02013-04-23 21:40:02 +0800546/**
547 * batadv_tt_len - compute length in bytes of given number of tt changes
548 * @changes_num: number of tt changes
549 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200550 * Return: computed length in bytes.
Marek Lindner335fbe02013-04-23 21:40:02 +0800551 */
552static int batadv_tt_len(int changes_num)
Antonio Quartullia73105b2011-04-27 14:27:44 +0200553{
Marek Lindner335fbe02013-04-23 21:40:02 +0800554 return changes_num * sizeof(struct batadv_tvlv_tt_change);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200555}
556
Antonio Quartulli298e6e62013-05-28 13:14:27 +0200557/**
558 * batadv_tt_entries - compute the number of entries fitting in tt_len bytes
559 * @tt_len: available space
560 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200561 * Return: the number of entries.
Antonio Quartulli298e6e62013-05-28 13:14:27 +0200562 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200563static u16 batadv_tt_entries(u16 tt_len)
Antonio Quartulli298e6e62013-05-28 13:14:27 +0200564{
565 return tt_len / batadv_tt_len(1);
566}
567
Marek Lindnera19d3d82013-05-27 15:33:25 +0800568/**
569 * batadv_tt_local_table_transmit_size - calculates the local translation table
570 * size when transmitted over the air
571 * @bat_priv: the bat priv with all the soft interface information
572 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200573 * Return: local translation table size in bytes.
Marek Lindnera19d3d82013-05-27 15:33:25 +0800574 */
575static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
576{
Sven Eckelmann4f248cf2015-06-09 20:50:49 +0200577 u16 num_vlan = 0;
578 u16 tt_local_entries = 0;
Marek Lindnera19d3d82013-05-27 15:33:25 +0800579 struct batadv_softif_vlan *vlan;
580 int hdr_size;
581
582 rcu_read_lock();
583 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
584 num_vlan++;
585 tt_local_entries += atomic_read(&vlan->tt.num_entries);
586 }
587 rcu_read_unlock();
588
589 /* header size of tvlv encapsulated tt response payload */
590 hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
591 hdr_size += sizeof(struct batadv_tvlv_hdr);
592 hdr_size += sizeof(struct batadv_tvlv_tt_data);
593 hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
594
595 return hdr_size + batadv_tt_len(tt_local_entries);
596}
597
Sven Eckelmann56303d32012-06-05 22:31:31 +0200598static int batadv_tt_local_init(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000599{
Sven Eckelmann807736f2012-07-15 22:26:51 +0200600 if (bat_priv->tt.local_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200601 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000602
Sven Eckelmann807736f2012-07-15 22:26:51 +0200603 bat_priv->tt.local_hash = batadv_hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000604
Sven Eckelmann807736f2012-07-15 22:26:51 +0200605 if (!bat_priv->tt.local_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200606 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000607
Antonio Quartullidec05072012-11-10 11:00:32 +0100608 batadv_hash_set_lock_class(bat_priv->tt.local_hash,
609 &batadv_tt_local_hash_lock_class_key);
610
Sven Eckelmann5346c352012-05-05 13:27:28 +0200611 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000612}
613
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200614static void batadv_tt_global_free(struct batadv_priv *bat_priv,
615 struct batadv_tt_global_entry *tt_global,
616 const char *message)
617{
Sven Eckelmann8223fbc2019-02-23 14:27:10 +0100618 struct batadv_tt_global_entry *tt_removed_entry;
619 struct hlist_node *tt_removed_node;
620
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200621 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200622 "Deleting global tt entry %pM (vid: %d): %s\n",
623 tt_global->common.addr,
624 BATADV_PRINT_VID(tt_global->common.vid), message);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200625
Sven Eckelmann8223fbc2019-02-23 14:27:10 +0100626 tt_removed_node = batadv_hash_remove(bat_priv->tt.global_hash,
627 batadv_compare_tt,
628 batadv_choose_tt,
629 &tt_global->common);
630 if (!tt_removed_node)
631 return;
632
633 /* drop reference of remove hash entry */
634 tt_removed_entry = hlist_entry(tt_removed_node,
635 struct batadv_tt_global_entry,
636 common.hash_entry);
637 batadv_tt_global_entry_put(tt_removed_entry);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200638}
639
Antonio Quartullic018ad32013-06-04 12:11:39 +0200640/**
641 * batadv_tt_local_add - add a new client to the local table or update an
642 * existing client
643 * @soft_iface: netdev struct of the mesh interface
644 * @addr: the mac address of the client to add
645 * @vid: VLAN identifier
646 * @ifindex: index of the interface where the client is connected to (useful to
647 * identify wireless clients)
Antonio Quartulli9464d072013-11-16 12:03:48 +0100648 * @mark: the value contained in the skb->mark field of the received packet (if
649 * any)
Marek Lindnera19d3d82013-05-27 15:33:25 +0800650 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200651 * Return: true if the client was successfully added, false otherwise.
Antonio Quartullic018ad32013-06-04 12:11:39 +0200652 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200653bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
654 unsigned short vid, int ifindex, u32 mark)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000655{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200656 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
Sven Eckelmann170173b2012-10-07 12:02:22 +0200657 struct batadv_tt_local_entry *tt_local;
Linus Lüssingc5caf4e2014-02-15 17:47:49 +0100658 struct batadv_tt_global_entry *tt_global = NULL;
Andrew Lunn2cd45a02016-04-21 12:57:27 +0200659 struct net *net = dev_net(soft_iface);
Antonio Quartulli35df3b22014-05-08 17:13:15 +0200660 struct batadv_softif_vlan *vlan;
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200661 struct net_device *in_dev = NULL;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200662 struct hlist_head *head;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200663 struct batadv_tt_orig_list_entry *orig_entry;
Marek Lindnera19d3d82013-05-27 15:33:25 +0800664 int hash_added, table_size, packet_size_max;
Sven Eckelmann4f248cf2015-06-09 20:50:49 +0200665 bool ret = false;
666 bool roamed_back = false;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200667 u8 remote_flags;
668 u32 match_mark;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000669
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200670 if (ifindex != BATADV_NULL_IFINDEX)
Andrew Lunn2cd45a02016-04-21 12:57:27 +0200671 in_dev = dev_get_by_index(net, ifindex);
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200672
Antonio Quartullic018ad32013-06-04 12:11:39 +0200673 tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
Linus Lüssingc5caf4e2014-02-15 17:47:49 +0100674
675 if (!is_multicast_ether_addr(addr))
676 tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000677
Antonio Quartulli47c94652012-09-23 22:38:35 +0200678 if (tt_local) {
679 tt_local->last_seen = jiffies;
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200680 if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
681 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200682 "Re-adding pending client %pM (vid: %d)\n",
683 addr, BATADV_PRINT_VID(vid));
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200684 /* whatever the reason why the PENDING flag was set,
685 * this is a client which was enqueued to be removed in
686 * this orig_interval. Since it popped up again, the
687 * flag can be reset like it was never enqueued
688 */
689 tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
690 goto add_event;
691 }
692
693 if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
694 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200695 "Roaming client %pM (vid: %d) came back to its original location\n",
696 addr, BATADV_PRINT_VID(vid));
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200697 /* the ROAM flag is set because this client roamed away
698 * and the node got a roaming_advertisement message. Now
699 * that the client popped up again at its original
700 * location such flag can be unset
701 */
702 tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
703 roamed_back = true;
704 }
705 goto check_roaming;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000706 }
707
Marek Lindnera19d3d82013-05-27 15:33:25 +0800708 /* Ignore the client if we cannot send it in a full table response. */
709 table_size = batadv_tt_local_table_transmit_size(bat_priv);
710 table_size += batadv_tt_len(1);
711 packet_size_max = atomic_read(&bat_priv->packet_size_max);
712 if (table_size > packet_size_max) {
713 net_ratelimited_function(batadv_info, soft_iface,
714 "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
715 table_size, packet_size_max, addr);
716 goto out;
717 }
718
Sven Eckelmann86452f82016-06-25 16:44:06 +0200719 tt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);
Antonio Quartulli47c94652012-09-23 22:38:35 +0200720 if (!tt_local)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200721 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200722
Antonio Quartulli35df3b22014-05-08 17:13:15 +0200723 /* increase the refcounter of the related vlan */
724 vlan = batadv_softif_vlan_get(bat_priv, vid);
Simon Wunderlich0b3dd7d2016-06-26 11:16:09 +0200725 if (!vlan) {
726 net_ratelimited_function(batadv_info, soft_iface,
727 "adding TT local entry %pM to non-existent VLAN %d\n",
728 addr, BATADV_PRINT_VID(vid));
Sven Eckelmann86452f82016-06-25 16:44:06 +0200729 kmem_cache_free(batadv_tl_cache, tt_local);
Sven Eckelmannfd7dec22015-08-18 13:37:01 +0200730 tt_local = NULL;
Marek Lindner354136b2015-06-09 21:24:36 +0800731 goto out;
Sven Eckelmannfd7dec22015-08-18 13:37:01 +0200732 }
Antonio Quartulli35df3b22014-05-08 17:13:15 +0200733
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200734 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200735 "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
736 addr, BATADV_PRINT_VID(vid),
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200737 (u8)atomic_read(&bat_priv->tt.vn));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000738
Antonio Quartulli8fdd0152014-01-22 00:42:11 +0100739 ether_addr_copy(tt_local->common.addr, addr);
Antonio Quartulli8425ec62012-11-19 09:01:44 +0100740 /* The local entry has to be marked as NEW to avoid to send it in
741 * a full table response going out before the next ttvn increment
742 * (consistency check)
743 */
744 tt_local->common.flags = BATADV_TT_CLIENT_NEW;
Antonio Quartullic018ad32013-06-04 12:11:39 +0200745 tt_local->common.vid = vid;
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200746 if (batadv_is_wifi_netdev(in_dev))
Antonio Quartulli47c94652012-09-23 22:38:35 +0200747 tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
Sven Eckelmann92dcdf02016-01-16 10:29:57 +0100748 kref_init(&tt_local->common.refcount);
Antonio Quartulli47c94652012-09-23 22:38:35 +0200749 tt_local->last_seen = jiffies;
750 tt_local->common.added_at = tt_local->last_seen;
Sven Eckelmanna33d9702016-03-11 16:44:05 +0100751 tt_local->vlan = vlan;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000752
Linus Lüssingc5caf4e2014-02-15 17:47:49 +0100753 /* the batman interface mac and multicast addresses should never be
754 * purged
755 */
756 if (batadv_compare_eth(addr, soft_iface->dev_addr) ||
757 is_multicast_ether_addr(addr))
Antonio Quartulli47c94652012-09-23 22:38:35 +0200758 tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000759
Sven Eckelmanne3387b22016-07-15 17:39:22 +0200760 kref_get(&tt_local->common.refcount);
Sven Eckelmann807736f2012-07-15 22:26:51 +0200761 hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
Antonio Quartullic018ad32013-06-04 12:11:39 +0200762 batadv_choose_tt, &tt_local->common,
Antonio Quartulli47c94652012-09-23 22:38:35 +0200763 &tt_local->common.hash_entry);
Simon Wunderlich80b3f582011-11-02 20:26:45 +0100764
765 if (unlikely(hash_added != 0)) {
766 /* remove the reference for the hash */
Sven Eckelmann95c0db92016-01-17 11:01:25 +0100767 batadv_tt_local_entry_put(tt_local);
Simon Wunderlich80b3f582011-11-02 20:26:45 +0100768 goto out;
769 }
770
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200771add_event:
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200772 batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
Antonio Quartulliff66c972011-06-30 01:14:00 +0200773
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200774check_roaming:
775 /* Check whether it is a roaming, but don't do anything if the roaming
776 * process has already been handled
777 */
778 if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200779 /* These node are probably going to update their tt table */
Antonio Quartulli47c94652012-09-23 22:38:35 +0200780 head = &tt_global->orig_list;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200781 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800782 hlist_for_each_entry_rcu(orig_entry, head, list) {
Antonio Quartulli47c94652012-09-23 22:38:35 +0200783 batadv_send_roam_adv(bat_priv, tt_global->common.addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +0200784 tt_global->common.vid,
Sven Eckelmanna5130882012-05-16 20:23:16 +0200785 orig_entry->orig_node);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200786 }
787 rcu_read_unlock();
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200788 if (roamed_back) {
789 batadv_tt_global_free(bat_priv, tt_global,
790 "Roaming canceled");
791 tt_global = NULL;
792 } else {
793 /* The global entry has to be marked as ROAMING and
794 * has to be kept for consistency purpose
795 */
796 tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
797 tt_global->roam_at = jiffies;
798 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200799 }
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200800
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200801 /* store the current remote flags before altering them. This helps
802 * understanding is flags are changing or not
803 */
804 remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
Marek Lindnera19d3d82013-05-27 15:33:25 +0800805
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200806 if (batadv_is_wifi_netdev(in_dev))
807 tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
808 else
809 tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
810
Antonio Quartulli9464d072013-11-16 12:03:48 +0100811 /* check the mark in the skb: if it's equal to the configured
812 * isolation_mark, it means the packet is coming from an isolated
813 * non-mesh client
814 */
815 match_mark = (mark & bat_priv->isolation_mark_mask);
816 if (bat_priv->isolation_mark_mask &&
817 match_mark == bat_priv->isolation_mark)
818 tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
819 else
820 tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
821
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200822 /* if any "dynamic" flag has been modified, resend an ADD event for this
823 * entry so that all the nodes can get the new flags
824 */
825 if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
826 batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
827
828 ret = true;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200829out:
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200830 if (in_dev)
831 dev_put(in_dev);
Antonio Quartulli47c94652012-09-23 22:38:35 +0200832 if (tt_local)
Sven Eckelmann95c0db92016-01-17 11:01:25 +0100833 batadv_tt_local_entry_put(tt_local);
Antonio Quartulli47c94652012-09-23 22:38:35 +0200834 if (tt_global)
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +0100835 batadv_tt_global_entry_put(tt_global);
Marek Lindnera19d3d82013-05-27 15:33:25 +0800836 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000837}
838
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800839/**
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200840 * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send
841 * within a TT Response directed to another node
842 * @orig_node: originator for which the TT data has to be prepared
843 * @tt_data: uninitialised pointer to the address of the TVLV buffer
844 * @tt_change: uninitialised pointer to the address of the area where the TT
845 * changed can be stored
846 * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
847 * function reserves the amount of space needed to send the entire global TT
848 * table. In case of success the value is updated with the real amount of
849 * reserved bytes
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200850 * Allocate the needed amount of memory for the entire TT TVLV and write its
851 * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
852 * objects, one per active VLAN served by the originator node.
853 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200854 * Return: the size of the allocated buffer or 0 in case of failure.
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200855 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200856static u16
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200857batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
858 struct batadv_tvlv_tt_data **tt_data,
859 struct batadv_tvlv_tt_change **tt_change,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200860 s32 *tt_len)
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200861{
Sven Eckelmann4f248cf2015-06-09 20:50:49 +0200862 u16 num_vlan = 0;
863 u16 num_entries = 0;
864 u16 change_offset;
865 u16 tvlv_len;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200866 struct batadv_tvlv_tt_vlan_data *tt_vlan;
867 struct batadv_orig_node_vlan *vlan;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200868 u8 *tt_change_ptr;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200869
Sven Eckelmannf4d59332020-03-16 23:30:54 +0100870 spin_lock_bh(&orig_node->vlan_list_lock);
Marek Lindnerd0fa4f32015-06-22 00:30:22 +0800871 hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200872 num_vlan++;
873 num_entries += atomic_read(&vlan->tt.num_entries);
874 }
875
876 change_offset = sizeof(**tt_data);
877 change_offset += num_vlan * sizeof(*tt_vlan);
878
879 /* if tt_len is negative, allocate the space needed by the full table */
880 if (*tt_len < 0)
881 *tt_len = batadv_tt_len(num_entries);
882
883 tvlv_len = *tt_len;
884 tvlv_len += change_offset;
885
886 *tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
887 if (!*tt_data) {
888 *tt_len = 0;
889 goto out;
890 }
891
892 (*tt_data)->flags = BATADV_NO_FLAGS;
893 (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn);
894 (*tt_data)->num_vlan = htons(num_vlan);
895
896 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
Marek Lindnerd0fa4f32015-06-22 00:30:22 +0800897 hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200898 tt_vlan->vid = htons(vlan->vid);
899 tt_vlan->crc = htonl(vlan->tt.crc);
900
901 tt_vlan++;
902 }
903
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200904 tt_change_ptr = (u8 *)*tt_data + change_offset;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200905 *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
906
907out:
Sven Eckelmannf4d59332020-03-16 23:30:54 +0100908 spin_unlock_bh(&orig_node->vlan_list_lock);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200909 return tvlv_len;
910}
911
912/**
913 * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this
914 * node
915 * @bat_priv: the bat priv with all the soft interface information
916 * @tt_data: uninitialised pointer to the address of the TVLV buffer
917 * @tt_change: uninitialised pointer to the address of the area where the TT
918 * changes can be stored
919 * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
920 * function reserves the amount of space needed to send the entire local TT
921 * table. In case of success the value is updated with the real amount of
922 * reserved bytes
923 *
924 * Allocate the needed amount of memory for the entire TT TVLV and write its
925 * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
926 * objects, one per active VLAN.
927 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200928 * Return: the size of the allocated buffer or 0 in case of failure.
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200929 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200930static u16
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200931batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
932 struct batadv_tvlv_tt_data **tt_data,
933 struct batadv_tvlv_tt_change **tt_change,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200934 s32 *tt_len)
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200935{
936 struct batadv_tvlv_tt_vlan_data *tt_vlan;
937 struct batadv_softif_vlan *vlan;
Sven Eckelmann4f248cf2015-06-09 20:50:49 +0200938 u16 num_vlan = 0;
939 u16 num_entries = 0;
940 u16 tvlv_len;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200941 u8 *tt_change_ptr;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200942 int change_offset;
943
Sven Eckelmannf4d59332020-03-16 23:30:54 +0100944 spin_lock_bh(&bat_priv->softif_vlan_list_lock);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200945 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
946 num_vlan++;
947 num_entries += atomic_read(&vlan->tt.num_entries);
948 }
949
950 change_offset = sizeof(**tt_data);
951 change_offset += num_vlan * sizeof(*tt_vlan);
952
953 /* if tt_len is negative, allocate the space needed by the full table */
954 if (*tt_len < 0)
955 *tt_len = batadv_tt_len(num_entries);
956
957 tvlv_len = *tt_len;
958 tvlv_len += change_offset;
959
960 *tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
961 if (!*tt_data) {
962 tvlv_len = 0;
963 goto out;
964 }
965
966 (*tt_data)->flags = BATADV_NO_FLAGS;
967 (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn);
968 (*tt_data)->num_vlan = htons(num_vlan);
969
970 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
971 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
972 tt_vlan->vid = htons(vlan->vid);
973 tt_vlan->crc = htonl(vlan->tt.crc);
974
975 tt_vlan++;
976 }
977
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200978 tt_change_ptr = (u8 *)*tt_data + change_offset;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200979 *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
980
981out:
Sven Eckelmannf4d59332020-03-16 23:30:54 +0100982 spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200983 return tvlv_len;
984}
985
986/**
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800987 * batadv_tt_tvlv_container_update - update the translation table tvlv container
988 * after local tt changes have been committed
989 * @bat_priv: the bat priv with all the soft interface information
990 */
991static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000992{
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800993 struct batadv_tt_change_node *entry, *safe;
994 struct batadv_tvlv_tt_data *tt_data;
995 struct batadv_tvlv_tt_change *tt_change;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200996 int tt_diff_len, tt_change_len = 0;
Sven Eckelmann4f248cf2015-06-09 20:50:49 +0200997 int tt_diff_entries_num = 0;
998 int tt_diff_entries_count = 0;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200999 u16 tvlv_len;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001000
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001001 tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes);
1002 tt_diff_len = batadv_tt_len(tt_diff_entries_num);
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08001003
1004 /* if we have too many changes for one packet don't send any
1005 * and wait for the tt table request which will be fragmented
1006 */
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001007 if (tt_diff_len > bat_priv->soft_iface->mtu)
1008 tt_diff_len = 0;
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08001009
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001010 tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
1011 &tt_change, &tt_diff_len);
1012 if (!tvlv_len)
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001013 return;
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08001014
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001015 tt_data->flags = BATADV_TT_OGM_DIFF;
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08001016
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001017 if (tt_diff_len == 0)
1018 goto container_register;
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08001019
Sven Eckelmann807736f2012-07-15 22:26:51 +02001020 spin_lock_bh(&bat_priv->tt.changes_list_lock);
1021 atomic_set(&bat_priv->tt.local_changes, 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001022
Sven Eckelmann807736f2012-07-15 22:26:51 +02001023 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
Sven Eckelmann7c64fd92012-02-28 10:55:36 +01001024 list) {
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001025 if (tt_diff_entries_count < tt_diff_entries_num) {
1026 memcpy(tt_change + tt_diff_entries_count,
1027 &entry->change,
1028 sizeof(struct batadv_tvlv_tt_change));
1029 tt_diff_entries_count++;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001030 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02001031 list_del(&entry->list);
Sven Eckelmann86452f82016-06-25 16:44:06 +02001032 kmem_cache_free(batadv_tt_change_cache, entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001033 }
Sven Eckelmann807736f2012-07-15 22:26:51 +02001034 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001035
Antonio Quartullia73105b2011-04-27 14:27:44 +02001036 /* Keep the buffer for possible tt_request */
Sven Eckelmann807736f2012-07-15 22:26:51 +02001037 spin_lock_bh(&bat_priv->tt.last_changeset_lock);
1038 kfree(bat_priv->tt.last_changeset);
1039 bat_priv->tt.last_changeset_len = 0;
1040 bat_priv->tt.last_changeset = NULL;
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001041 tt_change_len = batadv_tt_len(tt_diff_entries_count);
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08001042 /* check whether this new OGM has no changes due to size problems */
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001043 if (tt_diff_entries_count > 0) {
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08001044 /* if kmalloc() fails we will reply with the full table
Antonio Quartullia73105b2011-04-27 14:27:44 +02001045 * instead of providing the diff
1046 */
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001047 bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC);
Sven Eckelmann807736f2012-07-15 22:26:51 +02001048 if (bat_priv->tt.last_changeset) {
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001049 memcpy(bat_priv->tt.last_changeset,
1050 tt_change, tt_change_len);
1051 bat_priv->tt.last_changeset_len = tt_diff_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001052 }
1053 }
Sven Eckelmann807736f2012-07-15 22:26:51 +02001054 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001055
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001056container_register:
1057 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001058 tvlv_len);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08001059 kfree(tt_data);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001060}
1061
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +02001062#ifdef CONFIG_BATMAN_ADV_DEBUGFS
Sven Eckelmann08c36d32012-05-12 02:09:39 +02001063int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001064{
1065 struct net_device *net_dev = (struct net_device *)seq->private;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001066 struct batadv_priv *bat_priv = netdev_priv(net_dev);
Sven Eckelmann807736f2012-07-15 22:26:51 +02001067 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001068 struct batadv_tt_common_entry *tt_common_entry;
Antonio Quartulli85766a82012-11-08 22:16:16 +01001069 struct batadv_tt_local_entry *tt_local;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001070 struct batadv_hard_iface *primary_if;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001071 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001072 u32 i;
Antonio Quartulli85766a82012-11-08 22:16:16 +01001073 int last_seen_secs;
1074 int last_seen_msecs;
1075 unsigned long last_seen_jiffies;
1076 bool no_purge;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001077 u16 np_flag = BATADV_TT_CLIENT_NOPURGE;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001078
Marek Lindner30da63a2012-08-03 17:15:46 +02001079 primary_if = batadv_seq_print_text_primary_if_get(seq);
1080 if (!primary_if)
Marek Lindner32ae9b22011-04-20 15:40:58 +02001081 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001082
Sven Eckelmann86ceb362012-03-07 09:07:45 +01001083 seq_printf(seq,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001084 "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001085 net_dev->name, (u8)atomic_read(&bat_priv->tt.vn));
Antonio Quartulli925a6f32016-03-12 10:30:18 +01001086 seq_puts(seq,
1087 " Client VID Flags Last seen (CRC )\n");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001088
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001089 for (i = 0; i < hash->size; i++) {
1090 head = &hash->table[i];
1091
Marek Lindner7aadf882011-02-18 12:28:09 +00001092 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08001093 hlist_for_each_entry_rcu(tt_common_entry,
Marek Lindner7aadf882011-02-18 12:28:09 +00001094 head, hash_entry) {
Antonio Quartulli85766a82012-11-08 22:16:16 +01001095 tt_local = container_of(tt_common_entry,
1096 struct batadv_tt_local_entry,
1097 common);
1098 last_seen_jiffies = jiffies - tt_local->last_seen;
1099 last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
1100 last_seen_secs = last_seen_msecs / 1000;
1101 last_seen_msecs = last_seen_msecs % 1000;
1102
1103 no_purge = tt_common_entry->flags & np_flag;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001104 seq_printf(seq,
Antonio Quartullidd24ddb2013-11-16 12:03:49 +01001105 " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n",
Sven Eckelmann7c64fd92012-02-28 10:55:36 +01001106 tt_common_entry->addr,
Antonio Quartulli16052782013-06-04 12:11:41 +02001107 BATADV_PRINT_VID(tt_common_entry->vid),
Sven Eckelmanna2f2b6c2015-04-23 18:22:24 +02001108 ((tt_common_entry->flags &
1109 BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
Antonio Quartulli85766a82012-11-08 22:16:16 +01001110 no_purge ? 'P' : '.',
Sven Eckelmanna2f2b6c2015-04-23 18:22:24 +02001111 ((tt_common_entry->flags &
1112 BATADV_TT_CLIENT_NEW) ? 'N' : '.'),
1113 ((tt_common_entry->flags &
1114 BATADV_TT_CLIENT_PENDING) ? 'X' : '.'),
1115 ((tt_common_entry->flags &
1116 BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
1117 ((tt_common_entry->flags &
1118 BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
Antonio Quartullia7966d92013-01-24 11:41:39 +01001119 no_purge ? 0 : last_seen_secs,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001120 no_purge ? 0 : last_seen_msecs,
Sven Eckelmanna33d9702016-03-11 16:44:05 +01001121 tt_local->vlan->tt.crc);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001122 }
Marek Lindner7aadf882011-02-18 12:28:09 +00001123 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001124 }
Marek Lindner32ae9b22011-04-20 15:40:58 +02001125out:
1126 if (primary_if)
Sven Eckelmann82047ad2016-01-17 11:01:10 +01001127 batadv_hardif_put(primary_if);
Marek Lindner30da63a2012-08-03 17:15:46 +02001128 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001129}
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +02001130#endif
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001131
Matthias Schifferd34f0552016-07-03 13:31:37 +02001132/**
1133 * batadv_tt_local_dump_entry - Dump one TT local entry into a message
1134 * @msg :Netlink message to dump into
1135 * @portid: Port making netlink request
1136 * @seq: Sequence number of netlink message
1137 * @bat_priv: The bat priv with all the soft interface information
1138 * @common: tt local & tt global common data
1139 *
1140 * Return: Error code, or 0 on success
1141 */
1142static int
1143batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
1144 struct batadv_priv *bat_priv,
1145 struct batadv_tt_common_entry *common)
1146{
1147 void *hdr;
1148 struct batadv_softif_vlan *vlan;
1149 struct batadv_tt_local_entry *local;
1150 unsigned int last_seen_msecs;
1151 u32 crc;
1152
1153 local = container_of(common, struct batadv_tt_local_entry, common);
1154 last_seen_msecs = jiffies_to_msecs(jiffies - local->last_seen);
1155
1156 vlan = batadv_softif_vlan_get(bat_priv, common->vid);
1157 if (!vlan)
1158 return 0;
1159
1160 crc = vlan->tt.crc;
1161
1162 batadv_softif_vlan_put(vlan);
1163
1164 hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
1165 NLM_F_MULTI,
1166 BATADV_CMD_GET_TRANSTABLE_LOCAL);
1167 if (!hdr)
1168 return -ENOBUFS;
1169
1170 if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
1171 nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
1172 nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
1173 nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags))
1174 goto nla_put_failure;
1175
1176 if (!(common->flags & BATADV_TT_CLIENT_NOPURGE) &&
1177 nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs))
1178 goto nla_put_failure;
1179
1180 genlmsg_end(msg, hdr);
1181 return 0;
1182
1183 nla_put_failure:
1184 genlmsg_cancel(msg, hdr);
1185 return -EMSGSIZE;
1186}
1187
1188/**
1189 * batadv_tt_local_dump_bucket - Dump one TT local bucket into a message
1190 * @msg: Netlink message to dump into
1191 * @portid: Port making netlink request
1192 * @seq: Sequence number of netlink message
1193 * @bat_priv: The bat priv with all the soft interface information
1194 * @head: Pointer to the list containing the local tt entries
1195 * @idx_s: Number of entries to skip
1196 *
1197 * Return: Error code, or 0 on success
1198 */
1199static int
1200batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
1201 struct batadv_priv *bat_priv,
1202 struct hlist_head *head, int *idx_s)
1203{
1204 struct batadv_tt_common_entry *common;
1205 int idx = 0;
1206
1207 rcu_read_lock();
1208 hlist_for_each_entry_rcu(common, head, hash_entry) {
1209 if (idx++ < *idx_s)
1210 continue;
1211
1212 if (batadv_tt_local_dump_entry(msg, portid, seq, bat_priv,
1213 common)) {
1214 rcu_read_unlock();
1215 *idx_s = idx - 1;
1216 return -EMSGSIZE;
1217 }
1218 }
1219 rcu_read_unlock();
1220
1221 *idx_s = 0;
1222 return 0;
1223}
1224
1225/**
1226 * batadv_tt_local_dump - Dump TT local entries into a message
1227 * @msg: Netlink message to dump into
1228 * @cb: Parameters from query
1229 *
1230 * Return: Error code, or 0 on success
1231 */
1232int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
1233{
1234 struct net *net = sock_net(cb->skb->sk);
1235 struct net_device *soft_iface;
1236 struct batadv_priv *bat_priv;
1237 struct batadv_hard_iface *primary_if = NULL;
1238 struct batadv_hashtable *hash;
1239 struct hlist_head *head;
1240 int ret;
1241 int ifindex;
1242 int bucket = cb->args[0];
1243 int idx = cb->args[1];
1244 int portid = NETLINK_CB(cb->skb).portid;
1245
1246 ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
1247 if (!ifindex)
1248 return -EINVAL;
1249
1250 soft_iface = dev_get_by_index(net, ifindex);
1251 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
1252 ret = -ENODEV;
1253 goto out;
1254 }
1255
1256 bat_priv = netdev_priv(soft_iface);
1257
1258 primary_if = batadv_primary_if_get_selected(bat_priv);
1259 if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
1260 ret = -ENOENT;
1261 goto out;
1262 }
1263
1264 hash = bat_priv->tt.local_hash;
1265
1266 while (bucket < hash->size) {
1267 head = &hash->table[bucket];
1268
1269 if (batadv_tt_local_dump_bucket(msg, portid, cb->nlh->nlmsg_seq,
1270 bat_priv, head, &idx))
1271 break;
1272
1273 bucket++;
1274 }
1275
1276 ret = msg->len;
1277
1278 out:
1279 if (primary_if)
1280 batadv_hardif_put(primary_if);
1281 if (soft_iface)
1282 dev_put(soft_iface);
1283
1284 cb->args[0] = bucket;
1285 cb->args[1] = idx;
1286
1287 return ret;
1288}
1289
Sven Eckelmann56303d32012-06-05 22:31:31 +02001290static void
1291batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
1292 struct batadv_tt_local_entry *tt_local_entry,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001293 u16 flags, const char *message)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001294{
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +02001295 batadv_tt_local_event(bat_priv, tt_local_entry, flags);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001296
Antonio Quartulli015758d2011-07-09 17:52:13 +02001297 /* The local client has to be marked as "pending to be removed" but has
1298 * to be kept in the table in order to send it in a full table
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02001299 * response issued before the net ttvn increment (consistency check)
1300 */
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001301 tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
Antonio Quartullic566dbb2012-01-06 21:31:34 +01001302
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001303 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02001304 "Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
1305 tt_local_entry->common.addr,
1306 BATADV_PRINT_VID(tt_local_entry->common.vid), message);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001307}
1308
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001309/**
1310 * batadv_tt_local_remove - logically remove an entry from the local table
1311 * @bat_priv: the bat priv with all the soft interface information
1312 * @addr: the MAC address of the client to remove
Antonio Quartullic018ad32013-06-04 12:11:39 +02001313 * @vid: VLAN identifier
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001314 * @message: message to append to the log on deletion
1315 * @roaming: true if the deletion is due to a roaming event
1316 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001317 * Return: the flags assigned to the local entry before being deleted
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001318 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001319u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
1320 unsigned short vid, const char *message,
1321 bool roaming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001322{
Sven Eckelmann33a5be32019-02-23 14:27:10 +01001323 struct batadv_tt_local_entry *tt_removed_entry;
Sven Eckelmann170173b2012-10-07 12:02:22 +02001324 struct batadv_tt_local_entry *tt_local_entry;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001325 u16 flags, curr_flags = BATADV_NO_FLAGS;
Sven Eckelmann33a5be32019-02-23 14:27:10 +01001326 struct hlist_node *tt_removed_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001327
Antonio Quartullic018ad32013-06-04 12:11:39 +02001328 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001329 if (!tt_local_entry)
1330 goto out;
1331
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001332 curr_flags = tt_local_entry->common.flags;
1333
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001334 flags = BATADV_TT_CLIENT_DEL;
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001335 /* if this global entry addition is due to a roaming, the node has to
1336 * mark the local entry as "roamed" in order to correctly reroute
1337 * packets later
1338 */
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02001339 if (roaming) {
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001340 flags |= BATADV_TT_CLIENT_ROAM;
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02001341 /* mark the local client as ROAMed */
1342 tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
1343 }
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001344
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001345 if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
1346 batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
1347 message);
1348 goto out;
1349 }
1350 /* if this client has been added right now, it is possible to
1351 * immediately purge it
1352 */
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +02001353 batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
Marek Lindneref727062015-06-17 20:01:36 +08001354
Sven Eckelmann33a5be32019-02-23 14:27:10 +01001355 tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash,
Marek Lindneref727062015-06-17 20:01:36 +08001356 batadv_compare_tt,
1357 batadv_choose_tt,
1358 &tt_local_entry->common);
Sven Eckelmann33a5be32019-02-23 14:27:10 +01001359 if (!tt_removed_node)
Marek Lindneref727062015-06-17 20:01:36 +08001360 goto out;
1361
Sven Eckelmann33a5be32019-02-23 14:27:10 +01001362 /* drop reference of remove hash entry */
1363 tt_removed_entry = hlist_entry(tt_removed_node,
1364 struct batadv_tt_local_entry,
1365 common.hash_entry);
1366 batadv_tt_local_entry_put(tt_removed_entry);
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001367
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001368out:
1369 if (tt_local_entry)
Sven Eckelmann95c0db92016-01-17 11:01:25 +01001370 batadv_tt_local_entry_put(tt_local_entry);
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001371
1372 return curr_flags;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001373}
1374
Marek Lindnera19d3d82013-05-27 15:33:25 +08001375/**
1376 * batadv_tt_local_purge_list - purge inactive tt local entries
1377 * @bat_priv: the bat priv with all the soft interface information
1378 * @head: pointer to the list containing the local tt entries
1379 * @timeout: parameter deciding whether a given tt local entry is considered
1380 * inactive or not
1381 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001382static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
Marek Lindnera19d3d82013-05-27 15:33:25 +08001383 struct hlist_head *head,
1384 int timeout)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001385{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001386 struct batadv_tt_local_entry *tt_local_entry;
1387 struct batadv_tt_common_entry *tt_common_entry;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001388 struct hlist_node *node_tmp;
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001389
Sasha Levinb67bfe02013-02-27 17:06:00 -08001390 hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001391 hash_entry) {
1392 tt_local_entry = container_of(tt_common_entry,
Sven Eckelmann56303d32012-06-05 22:31:31 +02001393 struct batadv_tt_local_entry,
1394 common);
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001395 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
1396 continue;
1397
1398 /* entry already marked for deletion */
1399 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
1400 continue;
1401
Marek Lindnera19d3d82013-05-27 15:33:25 +08001402 if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001403 continue;
1404
1405 batadv_tt_local_set_pending(bat_priv, tt_local_entry,
1406 BATADV_TT_CLIENT_DEL, "timed out");
1407 }
1408}
1409
Marek Lindnera19d3d82013-05-27 15:33:25 +08001410/**
1411 * batadv_tt_local_purge - purge inactive tt local entries
1412 * @bat_priv: the bat priv with all the soft interface information
1413 * @timeout: parameter deciding whether a given tt local entry is considered
1414 * inactive or not
1415 */
1416static void batadv_tt_local_purge(struct batadv_priv *bat_priv,
1417 int timeout)
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001418{
Sven Eckelmann807736f2012-07-15 22:26:51 +02001419 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001420 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001421 spinlock_t *list_lock; /* protects write access to the hash lists */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001422 u32 i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001423
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001424 for (i = 0; i < hash->size; i++) {
1425 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001426 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001427
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001428 spin_lock_bh(list_lock);
Marek Lindnera19d3d82013-05-27 15:33:25 +08001429 batadv_tt_local_purge_list(bat_priv, head, timeout);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001430 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001431 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001432}
1433
Sven Eckelmann56303d32012-06-05 22:31:31 +02001434static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001435{
Sven Eckelmann5bf74e92012-06-05 22:31:28 +02001436 struct batadv_hashtable *hash;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001437 spinlock_t *list_lock; /* protects write access to the hash lists */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001438 struct batadv_tt_common_entry *tt_common_entry;
1439 struct batadv_tt_local_entry *tt_local;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001440 struct hlist_node *node_tmp;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001441 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001442 u32 i;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001443
Sven Eckelmann807736f2012-07-15 22:26:51 +02001444 if (!bat_priv->tt.local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001445 return;
1446
Sven Eckelmann807736f2012-07-15 22:26:51 +02001447 hash = bat_priv->tt.local_hash;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001448
1449 for (i = 0; i < hash->size; i++) {
1450 head = &hash->table[i];
1451 list_lock = &hash->list_locks[i];
1452
1453 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001454 hlist_for_each_entry_safe(tt_common_entry, node_tmp,
Antonio Quartullia73105b2011-04-27 14:27:44 +02001455 head, hash_entry) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08001456 hlist_del_rcu(&tt_common_entry->hash_entry);
Sven Eckelmann56303d32012-06-05 22:31:31 +02001457 tt_local = container_of(tt_common_entry,
1458 struct batadv_tt_local_entry,
1459 common);
Antonio Quartulli35df3b22014-05-08 17:13:15 +02001460
Sven Eckelmann95c0db92016-01-17 11:01:25 +01001461 batadv_tt_local_entry_put(tt_local);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001462 }
1463 spin_unlock_bh(list_lock);
1464 }
1465
Sven Eckelmann1a8eaf02012-05-12 02:09:32 +02001466 batadv_hash_destroy(hash);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001467
Sven Eckelmann807736f2012-07-15 22:26:51 +02001468 bat_priv->tt.local_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001469}
1470
Sven Eckelmann56303d32012-06-05 22:31:31 +02001471static int batadv_tt_global_init(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001472{
Sven Eckelmann807736f2012-07-15 22:26:51 +02001473 if (bat_priv->tt.global_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +02001474 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001475
Sven Eckelmann807736f2012-07-15 22:26:51 +02001476 bat_priv->tt.global_hash = batadv_hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001477
Sven Eckelmann807736f2012-07-15 22:26:51 +02001478 if (!bat_priv->tt.global_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +02001479 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001480
Antonio Quartullidec05072012-11-10 11:00:32 +01001481 batadv_hash_set_lock_class(bat_priv->tt.global_hash,
1482 &batadv_tt_global_hash_lock_class_key);
1483
Sven Eckelmann5346c352012-05-05 13:27:28 +02001484 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001485}
1486
Sven Eckelmann56303d32012-06-05 22:31:31 +02001487static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001488{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001489 struct batadv_tt_change_node *entry, *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001490
Sven Eckelmann807736f2012-07-15 22:26:51 +02001491 spin_lock_bh(&bat_priv->tt.changes_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001492
Sven Eckelmann807736f2012-07-15 22:26:51 +02001493 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
Antonio Quartullia73105b2011-04-27 14:27:44 +02001494 list) {
1495 list_del(&entry->list);
Sven Eckelmann86452f82016-06-25 16:44:06 +02001496 kmem_cache_free(batadv_tt_change_cache, entry);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001497 }
1498
Sven Eckelmann807736f2012-07-15 22:26:51 +02001499 atomic_set(&bat_priv->tt.local_changes, 0);
1500 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001501}
1502
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001503/**
Antonio Quartullid15cd622015-11-17 16:40:52 +08001504 * batadv_tt_global_orig_entry_find - find a TT orig_list_entry
1505 * @entry: the TT global entry where the orig_list_entry has to be
1506 * extracted from
1507 * @orig_node: the originator for which the orig_list_entry has to be found
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001508 *
Antonio Quartullid15cd622015-11-17 16:40:52 +08001509 * retrieve the orig_tt_list_entry belonging to orig_node from the
Antonio Quartullid657e622012-07-01 14:09:12 +02001510 * batadv_tt_global_entry list
1511 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001512 * Return: it with an increased refcounter, NULL if not found
Antonio Quartullid657e622012-07-01 14:09:12 +02001513 */
1514static struct batadv_tt_orig_list_entry *
1515batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
1516 const struct batadv_orig_node *orig_node)
1517{
1518 struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
1519 const struct hlist_head *head;
Antonio Quartullid657e622012-07-01 14:09:12 +02001520
1521 rcu_read_lock();
1522 head = &entry->orig_list;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001523 hlist_for_each_entry_rcu(tmp_orig_entry, head, list) {
Antonio Quartullid657e622012-07-01 14:09:12 +02001524 if (tmp_orig_entry->orig_node != orig_node)
1525 continue;
Sven Eckelmann6e8ef692016-01-16 10:29:50 +01001526 if (!kref_get_unless_zero(&tmp_orig_entry->refcount))
Antonio Quartullid657e622012-07-01 14:09:12 +02001527 continue;
1528
1529 orig_entry = tmp_orig_entry;
1530 break;
1531 }
1532 rcu_read_unlock();
1533
1534 return orig_entry;
1535}
1536
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001537/**
Antonio Quartullid15cd622015-11-17 16:40:52 +08001538 * batadv_tt_global_entry_has_orig - check if a TT global entry is also handled
1539 * by a given originator
1540 * @entry: the TT global entry to check
1541 * @orig_node: the originator to search in the list
Linus Lüssing24443bf2020-03-16 23:30:55 +01001542 * @flags: a pointer to store TT flags for the given @entry received
1543 * from @orig_node
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001544 *
1545 * find out if an orig_node is already in the list of a tt_global_entry.
1546 *
1547 * Return: true if found, false otherwise
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001548 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001549static bool
1550batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
Linus Lüssing24443bf2020-03-16 23:30:55 +01001551 const struct batadv_orig_node *orig_node,
1552 u8 *flags)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001553{
Antonio Quartullid657e622012-07-01 14:09:12 +02001554 struct batadv_tt_orig_list_entry *orig_entry;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001555 bool found = false;
1556
Antonio Quartullid657e622012-07-01 14:09:12 +02001557 orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
1558 if (orig_entry) {
1559 found = true;
Linus Lüssing24443bf2020-03-16 23:30:55 +01001560
1561 if (flags)
1562 *flags = orig_entry->flags;
1563
Sven Eckelmann7e2366c2016-01-17 11:01:27 +01001564 batadv_tt_orig_list_entry_put(orig_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001565 }
Antonio Quartullid657e622012-07-01 14:09:12 +02001566
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001567 return found;
1568}
1569
Linus Lüssing805596e2020-03-16 23:30:48 +01001570/**
1571 * batadv_tt_global_sync_flags - update TT sync flags
1572 * @tt_global: the TT global entry to update sync flags in
1573 *
1574 * Updates the sync flag bits in the tt_global flag attribute with a logical
1575 * OR of all sync flags from any of its TT orig entries.
1576 */
1577static void
1578batadv_tt_global_sync_flags(struct batadv_tt_global_entry *tt_global)
1579{
1580 struct batadv_tt_orig_list_entry *orig_entry;
1581 const struct hlist_head *head;
1582 u16 flags = BATADV_NO_FLAGS;
1583
1584 rcu_read_lock();
1585 head = &tt_global->orig_list;
1586 hlist_for_each_entry_rcu(orig_entry, head, list)
1587 flags |= orig_entry->flags;
1588 rcu_read_unlock();
1589
1590 flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
1591 tt_global->common.flags = flags;
1592}
1593
1594/**
1595 * batadv_tt_global_orig_entry_add - add or update a TT orig entry
1596 * @tt_global: the TT global entry to add an orig entry in
1597 * @orig_node: the originator to add an orig entry for
1598 * @ttvn: translation table version number of this changeset
1599 * @flags: TT sync flags
1600 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001601static void
Antonio Quartullid657e622012-07-01 14:09:12 +02001602batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
Linus Lüssing805596e2020-03-16 23:30:48 +01001603 struct batadv_orig_node *orig_node, int ttvn,
1604 u8 flags)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001605{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001606 struct batadv_tt_orig_list_entry *orig_entry;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001607
Sven Eckelmann8b7a4df2018-08-12 21:04:44 +02001608 spin_lock_bh(&tt_global->list_lock);
1609
Antonio Quartullid657e622012-07-01 14:09:12 +02001610 orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001611 if (orig_entry) {
1612 /* refresh the ttvn: the current value could be a bogus one that
1613 * was added during a "temporary client detection"
1614 */
1615 orig_entry->ttvn = ttvn;
Linus Lüssing805596e2020-03-16 23:30:48 +01001616 orig_entry->flags = flags;
1617 goto sync_flags;
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001618 }
Antonio Quartullid657e622012-07-01 14:09:12 +02001619
Sven Eckelmann86452f82016-06-25 16:44:06 +02001620 orig_entry = kmem_cache_zalloc(batadv_tt_orig_cache, GFP_ATOMIC);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001621 if (!orig_entry)
Antonio Quartullid657e622012-07-01 14:09:12 +02001622 goto out;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001623
1624 INIT_HLIST_NODE(&orig_entry->list);
Sven Eckelmann7c124392016-01-16 10:29:56 +01001625 kref_get(&orig_node->refcount);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001626 batadv_tt_global_size_inc(orig_node, tt_global->common.vid);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001627 orig_entry->orig_node = orig_node;
1628 orig_entry->ttvn = ttvn;
Linus Lüssing805596e2020-03-16 23:30:48 +01001629 orig_entry->flags = flags;
Sven Eckelmann6e8ef692016-01-16 10:29:50 +01001630 kref_init(&orig_entry->refcount);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001631
Sven Eckelmann23f554852016-07-15 17:39:18 +02001632 kref_get(&orig_entry->refcount);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001633 hlist_add_head_rcu(&orig_entry->list,
Antonio Quartullid657e622012-07-01 14:09:12 +02001634 &tt_global->orig_list);
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001635 atomic_inc(&tt_global->orig_list_count);
1636
Linus Lüssing805596e2020-03-16 23:30:48 +01001637sync_flags:
1638 batadv_tt_global_sync_flags(tt_global);
Antonio Quartullid657e622012-07-01 14:09:12 +02001639out:
1640 if (orig_entry)
Sven Eckelmann7e2366c2016-01-17 11:01:27 +01001641 batadv_tt_orig_list_entry_put(orig_entry);
Sven Eckelmann8b7a4df2018-08-12 21:04:44 +02001642
1643 spin_unlock_bh(&tt_global->list_lock);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001644}
1645
Antonio Quartullid4ff40f2013-04-18 15:13:01 +02001646/**
1647 * batadv_tt_global_add - add a new TT global entry or update an existing one
1648 * @bat_priv: the bat priv with all the soft interface information
1649 * @orig_node: the originator announcing the client
1650 * @tt_addr: the mac address of the non-mesh client
Antonio Quartullic018ad32013-06-04 12:11:39 +02001651 * @vid: VLAN identifier
Antonio Quartullid4ff40f2013-04-18 15:13:01 +02001652 * @flags: TT flags that have to be set for this non-mesh client
1653 * @ttvn: the tt version number ever announcing this non-mesh client
1654 *
1655 * Add a new TT global entry for the given originator. If the entry already
1656 * exists add a new reference to the given originator (a global entry can have
1657 * references to multiple originators) and adjust the flags attribute to reflect
1658 * the function argument.
1659 * If a TT local entry exists for this non-mesh client remove it.
1660 *
1661 * The caller must hold orig_node refcount.
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001662 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001663 * Return: true if the new entry has been added, false otherwise
Antonio Quartullid4ff40f2013-04-18 15:13:01 +02001664 */
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001665static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
1666 struct batadv_orig_node *orig_node,
Antonio Quartullic018ad32013-06-04 12:11:39 +02001667 const unsigned char *tt_addr,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001668 unsigned short vid, u16 flags, u8 ttvn)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001669{
Sven Eckelmann170173b2012-10-07 12:02:22 +02001670 struct batadv_tt_global_entry *tt_global_entry;
1671 struct batadv_tt_local_entry *tt_local_entry;
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001672 bool ret = false;
Simon Wunderlich80b3f582011-11-02 20:26:45 +01001673 int hash_added;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001674 struct batadv_tt_common_entry *common;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001675 u16 local_flags;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001676
Antonio Quartullicfd4f752013-08-07 18:28:56 +02001677 /* ignore global entries from backbone nodes */
1678 if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
1679 return true;
1680
Antonio Quartullic018ad32013-06-04 12:11:39 +02001681 tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid);
1682 tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001683
1684 /* if the node already has a local client for this entry, it has to wait
1685 * for a roaming advertisement instead of manually messing up the global
1686 * table
1687 */
1688 if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
1689 !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
1690 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001691
Antonio Quartullia73105b2011-04-27 14:27:44 +02001692 if (!tt_global_entry) {
Sven Eckelmann86452f82016-06-25 16:44:06 +02001693 tt_global_entry = kmem_cache_zalloc(batadv_tg_cache,
1694 GFP_ATOMIC);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001695 if (!tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001696 goto out;
1697
Sven Eckelmannc0a55922012-05-12 13:48:55 +02001698 common = &tt_global_entry->common;
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01001699 ether_addr_copy(common->addr, tt_addr);
Antonio Quartullic018ad32013-06-04 12:11:39 +02001700 common->vid = vid;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001701
Antonio Quartullid4f44692012-05-25 00:00:54 +02001702 common->flags = flags;
Antonio Quartullicc47f662011-04-27 14:27:57 +02001703 tt_global_entry->roam_at = 0;
Antonio Quartullifdf79322012-08-24 17:54:07 +02001704 /* node must store current time in case of roaming. This is
1705 * needed to purge this entry out on timeout (if nobody claims
1706 * it)
1707 */
1708 if (flags & BATADV_TT_CLIENT_ROAM)
1709 tt_global_entry->roam_at = jiffies;
Sven Eckelmann92dcdf02016-01-16 10:29:57 +01001710 kref_init(&common->refcount);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001711 common->added_at = jiffies;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001712
1713 INIT_HLIST_HEAD(&tt_global_entry->orig_list);
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001714 atomic_set(&tt_global_entry->orig_list_count, 0);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001715 spin_lock_init(&tt_global_entry->list_lock);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001716
Sven Eckelmann15d5ffd2016-07-15 17:39:23 +02001717 kref_get(&common->refcount);
Sven Eckelmann807736f2012-07-15 22:26:51 +02001718 hash_added = batadv_hash_add(bat_priv->tt.global_hash,
Sven Eckelmanna5130882012-05-16 20:23:16 +02001719 batadv_compare_tt,
Antonio Quartullic018ad32013-06-04 12:11:39 +02001720 batadv_choose_tt, common,
Sven Eckelmanna5130882012-05-16 20:23:16 +02001721 &common->hash_entry);
Simon Wunderlich80b3f582011-11-02 20:26:45 +01001722
1723 if (unlikely(hash_added != 0)) {
1724 /* remove the reference for the hash */
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01001725 batadv_tt_global_entry_put(tt_global_entry);
Simon Wunderlich80b3f582011-11-02 20:26:45 +01001726 goto out_remove;
1727 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02001728 } else {
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001729 common = &tt_global_entry->common;
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001730 /* If there is already a global entry, we can use this one for
1731 * our processing.
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001732 * But if we are trying to add a temporary client then here are
1733 * two options at this point:
1734 * 1) the global client is not a temporary client: the global
1735 * client has to be left as it is, temporary information
1736 * should never override any already known client state
1737 * 2) the global client is a temporary client: purge the
1738 * originator list and add the new one orig_entry
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001739 */
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001740 if (flags & BATADV_TT_CLIENT_TEMP) {
1741 if (!(common->flags & BATADV_TT_CLIENT_TEMP))
1742 goto out;
1743 if (batadv_tt_global_entry_has_orig(tt_global_entry,
Linus Lüssing24443bf2020-03-16 23:30:55 +01001744 orig_node, NULL))
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001745 goto out_remove;
1746 batadv_tt_global_del_orig_list(tt_global_entry);
1747 goto add_orig_entry;
1748 }
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001749
1750 /* if the client was temporary added before receiving the first
Simon Wunderlicha6cb3902015-09-02 20:09:55 +02001751 * OGM announcing it, we have to clear the TEMP flag. Also,
1752 * remove the previous temporary orig node and re-add it
1753 * if required. If the orig entry changed, the new one which
1754 * is a non-temporary entry is preferred.
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001755 */
Simon Wunderlicha6cb3902015-09-02 20:09:55 +02001756 if (common->flags & BATADV_TT_CLIENT_TEMP) {
1757 batadv_tt_global_del_orig_list(tt_global_entry);
1758 common->flags &= ~BATADV_TT_CLIENT_TEMP;
1759 }
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001760
Antonio Quartullie9c001362012-11-07 15:05:33 +01001761 /* the change can carry possible "attribute" flags like the
Linus Lüssing805596e2020-03-16 23:30:48 +01001762 * TT_CLIENT_TEMP, therefore they have to be copied in the
Antonio Quartullie9c001362012-11-07 15:05:33 +01001763 * client entry
1764 */
Linus Lüssing805596e2020-03-16 23:30:48 +01001765 common->flags |= flags & (~BATADV_TT_SYNC_MASK);
Antonio Quartullie9c001362012-11-07 15:05:33 +01001766
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001767 /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
1768 * one originator left in the list and we previously received a
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001769 * delete + roaming change for this originator.
1770 *
1771 * We should first delete the old originator before adding the
1772 * new one.
1773 */
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001774 if (common->flags & BATADV_TT_CLIENT_ROAM) {
Sven Eckelmanna5130882012-05-16 20:23:16 +02001775 batadv_tt_global_del_orig_list(tt_global_entry);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001776 common->flags &= ~BATADV_TT_CLIENT_ROAM;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001777 tt_global_entry->roam_at = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001778 }
1779 }
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001780add_orig_entry:
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001781 /* add the new orig_entry (if needed) or update it */
Linus Lüssing805596e2020-03-16 23:30:48 +01001782 batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn,
1783 flags & BATADV_TT_SYNC_MASK);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001784
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001785 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02001786 "Creating new global tt entry: %pM (vid: %d, via %pM)\n",
1787 common->addr, BATADV_PRINT_VID(common->vid),
1788 orig_node->orig);
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001789 ret = true;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001790
Simon Wunderlich80b3f582011-11-02 20:26:45 +01001791out_remove:
Linus Lüssingc5caf4e2014-02-15 17:47:49 +01001792 /* Do not remove multicast addresses from the local hash on
1793 * global additions
1794 */
1795 if (is_multicast_ether_addr(tt_addr))
1796 goto out;
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001797
Antonio Quartullia73105b2011-04-27 14:27:44 +02001798 /* remove address from local hash if present */
Antonio Quartullic018ad32013-06-04 12:11:39 +02001799 local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001800 "global tt received",
Antonio Quartullic1d07432013-01-15 22:17:19 +10001801 flags & BATADV_TT_CLIENT_ROAM);
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001802 tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
1803
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001804 if (!(flags & BATADV_TT_CLIENT_ROAM))
1805 /* this is a normal global add. Therefore the client is not in a
1806 * roaming state anymore.
1807 */
1808 tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
1809
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001810out:
1811 if (tt_global_entry)
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01001812 batadv_tt_global_entry_put(tt_global_entry);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001813 if (tt_local_entry)
Sven Eckelmann95c0db92016-01-17 11:01:25 +01001814 batadv_tt_local_entry_put(tt_local_entry);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001815 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001816}
1817
Simon Wunderlich1b371d12014-01-15 21:17:54 +01001818/**
1819 * batadv_transtable_best_orig - Get best originator list entry from tt entry
Antonio Quartulli46274562013-09-03 11:10:24 +02001820 * @bat_priv: the bat priv with all the soft interface information
Sven Eckelmann981d8902012-10-07 13:34:15 +02001821 * @tt_global_entry: global translation table entry to be analyzed
1822 *
1823 * This functon assumes the caller holds rcu_read_lock().
Sven Eckelmann62fe7102015-09-15 19:00:48 +02001824 * Return: best originator list entry or NULL on errors.
Sven Eckelmann981d8902012-10-07 13:34:15 +02001825 */
1826static struct batadv_tt_orig_list_entry *
Antonio Quartulli46274562013-09-03 11:10:24 +02001827batadv_transtable_best_orig(struct batadv_priv *bat_priv,
1828 struct batadv_tt_global_entry *tt_global_entry)
Sven Eckelmann981d8902012-10-07 13:34:15 +02001829{
Antonio Quartulli46274562013-09-03 11:10:24 +02001830 struct batadv_neigh_node *router, *best_router = NULL;
Antonio Quartulli29824a52016-05-25 23:27:31 +08001831 struct batadv_algo_ops *bao = bat_priv->algo_ops;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001832 struct hlist_head *head;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001833 struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001834
1835 head = &tt_global_entry->orig_list;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001836 hlist_for_each_entry_rcu(orig_entry, head, list) {
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001837 router = batadv_orig_router_get(orig_entry->orig_node,
1838 BATADV_IF_DEFAULT);
Sven Eckelmann981d8902012-10-07 13:34:15 +02001839 if (!router)
1840 continue;
1841
Antonio Quartulli46274562013-09-03 11:10:24 +02001842 if (best_router &&
Antonio Quartulli29824a52016-05-25 23:27:31 +08001843 bao->neigh.cmp(router, BATADV_IF_DEFAULT, best_router,
1844 BATADV_IF_DEFAULT) <= 0) {
Sven Eckelmann25bb2502016-01-17 11:01:11 +01001845 batadv_neigh_node_put(router);
Antonio Quartulli46274562013-09-03 11:10:24 +02001846 continue;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001847 }
1848
Antonio Quartulli46274562013-09-03 11:10:24 +02001849 /* release the refcount for the "old" best */
1850 if (best_router)
Sven Eckelmann25bb2502016-01-17 11:01:11 +01001851 batadv_neigh_node_put(best_router);
Antonio Quartulli46274562013-09-03 11:10:24 +02001852
1853 best_entry = orig_entry;
1854 best_router = router;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001855 }
1856
Antonio Quartulli46274562013-09-03 11:10:24 +02001857 if (best_router)
Sven Eckelmann25bb2502016-01-17 11:01:11 +01001858 batadv_neigh_node_put(best_router);
Antonio Quartulli46274562013-09-03 11:10:24 +02001859
Sven Eckelmann981d8902012-10-07 13:34:15 +02001860 return best_entry;
1861}
1862
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +02001863#ifdef CONFIG_BATMAN_ADV_DEBUGFS
Simon Wunderlich1b371d12014-01-15 21:17:54 +01001864/**
1865 * batadv_tt_global_print_entry - print all orig nodes who announce the address
1866 * for this global entry
Antonio Quartulli46274562013-09-03 11:10:24 +02001867 * @bat_priv: the bat priv with all the soft interface information
Sven Eckelmann981d8902012-10-07 13:34:15 +02001868 * @tt_global_entry: global translation table entry to be printed
1869 * @seq: debugfs table seq_file struct
1870 *
1871 * This functon assumes the caller holds rcu_read_lock().
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001872 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001873static void
Antonio Quartulli46274562013-09-03 11:10:24 +02001874batadv_tt_global_print_entry(struct batadv_priv *bat_priv,
1875 struct batadv_tt_global_entry *tt_global_entry,
Sven Eckelmanna5130882012-05-16 20:23:16 +02001876 struct seq_file *seq)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001877{
Sven Eckelmann981d8902012-10-07 13:34:15 +02001878 struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001879 struct batadv_tt_common_entry *tt_common_entry;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001880 struct batadv_orig_node_vlan *vlan;
1881 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001882 u8 last_ttvn;
1883 u16 flags;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001884
1885 tt_common_entry = &tt_global_entry->common;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001886 flags = tt_common_entry->flags;
1887
Antonio Quartulli46274562013-09-03 11:10:24 +02001888 best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
Sven Eckelmann981d8902012-10-07 13:34:15 +02001889 if (best_entry) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001890 vlan = batadv_orig_node_vlan_get(best_entry->orig_node,
1891 tt_common_entry->vid);
1892 if (!vlan) {
1893 seq_printf(seq,
1894 " * Cannot retrieve VLAN %d for originator %pM\n",
1895 BATADV_PRINT_VID(tt_common_entry->vid),
1896 best_entry->orig_node->orig);
1897 goto print_list;
1898 }
1899
Sven Eckelmann981d8902012-10-07 13:34:15 +02001900 last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
Antonio Quartullif9d8a532012-11-19 09:01:42 +01001901 seq_printf(seq,
Antonio Quartullidd24ddb2013-11-16 12:03:49 +01001902 " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n",
Sven Eckelmann981d8902012-10-07 13:34:15 +02001903 '*', tt_global_entry->common.addr,
Antonio Quartulli16052782013-06-04 12:11:41 +02001904 BATADV_PRINT_VID(tt_global_entry->common.vid),
Sven Eckelmann981d8902012-10-07 13:34:15 +02001905 best_entry->ttvn, best_entry->orig_node->orig,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001906 last_ttvn, vlan->tt.crc,
Sven Eckelmanna2f2b6c2015-04-23 18:22:24 +02001907 ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
1908 ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
1909 ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
1910 ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001911
Sven Eckelmann21754e22016-01-17 11:01:24 +01001912 batadv_orig_node_vlan_put(vlan);
Sven Eckelmann981d8902012-10-07 13:34:15 +02001913 }
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001914
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001915print_list:
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001916 head = &tt_global_entry->orig_list;
1917
Sasha Levinb67bfe02013-02-27 17:06:00 -08001918 hlist_for_each_entry_rcu(orig_entry, head, list) {
Sven Eckelmann981d8902012-10-07 13:34:15 +02001919 if (best_entry == orig_entry)
1920 continue;
1921
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001922 vlan = batadv_orig_node_vlan_get(orig_entry->orig_node,
1923 tt_common_entry->vid);
1924 if (!vlan) {
1925 seq_printf(seq,
1926 " + Cannot retrieve VLAN %d for originator %pM\n",
1927 BATADV_PRINT_VID(tt_common_entry->vid),
1928 orig_entry->orig_node->orig);
1929 continue;
1930 }
1931
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001932 last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
Antonio Quartulli16052782013-06-04 12:11:41 +02001933 seq_printf(seq,
Antonio Quartullidd24ddb2013-11-16 12:03:49 +01001934 " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n",
Sven Eckelmann981d8902012-10-07 13:34:15 +02001935 '+', tt_global_entry->common.addr,
Antonio Quartulli16052782013-06-04 12:11:41 +02001936 BATADV_PRINT_VID(tt_global_entry->common.vid),
Sven Eckelmann981d8902012-10-07 13:34:15 +02001937 orig_entry->ttvn, orig_entry->orig_node->orig,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001938 last_ttvn, vlan->tt.crc,
Sven Eckelmanna2f2b6c2015-04-23 18:22:24 +02001939 ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
1940 ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
1941 ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
1942 ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001943
Sven Eckelmann21754e22016-01-17 11:01:24 +01001944 batadv_orig_node_vlan_put(vlan);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001945 }
1946}
1947
Sven Eckelmann08c36d32012-05-12 02:09:39 +02001948int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001949{
1950 struct net_device *net_dev = (struct net_device *)seq->private;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001951 struct batadv_priv *bat_priv = netdev_priv(net_dev);
Sven Eckelmann807736f2012-07-15 22:26:51 +02001952 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001953 struct batadv_tt_common_entry *tt_common_entry;
1954 struct batadv_tt_global_entry *tt_global;
1955 struct batadv_hard_iface *primary_if;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001956 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02001957 u32 i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001958
Marek Lindner30da63a2012-08-03 17:15:46 +02001959 primary_if = batadv_seq_print_text_primary_if_get(seq);
1960 if (!primary_if)
Marek Lindner32ae9b22011-04-20 15:40:58 +02001961 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001962
Antonio Quartulli2dafb492011-05-05 08:42:45 +02001963 seq_printf(seq,
1964 "Globally announced TT entries received via the mesh %s\n",
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001965 net_dev->name);
Antonio Quartulli925a6f32016-03-12 10:30:18 +01001966 seq_puts(seq,
1967 " Client VID (TTVN) Originator (Curr TTVN) (CRC ) Flags\n");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001968
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001969 for (i = 0; i < hash->size; i++) {
1970 head = &hash->table[i];
1971
Marek Lindner7aadf882011-02-18 12:28:09 +00001972 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08001973 hlist_for_each_entry_rcu(tt_common_entry,
Marek Lindner7aadf882011-02-18 12:28:09 +00001974 head, hash_entry) {
Sven Eckelmann56303d32012-06-05 22:31:31 +02001975 tt_global = container_of(tt_common_entry,
1976 struct batadv_tt_global_entry,
1977 common);
Antonio Quartulli46274562013-09-03 11:10:24 +02001978 batadv_tt_global_print_entry(bat_priv, tt_global, seq);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001979 }
Marek Lindner7aadf882011-02-18 12:28:09 +00001980 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001981 }
Marek Lindner32ae9b22011-04-20 15:40:58 +02001982out:
1983 if (primary_if)
Sven Eckelmann82047ad2016-01-17 11:01:10 +01001984 batadv_hardif_put(primary_if);
Marek Lindner30da63a2012-08-03 17:15:46 +02001985 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001986}
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +02001987#endif
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001988
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001989/**
Matthias Schifferd34f0552016-07-03 13:31:37 +02001990 * batadv_tt_global_dump_subentry - Dump all TT local entries into a message
1991 * @msg: Netlink message to dump into
1992 * @portid: Port making netlink request
1993 * @seq: Sequence number of netlink message
1994 * @common: tt local & tt global common data
1995 * @orig: Originator node announcing a non-mesh client
1996 * @best: Is the best originator for the TT entry
1997 *
1998 * Return: Error code, or 0 on success
1999 */
2000static int
2001batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
2002 struct batadv_tt_common_entry *common,
2003 struct batadv_tt_orig_list_entry *orig,
2004 bool best)
2005{
Linus Lüssing805596e2020-03-16 23:30:48 +01002006 u16 flags = (common->flags & (~BATADV_TT_SYNC_MASK)) | orig->flags;
Matthias Schifferd34f0552016-07-03 13:31:37 +02002007 void *hdr;
2008 struct batadv_orig_node_vlan *vlan;
2009 u8 last_ttvn;
2010 u32 crc;
2011
2012 vlan = batadv_orig_node_vlan_get(orig->orig_node,
2013 common->vid);
2014 if (!vlan)
2015 return 0;
2016
2017 crc = vlan->tt.crc;
2018
2019 batadv_orig_node_vlan_put(vlan);
2020
2021 hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
2022 NLM_F_MULTI,
2023 BATADV_CMD_GET_TRANSTABLE_GLOBAL);
2024 if (!hdr)
2025 return -ENOBUFS;
2026
2027 last_ttvn = atomic_read(&orig->orig_node->last_ttvn);
2028
2029 if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
2030 nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
2031 orig->orig_node->orig) ||
2032 nla_put_u8(msg, BATADV_ATTR_TT_TTVN, orig->ttvn) ||
2033 nla_put_u8(msg, BATADV_ATTR_TT_LAST_TTVN, last_ttvn) ||
2034 nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
2035 nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
Linus Lüssing805596e2020-03-16 23:30:48 +01002036 nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, flags))
Matthias Schifferd34f0552016-07-03 13:31:37 +02002037 goto nla_put_failure;
2038
2039 if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
2040 goto nla_put_failure;
2041
2042 genlmsg_end(msg, hdr);
2043 return 0;
2044
2045 nla_put_failure:
2046 genlmsg_cancel(msg, hdr);
2047 return -EMSGSIZE;
2048}
2049
2050/**
2051 * batadv_tt_global_dump_entry - Dump one TT global entry into a message
2052 * @msg: Netlink message to dump into
2053 * @portid: Port making netlink request
2054 * @seq: Sequence number of netlink message
2055 * @bat_priv: The bat priv with all the soft interface information
2056 * @common: tt local & tt global common data
2057 * @sub_s: Number of entries to skip
2058 *
2059 * This function assumes the caller holds rcu_read_lock().
2060 *
2061 * Return: Error code, or 0 on success
2062 */
2063static int
2064batadv_tt_global_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
2065 struct batadv_priv *bat_priv,
2066 struct batadv_tt_common_entry *common, int *sub_s)
2067{
2068 struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
2069 struct batadv_tt_global_entry *global;
2070 struct hlist_head *head;
2071 int sub = 0;
2072 bool best;
2073
2074 global = container_of(common, struct batadv_tt_global_entry, common);
2075 best_entry = batadv_transtable_best_orig(bat_priv, global);
2076 head = &global->orig_list;
2077
2078 hlist_for_each_entry_rcu(orig_entry, head, list) {
2079 if (sub++ < *sub_s)
2080 continue;
2081
2082 best = (orig_entry == best_entry);
2083
2084 if (batadv_tt_global_dump_subentry(msg, portid, seq, common,
2085 orig_entry, best)) {
2086 *sub_s = sub - 1;
2087 return -EMSGSIZE;
2088 }
2089 }
2090
2091 *sub_s = 0;
2092 return 0;
2093}
2094
2095/**
2096 * batadv_tt_global_dump_bucket - Dump one TT local bucket into a message
2097 * @msg: Netlink message to dump into
2098 * @portid: Port making netlink request
2099 * @seq: Sequence number of netlink message
2100 * @bat_priv: The bat priv with all the soft interface information
2101 * @head: Pointer to the list containing the global tt entries
2102 * @idx_s: Number of entries to skip
2103 * @sub: Number of entries to skip
2104 *
2105 * Return: Error code, or 0 on success
2106 */
2107static int
2108batadv_tt_global_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
2109 struct batadv_priv *bat_priv,
2110 struct hlist_head *head, int *idx_s, int *sub)
2111{
2112 struct batadv_tt_common_entry *common;
2113 int idx = 0;
2114
2115 rcu_read_lock();
2116 hlist_for_each_entry_rcu(common, head, hash_entry) {
2117 if (idx++ < *idx_s)
2118 continue;
2119
2120 if (batadv_tt_global_dump_entry(msg, portid, seq, bat_priv,
2121 common, sub)) {
2122 rcu_read_unlock();
2123 *idx_s = idx - 1;
2124 return -EMSGSIZE;
2125 }
2126 }
2127 rcu_read_unlock();
2128
2129 *idx_s = 0;
2130 *sub = 0;
2131 return 0;
2132}
2133
2134/**
2135 * batadv_tt_global_dump - Dump TT global entries into a message
2136 * @msg: Netlink message to dump into
2137 * @cb: Parameters from query
2138 *
2139 * Return: Error code, or length of message on success
2140 */
2141int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb)
2142{
2143 struct net *net = sock_net(cb->skb->sk);
2144 struct net_device *soft_iface;
2145 struct batadv_priv *bat_priv;
2146 struct batadv_hard_iface *primary_if = NULL;
2147 struct batadv_hashtable *hash;
2148 struct hlist_head *head;
2149 int ret;
2150 int ifindex;
2151 int bucket = cb->args[0];
2152 int idx = cb->args[1];
2153 int sub = cb->args[2];
2154 int portid = NETLINK_CB(cb->skb).portid;
2155
2156 ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
2157 if (!ifindex)
2158 return -EINVAL;
2159
2160 soft_iface = dev_get_by_index(net, ifindex);
2161 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
2162 ret = -ENODEV;
2163 goto out;
2164 }
2165
2166 bat_priv = netdev_priv(soft_iface);
2167
2168 primary_if = batadv_primary_if_get_selected(bat_priv);
2169 if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
2170 ret = -ENOENT;
2171 goto out;
2172 }
2173
2174 hash = bat_priv->tt.global_hash;
2175
2176 while (bucket < hash->size) {
2177 head = &hash->table[bucket];
2178
2179 if (batadv_tt_global_dump_bucket(msg, portid,
2180 cb->nlh->nlmsg_seq, bat_priv,
2181 head, &idx, &sub))
2182 break;
2183
2184 bucket++;
2185 }
2186
2187 ret = msg->len;
2188
2189 out:
2190 if (primary_if)
2191 batadv_hardif_put(primary_if);
2192 if (soft_iface)
2193 dev_put(soft_iface);
2194
2195 cb->args[0] = bucket;
2196 cb->args[1] = idx;
2197 cb->args[2] = sub;
2198
2199 return ret;
2200}
2201
2202/**
Marek Lindner433ff982015-06-18 16:11:07 +08002203 * _batadv_tt_global_del_orig_entry - remove and free an orig_entry
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002204 * @tt_global_entry: the global entry to remove the orig_entry from
2205 * @orig_entry: the orig entry to remove and free
2206 *
2207 * Remove an orig_entry from its list in the given tt_global_entry and
2208 * free this orig_entry afterwards.
Marek Lindner433ff982015-06-18 16:11:07 +08002209 *
2210 * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is
2211 * part of a list.
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002212 */
2213static void
Marek Lindner433ff982015-06-18 16:11:07 +08002214_batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
2215 struct batadv_tt_orig_list_entry *orig_entry)
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002216{
Sven Eckelmann2c72d652015-06-21 14:45:14 +02002217 lockdep_assert_held(&tt_global_entry->list_lock);
2218
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002219 batadv_tt_global_size_dec(orig_entry->orig_node,
2220 tt_global_entry->common.vid);
2221 atomic_dec(&tt_global_entry->orig_list_count);
Marek Lindner433ff982015-06-18 16:11:07 +08002222 /* requires holding tt_global_entry->list_lock and orig_entry->list
2223 * being part of a list
2224 */
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002225 hlist_del_rcu(&orig_entry->list);
Sven Eckelmann7e2366c2016-01-17 11:01:27 +01002226 batadv_tt_orig_list_entry_put(orig_entry);
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002227}
2228
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002229/* deletes the orig list of a tt_global_entry */
Sven Eckelmanna5130882012-05-16 20:23:16 +02002230static void
Sven Eckelmann56303d32012-06-05 22:31:31 +02002231batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002232{
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002233 struct hlist_head *head;
Sasha Levinb67bfe02013-02-27 17:06:00 -08002234 struct hlist_node *safe;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002235 struct batadv_tt_orig_list_entry *orig_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002236
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002237 spin_lock_bh(&tt_global_entry->list_lock);
2238 head = &tt_global_entry->orig_list;
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002239 hlist_for_each_entry_safe(orig_entry, safe, head, list)
Marek Lindner433ff982015-06-18 16:11:07 +08002240 _batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002241 spin_unlock_bh(&tt_global_entry->list_lock);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002242}
2243
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002244/**
2245 * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry
2246 * @bat_priv: the bat priv with all the soft interface information
2247 * @tt_global_entry: the global entry to remove the orig_node from
2248 * @orig_node: the originator announcing the client
2249 * @message: message to append to the log on deletion
2250 *
2251 * Remove the given orig_node and its according orig_entry from the given
2252 * global tt entry.
2253 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02002254static void
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002255batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv,
2256 struct batadv_tt_global_entry *tt_global_entry,
2257 struct batadv_orig_node *orig_node,
2258 const char *message)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002259{
2260 struct hlist_head *head;
Sasha Levinb67bfe02013-02-27 17:06:00 -08002261 struct hlist_node *safe;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002262 struct batadv_tt_orig_list_entry *orig_entry;
Antonio Quartulli16052782013-06-04 12:11:41 +02002263 unsigned short vid;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002264
2265 spin_lock_bh(&tt_global_entry->list_lock);
2266 head = &tt_global_entry->orig_list;
Sasha Levinb67bfe02013-02-27 17:06:00 -08002267 hlist_for_each_entry_safe(orig_entry, safe, head, list) {
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002268 if (orig_entry->orig_node == orig_node) {
Antonio Quartulli16052782013-06-04 12:11:41 +02002269 vid = tt_global_entry->common.vid;
Sven Eckelmann39c75a52012-06-03 22:19:22 +02002270 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02002271 "Deleting %pM from global tt entry %pM (vid: %d): %s\n",
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02002272 orig_node->orig,
Antonio Quartulli16052782013-06-04 12:11:41 +02002273 tt_global_entry->common.addr,
2274 BATADV_PRINT_VID(vid), message);
Marek Lindner433ff982015-06-18 16:11:07 +08002275 _batadv_tt_global_del_orig_entry(tt_global_entry,
2276 orig_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002277 }
2278 }
2279 spin_unlock_bh(&tt_global_entry->list_lock);
2280}
2281
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002282/* If the client is to be deleted, we check if it is the last origantor entry
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002283 * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
2284 * timer, otherwise we simply remove the originator scheduled for deletion.
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002285 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02002286static void
Sven Eckelmann56303d32012-06-05 22:31:31 +02002287batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
2288 struct batadv_tt_global_entry *tt_global_entry,
2289 struct batadv_orig_node *orig_node,
2290 const char *message)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002291{
2292 bool last_entry = true;
2293 struct hlist_head *head;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002294 struct batadv_tt_orig_list_entry *orig_entry;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002295
2296 /* no local entry exists, case 1:
2297 * Check if this is the last one or if other entries exist.
2298 */
2299
2300 rcu_read_lock();
2301 head = &tt_global_entry->orig_list;
Sasha Levinb67bfe02013-02-27 17:06:00 -08002302 hlist_for_each_entry_rcu(orig_entry, head, list) {
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002303 if (orig_entry->orig_node != orig_node) {
2304 last_entry = false;
2305 break;
2306 }
2307 }
2308 rcu_read_unlock();
2309
2310 if (last_entry) {
2311 /* its the last one, mark for roaming. */
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002312 tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002313 tt_global_entry->roam_at = jiffies;
2314 } else
2315 /* there is another entry, we can simply delete this
2316 * one and can still use the other one.
2317 */
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002318 batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
2319 orig_node, message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002320}
2321
Antonio Quartullic018ad32013-06-04 12:11:39 +02002322/**
2323 * batadv_tt_global_del - remove a client from the global table
2324 * @bat_priv: the bat priv with all the soft interface information
2325 * @orig_node: an originator serving this client
2326 * @addr: the mac address of the client
2327 * @vid: VLAN identifier
2328 * @message: a message explaining the reason for deleting the client to print
2329 * for debugging purpose
2330 * @roaming: true if the deletion has been triggered by a roaming event
2331 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002332static void batadv_tt_global_del(struct batadv_priv *bat_priv,
2333 struct batadv_orig_node *orig_node,
Antonio Quartullic018ad32013-06-04 12:11:39 +02002334 const unsigned char *addr, unsigned short vid,
Sven Eckelmanna5130882012-05-16 20:23:16 +02002335 const char *message, bool roaming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002336{
Sven Eckelmann170173b2012-10-07 12:02:22 +02002337 struct batadv_tt_global_entry *tt_global_entry;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002338 struct batadv_tt_local_entry *local_entry = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002339
Antonio Quartullic018ad32013-06-04 12:11:39 +02002340 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002341 if (!tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002342 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002343
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002344 if (!roaming) {
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002345 batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
2346 orig_node, message);
Sven Eckelmann92f90f52011-12-22 20:31:12 +08002347
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002348 if (hlist_empty(&tt_global_entry->orig_list))
Antonio Quartullibe73b482012-09-23 22:38:36 +02002349 batadv_tt_global_free(bat_priv, tt_global_entry,
2350 message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002351
Sven Eckelmann92f90f52011-12-22 20:31:12 +08002352 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002353 }
Sven Eckelmann92f90f52011-12-22 20:31:12 +08002354
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002355 /* if we are deleting a global entry due to a roam
2356 * event, there are two possibilities:
2357 * 1) the client roamed from node A to node B => if there
2358 * is only one originator left for this client, we mark
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002359 * it with BATADV_TT_CLIENT_ROAM, we start a timer and we
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002360 * wait for node B to claim it. In case of timeout
2361 * the entry is purged.
2362 *
2363 * If there are other originators left, we directly delete
2364 * the originator.
2365 * 2) the client roamed to us => we can directly delete
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002366 * the global entry, since it is useless now.
2367 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02002368 local_entry = batadv_tt_local_hash_find(bat_priv,
Antonio Quartullic018ad32013-06-04 12:11:39 +02002369 tt_global_entry->common.addr,
2370 vid);
Sven Eckelmanna5130882012-05-16 20:23:16 +02002371 if (local_entry) {
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002372 /* local entry exists, case 2: client roamed to us. */
Sven Eckelmanna5130882012-05-16 20:23:16 +02002373 batadv_tt_global_del_orig_list(tt_global_entry);
Antonio Quartullibe73b482012-09-23 22:38:36 +02002374 batadv_tt_global_free(bat_priv, tt_global_entry, message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002375 } else
2376 /* no local entry exists, case 1: check for roaming */
Sven Eckelmanna5130882012-05-16 20:23:16 +02002377 batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
2378 orig_node, message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002379
Antonio Quartullicc47f662011-04-27 14:27:57 +02002380out:
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002381 if (tt_global_entry)
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01002382 batadv_tt_global_entry_put(tt_global_entry);
Sven Eckelmanna5130882012-05-16 20:23:16 +02002383 if (local_entry)
Sven Eckelmann95c0db92016-01-17 11:01:25 +01002384 batadv_tt_local_entry_put(local_entry);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002385}
2386
Antonio Quartulli95fb1302013-08-07 18:28:55 +02002387/**
2388 * batadv_tt_global_del_orig - remove all the TT global entries belonging to the
2389 * given originator matching the provided vid
2390 * @bat_priv: the bat priv with all the soft interface information
2391 * @orig_node: the originator owning the entries to remove
2392 * @match_vid: the VLAN identifier to match. If negative all the entries will be
2393 * removed
2394 * @message: debug message to print as "reason"
2395 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002396void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
2397 struct batadv_orig_node *orig_node,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002398 s32 match_vid,
Sven Eckelmann56303d32012-06-05 22:31:31 +02002399 const char *message)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002400{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002401 struct batadv_tt_global_entry *tt_global;
2402 struct batadv_tt_common_entry *tt_common_entry;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002403 u32 i;
Sven Eckelmann807736f2012-07-15 22:26:51 +02002404 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
Sasha Levinb67bfe02013-02-27 17:06:00 -08002405 struct hlist_node *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002406 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002407 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartulli16052782013-06-04 12:11:41 +02002408 unsigned short vid;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002409
Simon Wunderlich6e801492011-10-19 10:28:26 +02002410 if (!hash)
2411 return;
2412
Antonio Quartullia73105b2011-04-27 14:27:44 +02002413 for (i = 0; i < hash->size; i++) {
2414 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002415 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002416
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002417 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08002418 hlist_for_each_entry_safe(tt_common_entry, safe,
Sven Eckelmann7c64fd92012-02-28 10:55:36 +01002419 head, hash_entry) {
Antonio Quartulli95fb1302013-08-07 18:28:55 +02002420 /* remove only matching entries */
2421 if (match_vid >= 0 && tt_common_entry->vid != match_vid)
2422 continue;
2423
Sven Eckelmann56303d32012-06-05 22:31:31 +02002424 tt_global = container_of(tt_common_entry,
2425 struct batadv_tt_global_entry,
2426 common);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002427
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01002428 batadv_tt_global_del_orig_node(bat_priv, tt_global,
2429 orig_node, message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002430
Sven Eckelmann56303d32012-06-05 22:31:31 +02002431 if (hlist_empty(&tt_global->orig_list)) {
Antonio Quartulli16052782013-06-04 12:11:41 +02002432 vid = tt_global->common.vid;
Sven Eckelmann39c75a52012-06-03 22:19:22 +02002433 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02002434 "Deleting global tt entry %pM (vid: %d): %s\n",
2435 tt_global->common.addr,
2436 BATADV_PRINT_VID(vid), message);
Sasha Levinb67bfe02013-02-27 17:06:00 -08002437 hlist_del_rcu(&tt_common_entry->hash_entry);
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01002438 batadv_tt_global_entry_put(tt_global);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002439 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02002440 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002441 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002442 }
Linus Lüssingac4eebd2015-06-16 17:10:24 +02002443 clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002444}
2445
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002446static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
2447 char **msg)
Antonio Quartullicc47f662011-04-27 14:27:57 +02002448{
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002449 bool purge = false;
2450 unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT;
2451 unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002452
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002453 if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
2454 batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
2455 purge = true;
2456 *msg = "Roaming timeout\n";
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002457 }
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002458
2459 if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
2460 batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
2461 purge = true;
2462 *msg = "Temporary client timeout\n";
2463 }
2464
2465 return purge;
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002466}
2467
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002468static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002469{
Sven Eckelmann807736f2012-07-15 22:26:51 +02002470 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
Antonio Quartullicc47f662011-04-27 14:27:57 +02002471 struct hlist_head *head;
Sasha Levinb67bfe02013-02-27 17:06:00 -08002472 struct hlist_node *node_tmp;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002473 spinlock_t *list_lock; /* protects write access to the hash lists */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002474 u32 i;
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002475 char *msg = NULL;
2476 struct batadv_tt_common_entry *tt_common;
2477 struct batadv_tt_global_entry *tt_global;
Antonio Quartullicc47f662011-04-27 14:27:57 +02002478
Antonio Quartullicc47f662011-04-27 14:27:57 +02002479 for (i = 0; i < hash->size; i++) {
2480 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002481 list_lock = &hash->list_locks[i];
Antonio Quartullicc47f662011-04-27 14:27:57 +02002482
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002483 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08002484 hlist_for_each_entry_safe(tt_common, node_tmp, head,
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002485 hash_entry) {
2486 tt_global = container_of(tt_common,
2487 struct batadv_tt_global_entry,
2488 common);
2489
2490 if (!batadv_tt_global_to_purge(tt_global, &msg))
2491 continue;
2492
2493 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02002494 "Deleting global tt entry %pM (vid: %d): %s\n",
2495 tt_global->common.addr,
2496 BATADV_PRINT_VID(tt_global->common.vid),
2497 msg);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002498
Sasha Levinb67bfe02013-02-27 17:06:00 -08002499 hlist_del_rcu(&tt_common->hash_entry);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002500
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01002501 batadv_tt_global_entry_put(tt_global);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002502 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002503 spin_unlock_bh(list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02002504 }
Antonio Quartullicc47f662011-04-27 14:27:57 +02002505}
2506
Sven Eckelmann56303d32012-06-05 22:31:31 +02002507static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002508{
Sven Eckelmann5bf74e92012-06-05 22:31:28 +02002509 struct batadv_hashtable *hash;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002510 spinlock_t *list_lock; /* protects write access to the hash lists */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002511 struct batadv_tt_common_entry *tt_common_entry;
2512 struct batadv_tt_global_entry *tt_global;
Sasha Levinb67bfe02013-02-27 17:06:00 -08002513 struct hlist_node *node_tmp;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002514 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002515 u32 i;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002516
Sven Eckelmann807736f2012-07-15 22:26:51 +02002517 if (!bat_priv->tt.global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002518 return;
2519
Sven Eckelmann807736f2012-07-15 22:26:51 +02002520 hash = bat_priv->tt.global_hash;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002521
2522 for (i = 0; i < hash->size; i++) {
2523 head = &hash->table[i];
2524 list_lock = &hash->list_locks[i];
2525
2526 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08002527 hlist_for_each_entry_safe(tt_common_entry, node_tmp,
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002528 head, hash_entry) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08002529 hlist_del_rcu(&tt_common_entry->hash_entry);
Sven Eckelmann56303d32012-06-05 22:31:31 +02002530 tt_global = container_of(tt_common_entry,
2531 struct batadv_tt_global_entry,
2532 common);
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01002533 batadv_tt_global_entry_put(tt_global);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002534 }
2535 spin_unlock_bh(list_lock);
2536 }
2537
Sven Eckelmann1a8eaf02012-05-12 02:09:32 +02002538 batadv_hash_destroy(hash);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002539
Sven Eckelmann807736f2012-07-15 22:26:51 +02002540 bat_priv->tt.global_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002541}
2542
Sven Eckelmann56303d32012-06-05 22:31:31 +02002543static bool
2544_batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
2545 struct batadv_tt_global_entry *tt_global_entry)
Antonio Quartulli59b699c2011-07-07 15:35:36 +02002546{
2547 bool ret = false;
2548
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002549 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
2550 tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
Antonio Quartulli59b699c2011-07-07 15:35:36 +02002551 ret = true;
2552
Antonio Quartulli2d2fcc2a2013-11-16 12:03:50 +01002553 /* check if the two clients are marked as isolated */
2554 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
2555 tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
2556 ret = true;
2557
Antonio Quartulli59b699c2011-07-07 15:35:36 +02002558 return ret;
2559}
2560
Antonio Quartullic018ad32013-06-04 12:11:39 +02002561/**
2562 * batadv_transtable_search - get the mesh destination for a given client
2563 * @bat_priv: the bat priv with all the soft interface information
2564 * @src: mac address of the source client
2565 * @addr: mac address of the destination client
2566 * @vid: VLAN identifier
2567 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02002568 * Return: a pointer to the originator that was selected as destination in the
Antonio Quartullic018ad32013-06-04 12:11:39 +02002569 * mesh for contacting the client 'addr', NULL otherwise.
2570 * In case of multiple originators serving the same client, the function returns
2571 * the best one (best in terms of metric towards the destination node).
2572 *
2573 * If the two clients are AP isolated the function returns NULL.
2574 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002575struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002576 const u8 *src,
2577 const u8 *addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +02002578 unsigned short vid)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002579{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002580 struct batadv_tt_local_entry *tt_local_entry = NULL;
2581 struct batadv_tt_global_entry *tt_global_entry = NULL;
2582 struct batadv_orig_node *orig_node = NULL;
Sven Eckelmann981d8902012-10-07 13:34:15 +02002583 struct batadv_tt_orig_list_entry *best_entry;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002584
Antonio Quartullieceb22a2013-11-16 12:03:51 +01002585 if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
Antonio Quartullic018ad32013-06-04 12:11:39 +02002586 tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02002587 if (!tt_local_entry ||
2588 (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002589 goto out;
2590 }
Marek Lindner7aadf882011-02-18 12:28:09 +00002591
Antonio Quartullic018ad32013-06-04 12:11:39 +02002592 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
Antonio Quartulli2dafb492011-05-05 08:42:45 +02002593 if (!tt_global_entry)
Marek Lindner7b36e8e2011-02-18 12:28:10 +00002594 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002595
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002596 /* check whether the clients should not communicate due to AP
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002597 * isolation
2598 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02002599 if (tt_local_entry &&
2600 _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002601 goto out;
2602
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002603 rcu_read_lock();
Antonio Quartulli46274562013-09-03 11:10:24 +02002604 best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002605 /* found anything? */
Sven Eckelmann981d8902012-10-07 13:34:15 +02002606 if (best_entry)
2607 orig_node = best_entry->orig_node;
Sven Eckelmann7c124392016-01-16 10:29:56 +01002608 if (orig_node && !kref_get_unless_zero(&orig_node->refcount))
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002609 orig_node = NULL;
2610 rcu_read_unlock();
Sven Eckelmann981d8902012-10-07 13:34:15 +02002611
Marek Lindner7b36e8e2011-02-18 12:28:10 +00002612out:
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002613 if (tt_global_entry)
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01002614 batadv_tt_global_entry_put(tt_global_entry);
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002615 if (tt_local_entry)
Sven Eckelmann95c0db92016-01-17 11:01:25 +01002616 batadv_tt_local_entry_put(tt_local_entry);
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002617
Marek Lindner7b36e8e2011-02-18 12:28:10 +00002618 return orig_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002619}
Antonio Quartullia73105b2011-04-27 14:27:44 +02002620
Antonio Quartulliced72932013-04-24 16:37:51 +02002621/**
2622 * batadv_tt_global_crc - calculates the checksum of the local table belonging
2623 * to the given orig_node
2624 * @bat_priv: the bat priv with all the soft interface information
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002625 * @orig_node: originator for which the CRC should be computed
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002626 * @vid: VLAN identifier for which the CRC32 has to be computed
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002627 *
2628 * This function computes the checksum for the global table corresponding to a
2629 * specific originator. In particular, the checksum is computed as follows: For
2630 * each client connected to the originator the CRC32C of the MAC address and the
2631 * VID is computed and then all the CRC32Cs of the various clients are xor'ed
2632 * together.
2633 *
2634 * The idea behind is that CRC32C should be used as much as possible in order to
2635 * produce a unique hash of the table, but since the order which is used to feed
2636 * the CRC32C function affects the result and since every node in the network
2637 * probably sorts the clients differently, the hash function cannot be directly
2638 * computed over the entire table. Hence the CRC32C is used only on
2639 * the single client entry, while all the results are then xor'ed together
2640 * because the XOR operation can combine them all while trying to reduce the
2641 * noise as much as possible.
2642 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02002643 * Return: the checksum of the global table of a given originator.
Antonio Quartulliced72932013-04-24 16:37:51 +02002644 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002645static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
2646 struct batadv_orig_node *orig_node,
2647 unsigned short vid)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002648{
Sven Eckelmann807736f2012-07-15 22:26:51 +02002649 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
Linus Lüssing805596e2020-03-16 23:30:48 +01002650 struct batadv_tt_orig_list_entry *tt_orig;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002651 struct batadv_tt_common_entry *tt_common;
2652 struct batadv_tt_global_entry *tt_global;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002653 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002654 u32 i, crc_tmp, crc = 0;
2655 u8 flags;
Antonio Quartullia30e22c2014-02-11 17:05:06 +01002656 __be16 tmp_vid;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002657
2658 for (i = 0; i < hash->size; i++) {
2659 head = &hash->table[i];
2660
2661 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08002662 hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
Sven Eckelmann56303d32012-06-05 22:31:31 +02002663 tt_global = container_of(tt_common,
2664 struct batadv_tt_global_entry,
2665 common);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002666 /* compute the CRC only for entries belonging to the
2667 * VLAN identified by the vid passed as parameter
2668 */
2669 if (tt_common->vid != vid)
2670 continue;
2671
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002672 /* Roaming clients are in the global table for
2673 * consistency only. They don't have to be
2674 * taken into account while computing the
2675 * global crc
2676 */
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002677 if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002678 continue;
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002679 /* Temporary clients have not been announced yet, so
2680 * they have to be skipped while computing the global
2681 * crc
2682 */
2683 if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
2684 continue;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002685
2686 /* find out if this global entry is announced by this
2687 * originator
2688 */
Linus Lüssing805596e2020-03-16 23:30:48 +01002689 tt_orig = batadv_tt_global_orig_entry_find(tt_global,
2690 orig_node);
2691 if (!tt_orig)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002692 continue;
2693
Antonio Quartullia30e22c2014-02-11 17:05:06 +01002694 /* use network order to read the VID: this ensures that
2695 * every node reads the bytes in the same order.
2696 */
2697 tmp_vid = htons(tt_common->vid);
2698 crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
Antonio Quartulli0eb015682013-10-13 02:50:20 +02002699
2700 /* compute the CRC on flags that have to be kept in sync
2701 * among nodes
2702 */
Linus Lüssing805596e2020-03-16 23:30:48 +01002703 flags = tt_orig->flags;
Antonio Quartulli0eb015682013-10-13 02:50:20 +02002704 crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
2705
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002706 crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
Linus Lüssing805596e2020-03-16 23:30:48 +01002707
2708 batadv_tt_orig_list_entry_put(tt_orig);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002709 }
2710 rcu_read_unlock();
2711 }
2712
Antonio Quartulliced72932013-04-24 16:37:51 +02002713 return crc;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002714}
2715
Antonio Quartulliced72932013-04-24 16:37:51 +02002716/**
2717 * batadv_tt_local_crc - calculates the checksum of the local table
2718 * @bat_priv: the bat priv with all the soft interface information
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002719 * @vid: VLAN identifier for which the CRC32 has to be computed
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002720 *
2721 * For details about the computation, please refer to the documentation for
2722 * batadv_tt_global_crc().
2723 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02002724 * Return: the checksum of the local table
Antonio Quartulliced72932013-04-24 16:37:51 +02002725 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002726static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
2727 unsigned short vid)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002728{
Sven Eckelmann807736f2012-07-15 22:26:51 +02002729 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002730 struct batadv_tt_common_entry *tt_common;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002731 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002732 u32 i, crc_tmp, crc = 0;
2733 u8 flags;
Antonio Quartullia30e22c2014-02-11 17:05:06 +01002734 __be16 tmp_vid;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002735
2736 for (i = 0; i < hash->size; i++) {
2737 head = &hash->table[i];
2738
2739 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08002740 hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002741 /* compute the CRC only for entries belonging to the
2742 * VLAN identified by vid
2743 */
2744 if (tt_common->vid != vid)
2745 continue;
2746
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002747 /* not yet committed clients have not to be taken into
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002748 * account while computing the CRC
2749 */
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002750 if (tt_common->flags & BATADV_TT_CLIENT_NEW)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002751 continue;
Antonio Quartulliced72932013-04-24 16:37:51 +02002752
Antonio Quartullia30e22c2014-02-11 17:05:06 +01002753 /* use network order to read the VID: this ensures that
2754 * every node reads the bytes in the same order.
2755 */
2756 tmp_vid = htons(tt_common->vid);
2757 crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
Antonio Quartulli0eb015682013-10-13 02:50:20 +02002758
2759 /* compute the CRC on flags that have to be kept in sync
2760 * among nodes
2761 */
2762 flags = tt_common->flags & BATADV_TT_SYNC_MASK;
2763 crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
2764
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002765 crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002766 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02002767 rcu_read_unlock();
2768 }
2769
Antonio Quartulliced72932013-04-24 16:37:51 +02002770 return crc;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002771}
2772
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02002773/**
2774 * batadv_tt_req_node_release - free tt_req node entry
2775 * @ref: kref pointer of the tt req_node entry
2776 */
2777static void batadv_tt_req_node_release(struct kref *ref)
2778{
2779 struct batadv_tt_req_node *tt_req_node;
2780
2781 tt_req_node = container_of(ref, struct batadv_tt_req_node, refcount);
2782
Sven Eckelmann86452f82016-06-25 16:44:06 +02002783 kmem_cache_free(batadv_tt_req_cache, tt_req_node);
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02002784}
2785
2786/**
2787 * batadv_tt_req_node_put - decrement the tt_req_node refcounter and
2788 * possibly release it
2789 * @tt_req_node: tt_req_node to be free'd
2790 */
2791static void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node)
2792{
2793 kref_put(&tt_req_node->refcount, batadv_tt_req_node_release);
2794}
2795
Sven Eckelmann56303d32012-06-05 22:31:31 +02002796static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002797{
Marek Lindner7c26a532015-06-28 22:16:06 +08002798 struct batadv_tt_req_node *node;
2799 struct hlist_node *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002800
Sven Eckelmann807736f2012-07-15 22:26:51 +02002801 spin_lock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002802
Marek Lindner7c26a532015-06-28 22:16:06 +08002803 hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
2804 hlist_del_init(&node->list);
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02002805 batadv_tt_req_node_put(node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002806 }
2807
Sven Eckelmann807736f2012-07-15 22:26:51 +02002808 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002809}
2810
Sven Eckelmann56303d32012-06-05 22:31:31 +02002811static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv,
2812 struct batadv_orig_node *orig_node,
Antonio Quartullie8cf2342013-05-28 13:14:28 +02002813 const void *tt_buff,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002814 u16 tt_buff_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002815{
Antonio Quartullia73105b2011-04-27 14:27:44 +02002816 /* Replace the old buffer only if I received something in the
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002817 * last OGM (the OGM could carry no changes)
2818 */
Antonio Quartullia73105b2011-04-27 14:27:44 +02002819 spin_lock_bh(&orig_node->tt_buff_lock);
2820 if (tt_buff_len > 0) {
2821 kfree(orig_node->tt_buff);
2822 orig_node->tt_buff_len = 0;
2823 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
2824 if (orig_node->tt_buff) {
2825 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
2826 orig_node->tt_buff_len = tt_buff_len;
2827 }
2828 }
2829 spin_unlock_bh(&orig_node->tt_buff_lock);
2830}
2831
Sven Eckelmann56303d32012-06-05 22:31:31 +02002832static void batadv_tt_req_purge(struct batadv_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002833{
Marek Lindner7c26a532015-06-28 22:16:06 +08002834 struct batadv_tt_req_node *node;
2835 struct hlist_node *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002836
Sven Eckelmann807736f2012-07-15 22:26:51 +02002837 spin_lock_bh(&bat_priv->tt.req_list_lock);
Marek Lindner7c26a532015-06-28 22:16:06 +08002838 hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002839 if (batadv_has_timed_out(node->issued_at,
2840 BATADV_TT_REQUEST_TIMEOUT)) {
Marek Lindner7c26a532015-06-28 22:16:06 +08002841 hlist_del_init(&node->list);
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02002842 batadv_tt_req_node_put(node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002843 }
2844 }
Sven Eckelmann807736f2012-07-15 22:26:51 +02002845 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002846}
2847
Marek Lindner383b8632015-06-18 16:24:24 +08002848/**
2849 * batadv_tt_req_node_new - search and possibly create a tt_req_node object
2850 * @bat_priv: the bat priv with all the soft interface information
2851 * @orig_node: orig node this request is being issued for
2852 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02002853 * Return: the pointer to the new tt_req_node struct if no request
Marek Lindner383b8632015-06-18 16:24:24 +08002854 * has already been issued for this orig_node, NULL otherwise.
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002855 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002856static struct batadv_tt_req_node *
Marek Lindner383b8632015-06-18 16:24:24 +08002857batadv_tt_req_node_new(struct batadv_priv *bat_priv,
Sven Eckelmann56303d32012-06-05 22:31:31 +02002858 struct batadv_orig_node *orig_node)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002859{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002860 struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002861
Sven Eckelmann807736f2012-07-15 22:26:51 +02002862 spin_lock_bh(&bat_priv->tt.req_list_lock);
Marek Lindner7c26a532015-06-28 22:16:06 +08002863 hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) {
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02002864 if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
2865 !batadv_has_timed_out(tt_req_node_tmp->issued_at,
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002866 BATADV_TT_REQUEST_TIMEOUT))
Antonio Quartullia73105b2011-04-27 14:27:44 +02002867 goto unlock;
2868 }
2869
Sven Eckelmann86452f82016-06-25 16:44:06 +02002870 tt_req_node = kmem_cache_alloc(batadv_tt_req_cache, GFP_ATOMIC);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002871 if (!tt_req_node)
2872 goto unlock;
2873
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02002874 kref_init(&tt_req_node->refcount);
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01002875 ether_addr_copy(tt_req_node->addr, orig_node->orig);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002876 tt_req_node->issued_at = jiffies;
2877
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02002878 kref_get(&tt_req_node->refcount);
Marek Lindner7c26a532015-06-28 22:16:06 +08002879 hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002880unlock:
Sven Eckelmann807736f2012-07-15 22:26:51 +02002881 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002882 return tt_req_node;
2883}
2884
Marek Lindner335fbe02013-04-23 21:40:02 +08002885/**
Linus Lüssing24443bf2020-03-16 23:30:55 +01002886 * batadv_tt_local_valid() - verify local tt entry and get flags
Marek Lindner335fbe02013-04-23 21:40:02 +08002887 * @entry_ptr: to be checked local tt entry
2888 * @data_ptr: not used but definition required to satisfy the callback prototype
Linus Lüssing24443bf2020-03-16 23:30:55 +01002889 * @flags: a pointer to store TT flags for this client to
2890 *
2891 * Checks the validity of the given local TT entry. If it is, then the provided
2892 * flags pointer is updated.
Marek Lindner335fbe02013-04-23 21:40:02 +08002893 *
Sven Eckelmann4b426b12016-02-22 21:02:39 +01002894 * Return: true if the entry is a valid, false otherwise.
Marek Lindner335fbe02013-04-23 21:40:02 +08002895 */
Linus Lüssing24443bf2020-03-16 23:30:55 +01002896static bool batadv_tt_local_valid(const void *entry_ptr,
2897 const void *data_ptr,
2898 u8 *flags)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002899{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002900 const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002901
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002902 if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
Sven Eckelmann4b426b12016-02-22 21:02:39 +01002903 return false;
Linus Lüssing24443bf2020-03-16 23:30:55 +01002904
2905 if (flags)
2906 *flags = tt_common_entry->flags;
2907
Sven Eckelmann4b426b12016-02-22 21:02:39 +01002908 return true;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002909}
2910
Linus Lüssing24443bf2020-03-16 23:30:55 +01002911/**
2912 * batadv_tt_global_valid() - verify global tt entry and get flags
2913 * @entry_ptr: to be checked global tt entry
2914 * @data_ptr: an orig_node object (may be NULL)
2915 * @flags: a pointer to store TT flags for this client to
2916 *
2917 * Checks the validity of the given global TT entry. If it is, then the provided
2918 * flags pointer is updated either with the common (summed) TT flags if data_ptr
2919 * is NULL or the specific, per originator TT flags otherwise.
2920 *
2921 * Return: true if the entry is a valid, false otherwise.
2922 */
Sven Eckelmann4b426b12016-02-22 21:02:39 +01002923static bool batadv_tt_global_valid(const void *entry_ptr,
Linus Lüssing24443bf2020-03-16 23:30:55 +01002924 const void *data_ptr,
2925 u8 *flags)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002926{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002927 const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
2928 const struct batadv_tt_global_entry *tt_global_entry;
2929 const struct batadv_orig_node *orig_node = data_ptr;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002930
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002931 if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
2932 tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
Sven Eckelmann4b426b12016-02-22 21:02:39 +01002933 return false;
Antonio Quartullicc47f662011-04-27 14:27:57 +02002934
Sven Eckelmann56303d32012-06-05 22:31:31 +02002935 tt_global_entry = container_of(tt_common_entry,
2936 struct batadv_tt_global_entry,
Antonio Quartulli48100ba2011-10-30 12:17:33 +01002937 common);
2938
Linus Lüssing24443bf2020-03-16 23:30:55 +01002939 return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node,
2940 flags);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002941}
2942
Marek Lindner335fbe02013-04-23 21:40:02 +08002943/**
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002944 * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the
2945 * specified tt hash
Marek Lindner335fbe02013-04-23 21:40:02 +08002946 * @bat_priv: the bat priv with all the soft interface information
2947 * @hash: hash table containing the tt entries
2948 * @tt_len: expected tvlv tt data buffer length in number of bytes
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002949 * @tvlv_buff: pointer to the buffer to fill with the TT data
Linus Lüssing24443bf2020-03-16 23:30:55 +01002950 * @valid_cb: function to filter tt change entries and to return TT flags
Marek Lindner335fbe02013-04-23 21:40:02 +08002951 * @cb_data: data passed to the filter function as argument
Linus Lüssing24443bf2020-03-16 23:30:55 +01002952 *
2953 * Fills the tvlv buff with the tt entries from the specified hash. If valid_cb
2954 * is not provided then this becomes a no-op.
Marek Lindner335fbe02013-04-23 21:40:02 +08002955 */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002956static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
2957 struct batadv_hashtable *hash,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002958 void *tvlv_buff, u16 tt_len,
Sven Eckelmann4b426b12016-02-22 21:02:39 +01002959 bool (*valid_cb)(const void *,
Linus Lüssing24443bf2020-03-16 23:30:55 +01002960 const void *,
2961 u8 *flags),
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002962 void *cb_data)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002963{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002964 struct batadv_tt_common_entry *tt_common_entry;
Marek Lindner335fbe02013-04-23 21:40:02 +08002965 struct batadv_tvlv_tt_change *tt_change;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002966 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002967 u16 tt_tot, tt_num_entries = 0;
Linus Lüssing24443bf2020-03-16 23:30:55 +01002968 u8 flags;
2969 bool ret;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02002970 u32 i;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002971
Antonio Quartulli298e6e62013-05-28 13:14:27 +02002972 tt_tot = batadv_tt_entries(tt_len);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002973 tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002974
Linus Lüssing24443bf2020-03-16 23:30:55 +01002975 if (!valid_cb)
2976 return;
2977
Antonio Quartullia73105b2011-04-27 14:27:44 +02002978 rcu_read_lock();
2979 for (i = 0; i < hash->size; i++) {
2980 head = &hash->table[i];
2981
Sasha Levinb67bfe02013-02-27 17:06:00 -08002982 hlist_for_each_entry_rcu(tt_common_entry,
Antonio Quartullia73105b2011-04-27 14:27:44 +02002983 head, hash_entry) {
Marek Lindner335fbe02013-04-23 21:40:02 +08002984 if (tt_tot == tt_num_entries)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002985 break;
2986
Linus Lüssing24443bf2020-03-16 23:30:55 +01002987 ret = valid_cb(tt_common_entry, cb_data, &flags);
2988 if (!ret)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002989 continue;
2990
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01002991 ether_addr_copy(tt_change->addr, tt_common_entry->addr);
Linus Lüssing24443bf2020-03-16 23:30:55 +01002992 tt_change->flags = flags;
Antonio Quartullic018ad32013-06-04 12:11:39 +02002993 tt_change->vid = htons(tt_common_entry->vid);
Antonio Quartullica663042013-12-15 13:26:55 +01002994 memset(tt_change->reserved, 0,
2995 sizeof(tt_change->reserved));
Antonio Quartullia73105b2011-04-27 14:27:44 +02002996
Marek Lindner335fbe02013-04-23 21:40:02 +08002997 tt_num_entries++;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002998 tt_change++;
2999 }
3000 }
3001 rcu_read_unlock();
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003002}
Antonio Quartullia73105b2011-04-27 14:27:44 +02003003
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003004/**
3005 * batadv_tt_global_check_crc - check if all the CRCs are correct
3006 * @orig_node: originator for which the CRCs have to be checked
3007 * @tt_vlan: pointer to the first tvlv VLAN entry
3008 * @num_vlan: number of tvlv VLAN entries
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003009 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02003010 * Return: true if all the received CRCs match the locally stored ones, false
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003011 * otherwise
3012 */
3013static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
3014 struct batadv_tvlv_tt_vlan_data *tt_vlan,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003015 u16 num_vlan)
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003016{
3017 struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
3018 struct batadv_orig_node_vlan *vlan;
Simon Wunderlichc169c592015-09-02 20:09:56 +02003019 int i, orig_num_vlan;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003020 u32 crc;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003021
3022 /* check if each received CRC matches the locally stored one */
3023 for (i = 0; i < num_vlan; i++) {
3024 tt_vlan_tmp = tt_vlan + i;
3025
3026 /* if orig_node is a backbone node for this VLAN, don't check
3027 * the CRC as we ignore all the global entries over it
3028 */
3029 if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv,
Antonio Quartullicfd4f752013-08-07 18:28:56 +02003030 orig_node->orig,
3031 ntohs(tt_vlan_tmp->vid)))
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003032 continue;
3033
3034 vlan = batadv_orig_node_vlan_get(orig_node,
3035 ntohs(tt_vlan_tmp->vid));
3036 if (!vlan)
3037 return false;
3038
Antonio Quartulli91c2b1a2014-01-28 02:06:47 +01003039 crc = vlan->tt.crc;
Sven Eckelmann21754e22016-01-17 11:01:24 +01003040 batadv_orig_node_vlan_put(vlan);
Antonio Quartulli91c2b1a2014-01-28 02:06:47 +01003041
3042 if (crc != ntohl(tt_vlan_tmp->crc))
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003043 return false;
3044 }
3045
Simon Wunderlichc169c592015-09-02 20:09:56 +02003046 /* check if any excess VLANs exist locally for the originator
3047 * which are not mentioned in the TVLV from the originator.
3048 */
3049 rcu_read_lock();
3050 orig_num_vlan = 0;
3051 hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list)
3052 orig_num_vlan++;
3053 rcu_read_unlock();
3054
3055 if (orig_num_vlan > num_vlan)
3056 return false;
3057
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003058 return true;
3059}
3060
3061/**
3062 * batadv_tt_local_update_crc - update all the local CRCs
3063 * @bat_priv: the bat priv with all the soft interface information
3064 */
3065static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv)
3066{
3067 struct batadv_softif_vlan *vlan;
3068
3069 /* recompute the global CRC for each VLAN */
3070 rcu_read_lock();
3071 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
3072 vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid);
3073 }
3074 rcu_read_unlock();
3075}
3076
3077/**
3078 * batadv_tt_global_update_crc - update all the global CRCs for this orig_node
3079 * @bat_priv: the bat priv with all the soft interface information
3080 * @orig_node: the orig_node for which the CRCs have to be updated
3081 */
3082static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
3083 struct batadv_orig_node *orig_node)
3084{
3085 struct batadv_orig_node_vlan *vlan;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003086 u32 crc;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003087
3088 /* recompute the global CRC for each VLAN */
3089 rcu_read_lock();
Marek Lindnerd0fa4f32015-06-22 00:30:22 +08003090 hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003091 /* if orig_node is a backbone node for this VLAN, don't compute
3092 * the CRC as we ignore all the global entries over it
3093 */
Antonio Quartullicfd4f752013-08-07 18:28:56 +02003094 if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig,
3095 vlan->vid))
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003096 continue;
3097
3098 crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid);
3099 vlan->tt.crc = crc;
3100 }
3101 rcu_read_unlock();
Antonio Quartullia73105b2011-04-27 14:27:44 +02003102}
3103
Antonio Quartulliced72932013-04-24 16:37:51 +02003104/**
3105 * batadv_send_tt_request - send a TT Request message to a given node
3106 * @bat_priv: the bat priv with all the soft interface information
3107 * @dst_orig_node: the destination of the message
3108 * @ttvn: the version number that the source of the message is looking for
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003109 * @tt_vlan: pointer to the first tvlv VLAN object to request
3110 * @num_vlan: number of tvlv VLAN entries
Antonio Quartulliced72932013-04-24 16:37:51 +02003111 * @full_table: ask for the entire translation table if true, while only for the
3112 * last TT diff otherwise
Antonio Quartullid15cd622015-11-17 16:40:52 +08003113 *
3114 * Return: true if the TT Request was sent, false otherwise
Antonio Quartulliced72932013-04-24 16:37:51 +02003115 */
Sven Eckelmann4b426b12016-02-22 21:02:39 +01003116static bool batadv_send_tt_request(struct batadv_priv *bat_priv,
3117 struct batadv_orig_node *dst_orig_node,
3118 u8 ttvn,
3119 struct batadv_tvlv_tt_vlan_data *tt_vlan,
3120 u16 num_vlan, bool full_table)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003121{
Marek Lindner335fbe02013-04-23 21:40:02 +08003122 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
Sven Eckelmann56303d32012-06-05 22:31:31 +02003123 struct batadv_tt_req_node *tt_req_node = NULL;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003124 struct batadv_tvlv_tt_vlan_data *tt_vlan_req;
3125 struct batadv_hard_iface *primary_if;
Marek Lindner335fbe02013-04-23 21:40:02 +08003126 bool ret = false;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003127 int i, size;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003128
Sven Eckelmanne5d89252012-05-12 13:48:54 +02003129 primary_if = batadv_primary_if_get_selected(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003130 if (!primary_if)
3131 goto out;
3132
3133 /* The new tt_req will be issued only if I'm not waiting for a
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003134 * reply from the same orig_node yet
3135 */
Marek Lindner383b8632015-06-18 16:24:24 +08003136 tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003137 if (!tt_req_node)
3138 goto out;
3139
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003140 size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan;
3141 tvlv_tt_data = kzalloc(size, GFP_ATOMIC);
Marek Lindner335fbe02013-04-23 21:40:02 +08003142 if (!tvlv_tt_data)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003143 goto out;
3144
Marek Lindner335fbe02013-04-23 21:40:02 +08003145 tvlv_tt_data->flags = BATADV_TT_REQUEST;
3146 tvlv_tt_data->ttvn = ttvn;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003147 tvlv_tt_data->num_vlan = htons(num_vlan);
3148
3149 /* send all the CRCs within the request. This is needed by intermediate
3150 * nodes to ensure they have the correct table before replying
3151 */
3152 tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1);
3153 for (i = 0; i < num_vlan; i++) {
3154 tt_vlan_req->vid = tt_vlan->vid;
3155 tt_vlan_req->crc = tt_vlan->crc;
3156
3157 tt_vlan_req++;
3158 tt_vlan++;
3159 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02003160
3161 if (full_table)
Marek Lindner335fbe02013-04-23 21:40:02 +08003162 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003163
Martin Hundebøllbb351ba2012-10-16 16:13:48 +02003164 batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n",
Marek Lindner335fbe02013-04-23 21:40:02 +08003165 dst_orig_node->orig, full_table ? 'F' : '.');
Antonio Quartullia73105b2011-04-27 14:27:44 +02003166
Sven Eckelmannd69909d2012-06-03 22:19:20 +02003167 batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX);
Marek Lindner335fbe02013-04-23 21:40:02 +08003168 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
3169 dst_orig_node->orig, BATADV_TVLV_TT, 1,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003170 tvlv_tt_data, size);
Marek Lindner335fbe02013-04-23 21:40:02 +08003171 ret = true;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003172
3173out:
Antonio Quartullia73105b2011-04-27 14:27:44 +02003174 if (primary_if)
Sven Eckelmann82047ad2016-01-17 11:01:10 +01003175 batadv_hardif_put(primary_if);
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02003176
Antonio Quartullia73105b2011-04-27 14:27:44 +02003177 if (ret && tt_req_node) {
Sven Eckelmann807736f2012-07-15 22:26:51 +02003178 spin_lock_bh(&bat_priv->tt.req_list_lock);
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02003179 if (!hlist_unhashed(&tt_req_node->list)) {
3180 hlist_del_init(&tt_req_node->list);
3181 batadv_tt_req_node_put(tt_req_node);
3182 }
Sven Eckelmann807736f2012-07-15 22:26:51 +02003183 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003184 }
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02003185
3186 if (tt_req_node)
3187 batadv_tt_req_node_put(tt_req_node);
3188
Marek Lindner335fbe02013-04-23 21:40:02 +08003189 kfree(tvlv_tt_data);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003190 return ret;
3191}
3192
Marek Lindner335fbe02013-04-23 21:40:02 +08003193/**
3194 * batadv_send_other_tt_response - send reply to tt request concerning another
3195 * node's translation table
3196 * @bat_priv: the bat priv with all the soft interface information
3197 * @tt_data: tt data containing the tt request information
3198 * @req_src: mac address of tt request sender
3199 * @req_dst: mac address of tt request recipient
3200 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02003201 * Return: true if tt request reply was sent, false otherwise.
Marek Lindner335fbe02013-04-23 21:40:02 +08003202 */
3203static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
3204 struct batadv_tvlv_tt_data *tt_data,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003205 u8 *req_src, u8 *req_dst)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003206{
Sven Eckelmann170173b2012-10-07 12:02:22 +02003207 struct batadv_orig_node *req_dst_orig_node;
Sven Eckelmann56303d32012-06-05 22:31:31 +02003208 struct batadv_orig_node *res_dst_orig_node = NULL;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003209 struct batadv_tvlv_tt_change *tt_change;
Marek Lindner335fbe02013-04-23 21:40:02 +08003210 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003211 struct batadv_tvlv_tt_vlan_data *tt_vlan;
Marek Lindner335fbe02013-04-23 21:40:02 +08003212 bool ret = false, full_table;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003213 u8 orig_ttvn, req_ttvn;
3214 u16 tvlv_len;
3215 s32 tt_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003216
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003217 batadv_dbg(BATADV_DBG_TT, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02003218 "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
Marek Lindner335fbe02013-04-23 21:40:02 +08003219 req_src, tt_data->ttvn, req_dst,
Sven Eckelmanna2f2b6c2015-04-23 18:22:24 +02003220 ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
Antonio Quartullia73105b2011-04-27 14:27:44 +02003221
3222 /* Let's get the orig node of the REAL destination */
Marek Lindner335fbe02013-04-23 21:40:02 +08003223 req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003224 if (!req_dst_orig_node)
3225 goto out;
3226
Marek Lindner335fbe02013-04-23 21:40:02 +08003227 res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003228 if (!res_dst_orig_node)
3229 goto out;
3230
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003231 orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn);
Marek Lindner335fbe02013-04-23 21:40:02 +08003232 req_ttvn = tt_data->ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003233
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003234 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
Marek Lindner335fbe02013-04-23 21:40:02 +08003235 /* this node doesn't have the requested data */
Antonio Quartullia73105b2011-04-27 14:27:44 +02003236 if (orig_ttvn != req_ttvn ||
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003237 !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan,
3238 ntohs(tt_data->num_vlan)))
Antonio Quartullia73105b2011-04-27 14:27:44 +02003239 goto out;
3240
Antonio Quartulli015758d2011-07-09 17:52:13 +02003241 /* If the full table has been explicitly requested */
Marek Lindner335fbe02013-04-23 21:40:02 +08003242 if (tt_data->flags & BATADV_TT_FULL_TABLE ||
Antonio Quartullia73105b2011-04-27 14:27:44 +02003243 !req_dst_orig_node->tt_buff)
3244 full_table = true;
3245 else
3246 full_table = false;
3247
Marek Lindner335fbe02013-04-23 21:40:02 +08003248 /* TT fragmentation hasn't been implemented yet, so send as many
3249 * TT entries fit a single packet as possible only
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003250 */
Antonio Quartullia73105b2011-04-27 14:27:44 +02003251 if (!full_table) {
3252 spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
3253 tt_len = req_dst_orig_node->tt_buff_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003254
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003255 tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
3256 &tvlv_tt_data,
3257 &tt_change,
3258 &tt_len);
3259 if (!tt_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003260 goto unlock;
3261
Antonio Quartullia73105b2011-04-27 14:27:44 +02003262 /* Copy the last orig_node's OGM buffer */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003263 memcpy(tt_change, req_dst_orig_node->tt_buff,
Antonio Quartullia73105b2011-04-27 14:27:44 +02003264 req_dst_orig_node->tt_buff_len);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003265 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
3266 } else {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003267 /* allocate the tvlv, put the tt_data and all the tt_vlan_data
3268 * in the initial part
3269 */
3270 tt_len = -1;
3271 tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
3272 &tvlv_tt_data,
3273 &tt_change,
3274 &tt_len);
3275 if (!tt_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003276 goto out;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003277
3278 /* fill the rest of the tvlv with the real TT entries */
3279 batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash,
3280 tt_change, tt_len,
3281 batadv_tt_global_valid,
3282 req_dst_orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003283 }
3284
Marek Lindnera19d3d82013-05-27 15:33:25 +08003285 /* Don't send the response, if larger than fragmented packet. */
3286 tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
3287 if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
3288 net_ratelimited_function(batadv_info, bat_priv->soft_iface,
3289 "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
3290 res_dst_orig_node->orig);
3291 goto out;
3292 }
3293
Marek Lindner335fbe02013-04-23 21:40:02 +08003294 tvlv_tt_data->flags = BATADV_TT_RESPONSE;
3295 tvlv_tt_data->ttvn = req_ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003296
3297 if (full_table)
Marek Lindner335fbe02013-04-23 21:40:02 +08003298 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003299
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003300 batadv_dbg(BATADV_DBG_TT, bat_priv,
Marek Lindner335fbe02013-04-23 21:40:02 +08003301 "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n",
3302 res_dst_orig_node->orig, req_dst_orig_node->orig,
3303 full_table ? 'F' : '.', req_ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003304
Sven Eckelmannd69909d2012-06-03 22:19:20 +02003305 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
Martin Hundebøllf8214862012-04-20 17:02:45 +02003306
Marek Lindner335fbe02013-04-23 21:40:02 +08003307 batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003308 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
3309 tvlv_len);
Martin Hundebølle91ecfc2013-04-20 13:54:39 +02003310
Marek Lindner335fbe02013-04-23 21:40:02 +08003311 ret = true;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003312 goto out;
3313
3314unlock:
3315 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
3316
3317out:
3318 if (res_dst_orig_node)
Sven Eckelmann5d967312016-01-17 11:01:09 +01003319 batadv_orig_node_put(res_dst_orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003320 if (req_dst_orig_node)
Sven Eckelmann5d967312016-01-17 11:01:09 +01003321 batadv_orig_node_put(req_dst_orig_node);
Marek Lindner335fbe02013-04-23 21:40:02 +08003322 kfree(tvlv_tt_data);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003323 return ret;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003324}
Sven Eckelmann96412692012-06-05 22:31:30 +02003325
Marek Lindner335fbe02013-04-23 21:40:02 +08003326/**
3327 * batadv_send_my_tt_response - send reply to tt request concerning this node's
3328 * translation table
3329 * @bat_priv: the bat priv with all the soft interface information
3330 * @tt_data: tt data containing the tt request information
3331 * @req_src: mac address of tt request sender
3332 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02003333 * Return: true if tt request reply was sent, false otherwise.
Marek Lindner335fbe02013-04-23 21:40:02 +08003334 */
3335static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
3336 struct batadv_tvlv_tt_data *tt_data,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003337 u8 *req_src)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003338{
Marek Lindner335fbe02013-04-23 21:40:02 +08003339 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
Sven Eckelmann56303d32012-06-05 22:31:31 +02003340 struct batadv_hard_iface *primary_if = NULL;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003341 struct batadv_tvlv_tt_change *tt_change;
3342 struct batadv_orig_node *orig_node;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003343 u8 my_ttvn, req_ttvn;
3344 u16 tvlv_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003345 bool full_table;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003346 s32 tt_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003347
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003348 batadv_dbg(BATADV_DBG_TT, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02003349 "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
Marek Lindner335fbe02013-04-23 21:40:02 +08003350 req_src, tt_data->ttvn,
Sven Eckelmanna2f2b6c2015-04-23 18:22:24 +02003351 ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
Antonio Quartullia73105b2011-04-27 14:27:44 +02003352
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003353 spin_lock_bh(&bat_priv->tt.commit_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003354
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003355 my_ttvn = (u8)atomic_read(&bat_priv->tt.vn);
Marek Lindner335fbe02013-04-23 21:40:02 +08003356 req_ttvn = tt_data->ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003357
Marek Lindner335fbe02013-04-23 21:40:02 +08003358 orig_node = batadv_orig_hash_find(bat_priv, req_src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003359 if (!orig_node)
3360 goto out;
3361
Sven Eckelmanne5d89252012-05-12 13:48:54 +02003362 primary_if = batadv_primary_if_get_selected(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003363 if (!primary_if)
3364 goto out;
3365
3366 /* If the full table has been explicitly requested or the gap
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003367 * is too big send the whole local translation table
3368 */
Marek Lindner335fbe02013-04-23 21:40:02 +08003369 if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn ||
Sven Eckelmann807736f2012-07-15 22:26:51 +02003370 !bat_priv->tt.last_changeset)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003371 full_table = true;
3372 else
3373 full_table = false;
3374
Marek Lindner335fbe02013-04-23 21:40:02 +08003375 /* TT fragmentation hasn't been implemented yet, so send as many
3376 * TT entries fit a single packet as possible only
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003377 */
Antonio Quartullia73105b2011-04-27 14:27:44 +02003378 if (!full_table) {
Sven Eckelmann807736f2012-07-15 22:26:51 +02003379 spin_lock_bh(&bat_priv->tt.last_changeset_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003380
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003381 tt_len = bat_priv->tt.last_changeset_len;
3382 tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
3383 &tvlv_tt_data,
3384 &tt_change,
3385 &tt_len);
Sven Eckelmannc2d0f482016-11-30 21:47:09 +01003386 if (!tt_len || !tvlv_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003387 goto unlock;
3388
Marek Lindner335fbe02013-04-23 21:40:02 +08003389 /* Copy the last orig_node's OGM buffer */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003390 memcpy(tt_change, bat_priv->tt.last_changeset,
Sven Eckelmann807736f2012-07-15 22:26:51 +02003391 bat_priv->tt.last_changeset_len);
3392 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003393 } else {
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003394 req_ttvn = (u8)atomic_read(&bat_priv->tt.vn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003395
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003396 /* allocate the tvlv, put the tt_data and all the tt_vlan_data
3397 * in the initial part
3398 */
3399 tt_len = -1;
3400 tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
3401 &tvlv_tt_data,
3402 &tt_change,
3403 &tt_len);
Sven Eckelmannc2d0f482016-11-30 21:47:09 +01003404 if (!tt_len || !tvlv_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003405 goto out;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003406
3407 /* fill the rest of the tvlv with the real TT entries */
3408 batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash,
3409 tt_change, tt_len,
3410 batadv_tt_local_valid, NULL);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003411 }
3412
Marek Lindner335fbe02013-04-23 21:40:02 +08003413 tvlv_tt_data->flags = BATADV_TT_RESPONSE;
3414 tvlv_tt_data->ttvn = req_ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003415
3416 if (full_table)
Marek Lindner335fbe02013-04-23 21:40:02 +08003417 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003418
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003419 batadv_dbg(BATADV_DBG_TT, bat_priv,
Marek Lindner335fbe02013-04-23 21:40:02 +08003420 "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n",
3421 orig_node->orig, full_table ? 'F' : '.', req_ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003422
Sven Eckelmannd69909d2012-06-03 22:19:20 +02003423 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
Martin Hundebøllf8214862012-04-20 17:02:45 +02003424
Marek Lindner335fbe02013-04-23 21:40:02 +08003425 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003426 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
3427 tvlv_len);
Marek Lindner335fbe02013-04-23 21:40:02 +08003428
Antonio Quartullia73105b2011-04-27 14:27:44 +02003429 goto out;
3430
3431unlock:
Sven Eckelmann807736f2012-07-15 22:26:51 +02003432 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003433out:
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003434 spin_unlock_bh(&bat_priv->tt.commit_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003435 if (orig_node)
Sven Eckelmann5d967312016-01-17 11:01:09 +01003436 batadv_orig_node_put(orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003437 if (primary_if)
Sven Eckelmann82047ad2016-01-17 11:01:10 +01003438 batadv_hardif_put(primary_if);
Marek Lindner335fbe02013-04-23 21:40:02 +08003439 kfree(tvlv_tt_data);
3440 /* The packet was for this host, so it doesn't need to be re-routed */
Antonio Quartullia73105b2011-04-27 14:27:44 +02003441 return true;
3442}
3443
Marek Lindner335fbe02013-04-23 21:40:02 +08003444/**
3445 * batadv_send_tt_response - send reply to tt request
3446 * @bat_priv: the bat priv with all the soft interface information
3447 * @tt_data: tt data containing the tt request information
3448 * @req_src: mac address of tt request sender
3449 * @req_dst: mac address of tt request recipient
3450 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02003451 * Return: true if tt request reply was sent, false otherwise.
Marek Lindner335fbe02013-04-23 21:40:02 +08003452 */
3453static bool batadv_send_tt_response(struct batadv_priv *bat_priv,
3454 struct batadv_tvlv_tt_data *tt_data,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003455 u8 *req_src, u8 *req_dst)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003456{
Antonio Quartullicfd4f752013-08-07 18:28:56 +02003457 if (batadv_is_my_mac(bat_priv, req_dst))
Marek Lindner335fbe02013-04-23 21:40:02 +08003458 return batadv_send_my_tt_response(bat_priv, tt_data, req_src);
Antonio Quartulli24820df2014-09-01 14:37:25 +02003459 return batadv_send_other_tt_response(bat_priv, tt_data, req_src,
3460 req_dst);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003461}
3462
Sven Eckelmann56303d32012-06-05 22:31:31 +02003463static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
3464 struct batadv_orig_node *orig_node,
Marek Lindner335fbe02013-04-23 21:40:02 +08003465 struct batadv_tvlv_tt_change *tt_change,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003466 u16 tt_num_changes, u8 ttvn)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003467{
3468 int i;
Sven Eckelmanna5130882012-05-16 20:23:16 +02003469 int roams;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003470
3471 for (i = 0; i < tt_num_changes; i++) {
Sven Eckelmannacd34af2012-06-03 22:19:21 +02003472 if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
3473 roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
Sven Eckelmanna5130882012-05-16 20:23:16 +02003474 batadv_tt_global_del(bat_priv, orig_node,
3475 (tt_change + i)->addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003476 ntohs((tt_change + i)->vid),
Antonio Quartullid4f44692012-05-25 00:00:54 +02003477 "tt removed by changes",
3478 roams);
Sven Eckelmann08c36d32012-05-12 02:09:39 +02003479 } else {
Sven Eckelmann08c36d32012-05-12 02:09:39 +02003480 if (!batadv_tt_global_add(bat_priv, orig_node,
Antonio Quartullid4f44692012-05-25 00:00:54 +02003481 (tt_change + i)->addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003482 ntohs((tt_change + i)->vid),
Antonio Quartullid4f44692012-05-25 00:00:54 +02003483 (tt_change + i)->flags, ttvn))
Antonio Quartullia73105b2011-04-27 14:27:44 +02003484 /* In case of problem while storing a
3485 * global_entry, we stop the updating
3486 * procedure without committing the
3487 * ttvn change. This will avoid to send
3488 * corrupted data on tt_request
3489 */
3490 return;
Sven Eckelmann08c36d32012-05-12 02:09:39 +02003491 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02003492 }
Linus Lüssingac4eebd2015-06-16 17:10:24 +02003493 set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003494}
3495
Sven Eckelmann56303d32012-06-05 22:31:31 +02003496static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003497 struct batadv_tvlv_tt_change *tt_change,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003498 u8 ttvn, u8 *resp_src,
3499 u16 num_entries)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003500{
Sven Eckelmann170173b2012-10-07 12:02:22 +02003501 struct batadv_orig_node *orig_node;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003502
Marek Lindner335fbe02013-04-23 21:40:02 +08003503 orig_node = batadv_orig_hash_find(bat_priv, resp_src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003504 if (!orig_node)
3505 goto out;
3506
3507 /* Purge the old table first.. */
Antonio Quartulli95fb1302013-08-07 18:28:55 +02003508 batadv_tt_global_del_orig(bat_priv, orig_node, -1,
3509 "Received full table");
Antonio Quartullia73105b2011-04-27 14:27:44 +02003510
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003511 _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries,
3512 ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003513
3514 spin_lock_bh(&orig_node->tt_buff_lock);
3515 kfree(orig_node->tt_buff);
3516 orig_node->tt_buff_len = 0;
3517 orig_node->tt_buff = NULL;
3518 spin_unlock_bh(&orig_node->tt_buff_lock);
3519
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003520 atomic_set(&orig_node->last_ttvn, ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003521
3522out:
3523 if (orig_node)
Sven Eckelmann5d967312016-01-17 11:01:09 +01003524 batadv_orig_node_put(orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003525}
3526
Sven Eckelmann56303d32012-06-05 22:31:31 +02003527static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
3528 struct batadv_orig_node *orig_node,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003529 u16 tt_num_changes, u8 ttvn,
Marek Lindner335fbe02013-04-23 21:40:02 +08003530 struct batadv_tvlv_tt_change *tt_change)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003531{
Sven Eckelmanna5130882012-05-16 20:23:16 +02003532 _batadv_tt_update_changes(bat_priv, orig_node, tt_change,
3533 tt_num_changes, ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003534
Antonio Quartullie8cf2342013-05-28 13:14:28 +02003535 batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change,
3536 batadv_tt_len(tt_num_changes));
Antonio Quartullia73105b2011-04-27 14:27:44 +02003537 atomic_set(&orig_node->last_ttvn, ttvn);
3538}
3539
Antonio Quartullic018ad32013-06-04 12:11:39 +02003540/**
3541 * batadv_is_my_client - check if a client is served by the local node
3542 * @bat_priv: the bat priv with all the soft interface information
Antonio Quartulli3f687852014-11-02 11:29:56 +01003543 * @addr: the mac address of the client to check
Antonio Quartullic018ad32013-06-04 12:11:39 +02003544 * @vid: VLAN identifier
3545 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02003546 * Return: true if the client is served by this node, false otherwise.
Antonio Quartullic018ad32013-06-04 12:11:39 +02003547 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003548bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003549 unsigned short vid)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003550{
Sven Eckelmann170173b2012-10-07 12:02:22 +02003551 struct batadv_tt_local_entry *tt_local_entry;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02003552 bool ret = false;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003553
Antonio Quartullic018ad32013-06-04 12:11:39 +02003554 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02003555 if (!tt_local_entry)
3556 goto out;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003557 /* Check if the client has been logically deleted (but is kept for
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003558 * consistency purpose)
3559 */
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02003560 if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
3561 (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003562 goto out;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02003563 ret = true;
3564out:
Antonio Quartullia73105b2011-04-27 14:27:44 +02003565 if (tt_local_entry)
Sven Eckelmann95c0db92016-01-17 11:01:25 +01003566 batadv_tt_local_entry_put(tt_local_entry);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02003567 return ret;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003568}
3569
Marek Lindner335fbe02013-04-23 21:40:02 +08003570/**
3571 * batadv_handle_tt_response - process incoming tt reply
3572 * @bat_priv: the bat priv with all the soft interface information
3573 * @tt_data: tt data containing the tt request information
3574 * @resp_src: mac address of tt reply sender
3575 * @num_entries: number of tt change entries appended to the tt data
3576 */
3577static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
3578 struct batadv_tvlv_tt_data *tt_data,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003579 u8 *resp_src, u16 num_entries)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003580{
Marek Lindner7c26a532015-06-28 22:16:06 +08003581 struct batadv_tt_req_node *node;
3582 struct hlist_node *safe;
Sven Eckelmann56303d32012-06-05 22:31:31 +02003583 struct batadv_orig_node *orig_node = NULL;
Marek Lindner335fbe02013-04-23 21:40:02 +08003584 struct batadv_tvlv_tt_change *tt_change;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003585 u8 *tvlv_ptr = (u8 *)tt_data;
3586 u16 change_offset;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003587
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003588 batadv_dbg(BATADV_DBG_TT, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02003589 "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
Marek Lindner335fbe02013-04-23 21:40:02 +08003590 resp_src, tt_data->ttvn, num_entries,
Sven Eckelmanna2f2b6c2015-04-23 18:22:24 +02003591 ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
Antonio Quartullia73105b2011-04-27 14:27:44 +02003592
Marek Lindner335fbe02013-04-23 21:40:02 +08003593 orig_node = batadv_orig_hash_find(bat_priv, resp_src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003594 if (!orig_node)
3595 goto out;
3596
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003597 spin_lock_bh(&orig_node->tt_lock);
3598
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003599 change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
3600 change_offset *= ntohs(tt_data->num_vlan);
3601 change_offset += sizeof(*tt_data);
3602 tvlv_ptr += change_offset;
3603
3604 tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
Marek Lindner335fbe02013-04-23 21:40:02 +08003605 if (tt_data->flags & BATADV_TT_FULL_TABLE) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003606 batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn,
3607 resp_src, num_entries);
Sven Eckelmann96412692012-06-05 22:31:30 +02003608 } else {
Marek Lindner335fbe02013-04-23 21:40:02 +08003609 batadv_tt_update_changes(bat_priv, orig_node, num_entries,
3610 tt_data->ttvn, tt_change);
Sven Eckelmann96412692012-06-05 22:31:30 +02003611 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02003612
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003613 /* Recalculate the CRC for this orig_node and store it */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003614 batadv_tt_global_update_crc(bat_priv, orig_node);
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003615
3616 spin_unlock_bh(&orig_node->tt_lock);
3617
Antonio Quartullia73105b2011-04-27 14:27:44 +02003618 /* Delete the tt_req_node from pending tt_requests list */
Sven Eckelmann807736f2012-07-15 22:26:51 +02003619 spin_lock_bh(&bat_priv->tt.req_list_lock);
Marek Lindner7c26a532015-06-28 22:16:06 +08003620 hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
Marek Lindner335fbe02013-04-23 21:40:02 +08003621 if (!batadv_compare_eth(node->addr, resp_src))
Antonio Quartullia73105b2011-04-27 14:27:44 +02003622 continue;
Marek Lindner7c26a532015-06-28 22:16:06 +08003623 hlist_del_init(&node->list);
Sven Eckelmann9c4604a2016-06-26 11:16:10 +02003624 batadv_tt_req_node_put(node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003625 }
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003626
Sven Eckelmann807736f2012-07-15 22:26:51 +02003627 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003628out:
3629 if (orig_node)
Sven Eckelmann5d967312016-01-17 11:01:09 +01003630 batadv_orig_node_put(orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003631}
3632
Sven Eckelmann56303d32012-06-05 22:31:31 +02003633static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003634{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003635 struct batadv_tt_roam_node *node, *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02003636
Sven Eckelmann807736f2012-07-15 22:26:51 +02003637 spin_lock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003638
Sven Eckelmann807736f2012-07-15 22:26:51 +02003639 list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
Antonio Quartullicc47f662011-04-27 14:27:57 +02003640 list_del(&node->list);
Sven Eckelmann86452f82016-06-25 16:44:06 +02003641 kmem_cache_free(batadv_tt_roam_cache, node);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003642 }
3643
Sven Eckelmann807736f2012-07-15 22:26:51 +02003644 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003645}
3646
Sven Eckelmann56303d32012-06-05 22:31:31 +02003647static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)
Antonio Quartullicc47f662011-04-27 14:27:57 +02003648{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003649 struct batadv_tt_roam_node *node, *safe;
Antonio Quartullicc47f662011-04-27 14:27:57 +02003650
Sven Eckelmann807736f2012-07-15 22:26:51 +02003651 spin_lock_bh(&bat_priv->tt.roam_list_lock);
3652 list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
Sven Eckelmann42d0b042012-06-03 22:19:17 +02003653 if (!batadv_has_timed_out(node->first_time,
3654 BATADV_ROAMING_MAX_TIME))
Antonio Quartullicc47f662011-04-27 14:27:57 +02003655 continue;
3656
3657 list_del(&node->list);
Sven Eckelmann86452f82016-06-25 16:44:06 +02003658 kmem_cache_free(batadv_tt_roam_cache, node);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003659 }
Sven Eckelmann807736f2012-07-15 22:26:51 +02003660 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003661}
3662
Sven Eckelmann62fe7102015-09-15 19:00:48 +02003663/**
Antonio Quartullid15cd622015-11-17 16:40:52 +08003664 * batadv_tt_check_roam_count - check if a client has roamed too frequently
3665 * @bat_priv: the bat priv with all the soft interface information
3666 * @client: mac address of the roaming client
Sven Eckelmann62fe7102015-09-15 19:00:48 +02003667 *
3668 * This function checks whether the client already reached the
Antonio Quartullicc47f662011-04-27 14:27:57 +02003669 * maximum number of possible roaming phases. In this case the ROAMING_ADV
3670 * will not be sent.
3671 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02003672 * Return: true if the ROAMING_ADV can be sent, false otherwise
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003673 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003674static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client)
Antonio Quartullicc47f662011-04-27 14:27:57 +02003675{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003676 struct batadv_tt_roam_node *tt_roam_node;
Antonio Quartullicc47f662011-04-27 14:27:57 +02003677 bool ret = false;
3678
Sven Eckelmann807736f2012-07-15 22:26:51 +02003679 spin_lock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003680 /* The new tt_req will be issued only if I'm not waiting for a
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003681 * reply from the same orig_node yet
3682 */
Sven Eckelmann807736f2012-07-15 22:26:51 +02003683 list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) {
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02003684 if (!batadv_compare_eth(tt_roam_node->addr, client))
Antonio Quartullicc47f662011-04-27 14:27:57 +02003685 continue;
3686
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02003687 if (batadv_has_timed_out(tt_roam_node->first_time,
Sven Eckelmann42d0b042012-06-03 22:19:17 +02003688 BATADV_ROAMING_MAX_TIME))
Antonio Quartullicc47f662011-04-27 14:27:57 +02003689 continue;
3690
Sven Eckelmann3e348192012-05-16 20:23:22 +02003691 if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter))
Antonio Quartullicc47f662011-04-27 14:27:57 +02003692 /* Sorry, you roamed too many times! */
3693 goto unlock;
3694 ret = true;
3695 break;
3696 }
3697
3698 if (!ret) {
Sven Eckelmann86452f82016-06-25 16:44:06 +02003699 tt_roam_node = kmem_cache_alloc(batadv_tt_roam_cache,
3700 GFP_ATOMIC);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003701 if (!tt_roam_node)
3702 goto unlock;
3703
3704 tt_roam_node->first_time = jiffies;
Sven Eckelmann42d0b042012-06-03 22:19:17 +02003705 atomic_set(&tt_roam_node->counter,
3706 BATADV_ROAMING_MAX_COUNT - 1);
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01003707 ether_addr_copy(tt_roam_node->addr, client);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003708
Sven Eckelmann807736f2012-07-15 22:26:51 +02003709 list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003710 ret = true;
3711 }
3712
3713unlock:
Sven Eckelmann807736f2012-07-15 22:26:51 +02003714 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003715 return ret;
3716}
3717
Antonio Quartullic018ad32013-06-04 12:11:39 +02003718/**
3719 * batadv_send_roam_adv - send a roaming advertisement message
3720 * @bat_priv: the bat priv with all the soft interface information
3721 * @client: mac address of the roaming client
3722 * @vid: VLAN identifier
3723 * @orig_node: message destination
3724 *
3725 * Send a ROAMING_ADV message to the node which was previously serving this
3726 * client. This is done to inform the node that from now on all traffic destined
3727 * for this particular roamed client has to be forwarded to the sender of the
3728 * roaming message.
3729 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003730static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003731 unsigned short vid,
Sven Eckelmann56303d32012-06-05 22:31:31 +02003732 struct batadv_orig_node *orig_node)
Antonio Quartullicc47f662011-04-27 14:27:57 +02003733{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003734 struct batadv_hard_iface *primary_if;
Marek Lindner122edaa2013-04-23 21:40:03 +08003735 struct batadv_tvlv_roam_adv tvlv_roam;
3736
3737 primary_if = batadv_primary_if_get_selected(bat_priv);
3738 if (!primary_if)
3739 goto out;
Antonio Quartullicc47f662011-04-27 14:27:57 +02003740
3741 /* before going on we have to check whether the client has
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003742 * already roamed to us too many times
3743 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02003744 if (!batadv_tt_check_roam_count(bat_priv, client))
Antonio Quartullicc47f662011-04-27 14:27:57 +02003745 goto out;
3746
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003747 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02003748 "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n",
3749 orig_node->orig, client, BATADV_PRINT_VID(vid));
Antonio Quartullicc47f662011-04-27 14:27:57 +02003750
Sven Eckelmannd69909d2012-06-03 22:19:20 +02003751 batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
Martin Hundebøllf8214862012-04-20 17:02:45 +02003752
Marek Lindner122edaa2013-04-23 21:40:03 +08003753 memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client));
Antonio Quartullic018ad32013-06-04 12:11:39 +02003754 tvlv_roam.vid = htons(vid);
Marek Lindner122edaa2013-04-23 21:40:03 +08003755
3756 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
3757 orig_node->orig, BATADV_TVLV_ROAM, 1,
3758 &tvlv_roam, sizeof(tvlv_roam));
Antonio Quartullicc47f662011-04-27 14:27:57 +02003759
3760out:
Marek Lindner122edaa2013-04-23 21:40:03 +08003761 if (primary_if)
Sven Eckelmann82047ad2016-01-17 11:01:10 +01003762 batadv_hardif_put(primary_if);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003763}
3764
Sven Eckelmanna5130882012-05-16 20:23:16 +02003765static void batadv_tt_purge(struct work_struct *work)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003766{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003767 struct delayed_work *delayed_work;
Sven Eckelmann807736f2012-07-15 22:26:51 +02003768 struct batadv_priv_tt *priv_tt;
Sven Eckelmann56303d32012-06-05 22:31:31 +02003769 struct batadv_priv *bat_priv;
3770
Geliang Tang4ba4bc02015-12-28 23:43:37 +08003771 delayed_work = to_delayed_work(work);
Sven Eckelmann807736f2012-07-15 22:26:51 +02003772 priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
3773 bat_priv = container_of(priv_tt, struct batadv_priv, tt);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003774
Marek Lindnera19d3d82013-05-27 15:33:25 +08003775 batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02003776 batadv_tt_global_purge(bat_priv);
Sven Eckelmanna5130882012-05-16 20:23:16 +02003777 batadv_tt_req_purge(bat_priv);
3778 batadv_tt_roam_purge(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003779
Antonio Quartulli72414442012-12-25 13:14:37 +01003780 queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
3781 msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
Antonio Quartullia73105b2011-04-27 14:27:44 +02003782}
Antonio Quartullicc47f662011-04-27 14:27:57 +02003783
Sven Eckelmann56303d32012-06-05 22:31:31 +02003784void batadv_tt_free(struct batadv_priv *bat_priv)
Antonio Quartullicc47f662011-04-27 14:27:57 +02003785{
Jeremy Sowden4a604de2019-05-21 20:58:57 +01003786 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_ROAM, 1);
3787
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003788 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1);
3789 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1);
3790
Sven Eckelmann807736f2012-07-15 22:26:51 +02003791 cancel_delayed_work_sync(&bat_priv->tt.work);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003792
Sven Eckelmanna5130882012-05-16 20:23:16 +02003793 batadv_tt_local_table_free(bat_priv);
3794 batadv_tt_global_table_free(bat_priv);
3795 batadv_tt_req_list_free(bat_priv);
3796 batadv_tt_changes_list_free(bat_priv);
3797 batadv_tt_roam_list_free(bat_priv);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003798
Sven Eckelmann807736f2012-07-15 22:26:51 +02003799 kfree(bat_priv->tt.last_changeset);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003800}
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003801
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003802/**
3803 * batadv_tt_local_set_flags - set or unset the specified flags on the local
3804 * table and possibly count them in the TT size
3805 * @bat_priv: the bat priv with all the soft interface information
3806 * @flags: the flag to switch
3807 * @enable: whether to set or unset the flag
3808 * @count: whether to increase the TT size by the number of changed entries
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003809 */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003810static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
3811 bool enable, bool count)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003812{
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003813 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
3814 struct batadv_tt_common_entry *tt_common_entry;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003815 u16 changed_num = 0;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003816 struct hlist_head *head;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003817 u32 i;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003818
3819 if (!hash)
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003820 return;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003821
3822 for (i = 0; i < hash->size; i++) {
3823 head = &hash->table[i];
3824
3825 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08003826 hlist_for_each_entry_rcu(tt_common_entry,
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003827 head, hash_entry) {
Antonio Quartulli697f2532011-11-07 16:47:01 +01003828 if (enable) {
3829 if ((tt_common_entry->flags & flags) == flags)
3830 continue;
3831 tt_common_entry->flags |= flags;
3832 } else {
3833 if (!(tt_common_entry->flags & flags))
3834 continue;
3835 tt_common_entry->flags &= ~flags;
3836 }
3837 changed_num++;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003838
3839 if (!count)
3840 continue;
3841
3842 batadv_tt_local_size_inc(bat_priv,
3843 tt_common_entry->vid);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003844 }
3845 rcu_read_unlock();
3846 }
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003847}
3848
Sven Eckelmannacd34af2012-06-03 22:19:21 +02003849/* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */
Sven Eckelmann56303d32012-06-05 22:31:31 +02003850static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003851{
Sven Eckelmann807736f2012-07-15 22:26:51 +02003852 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +02003853 struct batadv_tt_common_entry *tt_common;
3854 struct batadv_tt_local_entry *tt_local;
Sasha Levinb67bfe02013-02-27 17:06:00 -08003855 struct hlist_node *node_tmp;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003856 struct hlist_head *head;
3857 spinlock_t *list_lock; /* protects write access to the hash lists */
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003858 u32 i;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003859
3860 if (!hash)
3861 return;
3862
3863 for (i = 0; i < hash->size; i++) {
3864 head = &hash->table[i];
3865 list_lock = &hash->list_locks[i];
3866
3867 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08003868 hlist_for_each_entry_safe(tt_common, node_tmp, head,
Sven Eckelmannacd34af2012-06-03 22:19:21 +02003869 hash_entry) {
3870 if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003871 continue;
3872
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003873 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02003874 "Deleting local tt entry (%pM, vid: %d): pending\n",
3875 tt_common->addr,
3876 BATADV_PRINT_VID(tt_common->vid));
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003877
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003878 batadv_tt_local_size_dec(bat_priv, tt_common->vid);
Sasha Levinb67bfe02013-02-27 17:06:00 -08003879 hlist_del_rcu(&tt_common->hash_entry);
Sven Eckelmann56303d32012-06-05 22:31:31 +02003880 tt_local = container_of(tt_common,
3881 struct batadv_tt_local_entry,
3882 common);
Antonio Quartulli35df3b22014-05-08 17:13:15 +02003883
Sven Eckelmann95c0db92016-01-17 11:01:25 +01003884 batadv_tt_local_entry_put(tt_local);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003885 }
3886 spin_unlock_bh(list_lock);
3887 }
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003888}
3889
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003890/**
Marek Lindnera19d3d82013-05-27 15:33:25 +08003891 * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes
3892 * which have been queued in the time since the last commit
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003893 * @bat_priv: the bat priv with all the soft interface information
Marek Lindnera19d3d82013-05-27 15:33:25 +08003894 *
3895 * Caller must hold tt->commit_lock.
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003896 */
Marek Lindnera19d3d82013-05-27 15:33:25 +08003897static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003898{
Sven Eckelmann5274cd62015-06-21 14:45:15 +02003899 lockdep_assert_held(&bat_priv->tt.commit_lock);
3900
Linus Lüssingc5caf4e2014-02-15 17:47:49 +01003901 /* Update multicast addresses in local translation table */
3902 batadv_mcast_mla_update(bat_priv);
3903
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003904 if (atomic_read(&bat_priv->tt.local_changes) < 1) {
3905 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
3906 batadv_tt_tvlv_container_update(bat_priv);
Marek Lindnera19d3d82013-05-27 15:33:25 +08003907 return;
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003908 }
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08003909
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003910 batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08003911
Sven Eckelmanna5130882012-05-16 20:23:16 +02003912 batadv_tt_local_purge_pending_clients(bat_priv);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003913 batadv_tt_local_update_crc(bat_priv);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003914
3915 /* Increment the TTVN only once per OGM interval */
Sven Eckelmann807736f2012-07-15 22:26:51 +02003916 atomic_inc(&bat_priv->tt.vn);
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003917 batadv_dbg(BATADV_DBG_TT, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02003918 "Local changes committed, updating to ttvn %u\n",
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003919 (u8)atomic_read(&bat_priv->tt.vn));
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08003920
3921 /* reset the sending counter */
Sven Eckelmann807736f2012-07-15 22:26:51 +02003922 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003923 batadv_tt_tvlv_container_update(bat_priv);
Marek Lindnera19d3d82013-05-27 15:33:25 +08003924}
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003925
Marek Lindnera19d3d82013-05-27 15:33:25 +08003926/**
3927 * batadv_tt_local_commit_changes - commit all pending local tt changes which
3928 * have been queued in the time since the last commit
3929 * @bat_priv: the bat priv with all the soft interface information
3930 */
3931void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
3932{
3933 spin_lock_bh(&bat_priv->tt.commit_lock);
3934 batadv_tt_local_commit_changes_nolock(bat_priv);
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003935 spin_unlock_bh(&bat_priv->tt.commit_lock);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003936}
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003937
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003938bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst,
3939 unsigned short vid)
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003940{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003941 struct batadv_tt_local_entry *tt_local_entry = NULL;
3942 struct batadv_tt_global_entry *tt_global_entry = NULL;
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003943 struct batadv_softif_vlan *vlan;
Marek Lindner5870adc2012-06-20 17:16:05 +02003944 bool ret = false;
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003945
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003946 vlan = batadv_softif_vlan_get(bat_priv, vid);
Markus Elfringe087f342015-11-03 19:20:34 +01003947 if (!vlan)
3948 return false;
3949
3950 if (!atomic_read(&vlan->ap_isolation))
Marek Lindner5870adc2012-06-20 17:16:05 +02003951 goto out;
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003952
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003953 tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003954 if (!tt_local_entry)
3955 goto out;
3956
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003957 tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003958 if (!tt_global_entry)
3959 goto out;
3960
Antonio Quartulli1f129fe2012-06-25 20:49:50 +00003961 if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003962 goto out;
3963
Marek Lindner5870adc2012-06-20 17:16:05 +02003964 ret = true;
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003965
3966out:
Sven Eckelmann9c3bf082016-01-17 11:01:21 +01003967 batadv_softif_vlan_put(vlan);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003968 if (tt_global_entry)
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01003969 batadv_tt_global_entry_put(tt_global_entry);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003970 if (tt_local_entry)
Sven Eckelmann95c0db92016-01-17 11:01:25 +01003971 batadv_tt_local_entry_put(tt_local_entry);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003972 return ret;
3973}
Marek Lindnera943cac2011-07-30 13:10:18 +02003974
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003975/**
3976 * batadv_tt_update_orig - update global translation table with new tt
3977 * information received via ogms
3978 * @bat_priv: the bat priv with all the soft interface information
Sven Eckelmanne51f0392015-09-06 21:38:51 +02003979 * @orig_node: the orig_node of the ogm
3980 * @tt_buff: pointer to the first tvlv VLAN entry
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003981 * @tt_num_vlan: number of tvlv VLAN entries
3982 * @tt_change: pointer to the first entry in the TT buffer
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003983 * @tt_num_changes: number of tt changes inside the tt buffer
3984 * @ttvn: translation table version number of this changeset
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003985 */
3986static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
3987 struct batadv_orig_node *orig_node,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003988 const void *tt_buff, u16 tt_num_vlan,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003989 struct batadv_tvlv_tt_change *tt_change,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003990 u16 tt_num_changes, u8 ttvn)
Marek Lindnera943cac2011-07-30 13:10:18 +02003991{
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02003992 u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003993 struct batadv_tvlv_tt_vlan_data *tt_vlan;
Marek Lindnera943cac2011-07-30 13:10:18 +02003994 bool full_table = true;
Linus Lüssinge17931d2014-02-15 17:47:50 +01003995 bool has_tt_init;
Marek Lindnera943cac2011-07-30 13:10:18 +02003996
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003997 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
Linus Lüssingac4eebd2015-06-16 17:10:24 +02003998 has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT,
3999 &orig_node->capa_initialized);
Linus Lüssinge17931d2014-02-15 17:47:50 +01004000
Antonio Quartulli17071572011-11-07 16:36:40 +01004001 /* orig table not initialised AND first diff is in the OGM OR the ttvn
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02004002 * increased by one -> we can apply the attached changes
4003 */
Linus Lüssinge17931d2014-02-15 17:47:50 +01004004 if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) {
Marek Lindnera943cac2011-07-30 13:10:18 +02004005 /* the OGM could not contain the changes due to their size or
Sven Eckelmann42d0b042012-06-03 22:19:17 +02004006 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
4007 * times.
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02004008 * In this case send a tt request
4009 */
Marek Lindnera943cac2011-07-30 13:10:18 +02004010 if (!tt_num_changes) {
4011 full_table = false;
4012 goto request_table;
4013 }
4014
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02004015 spin_lock_bh(&orig_node->tt_lock);
4016
Sven Eckelmanna5130882012-05-16 20:23:16 +02004017 batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
Sven Eckelmann96412692012-06-05 22:31:30 +02004018 ttvn, tt_change);
Marek Lindnera943cac2011-07-30 13:10:18 +02004019
4020 /* Even if we received the precomputed crc with the OGM, we
4021 * prefer to recompute it to spot any possible inconsistency
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02004022 * in the global table
4023 */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004024 batadv_tt_global_update_crc(bat_priv, orig_node);
Marek Lindnera943cac2011-07-30 13:10:18 +02004025
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02004026 spin_unlock_bh(&orig_node->tt_lock);
4027
Marek Lindnera943cac2011-07-30 13:10:18 +02004028 /* The ttvn alone is not enough to guarantee consistency
4029 * because a single value could represent different states
4030 * (due to the wrap around). Thus a node has to check whether
4031 * the resulting table (after applying the changes) is still
4032 * consistent or not. E.g. a node could disconnect while its
4033 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
4034 * checking the CRC value is mandatory to detect the
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02004035 * inconsistency
4036 */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004037 if (!batadv_tt_global_check_crc(orig_node, tt_vlan,
4038 tt_num_vlan))
Marek Lindnera943cac2011-07-30 13:10:18 +02004039 goto request_table;
Marek Lindnera943cac2011-07-30 13:10:18 +02004040 } else {
4041 /* if we missed more than one change or our tables are not
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02004042 * in sync anymore -> request fresh tt data
4043 */
Linus Lüssinge17931d2014-02-15 17:47:50 +01004044 if (!has_tt_init || ttvn != orig_ttvn ||
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004045 !batadv_tt_global_check_crc(orig_node, tt_vlan,
4046 tt_num_vlan)) {
Marek Lindnera943cac2011-07-30 13:10:18 +02004047request_table:
Sven Eckelmann39c75a52012-06-03 22:19:22 +02004048 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004049 "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n",
4050 orig_node->orig, ttvn, orig_ttvn,
4051 tt_num_changes);
Sven Eckelmanna5130882012-05-16 20:23:16 +02004052 batadv_send_tt_request(bat_priv, orig_node, ttvn,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004053 tt_vlan, tt_num_vlan,
4054 full_table);
Marek Lindnera943cac2011-07-30 13:10:18 +02004055 return;
4056 }
4057 }
4058}
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01004059
Antonio Quartullic018ad32013-06-04 12:11:39 +02004060/**
4061 * batadv_tt_global_client_is_roaming - check if a client is marked as roaming
4062 * @bat_priv: the bat priv with all the soft interface information
4063 * @addr: the mac address of the client to check
4064 * @vid: VLAN identifier
4065 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02004066 * Return: true if we know that the client has moved from its old originator
Antonio Quartullic018ad32013-06-04 12:11:39 +02004067 * to another one. This entry is still kept for consistency purposes and will be
4068 * deleted later by a DEL or because of timeout
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01004069 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02004070bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004071 u8 *addr, unsigned short vid)
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01004072{
Sven Eckelmann56303d32012-06-05 22:31:31 +02004073 struct batadv_tt_global_entry *tt_global_entry;
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01004074 bool ret = false;
4075
Antonio Quartullic018ad32013-06-04 12:11:39 +02004076 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01004077 if (!tt_global_entry)
4078 goto out;
4079
Antonio Quartullic1d07432013-01-15 22:17:19 +10004080 ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01004081 batadv_tt_global_entry_put(tt_global_entry);
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01004082out:
4083 return ret;
4084}
Antonio Quartulli30cfd022012-07-05 23:38:29 +02004085
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02004086/**
4087 * batadv_tt_local_client_is_roaming - tells whether the client is roaming
4088 * @bat_priv: the bat priv with all the soft interface information
Antonio Quartullic018ad32013-06-04 12:11:39 +02004089 * @addr: the mac address of the local client to query
4090 * @vid: VLAN identifier
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02004091 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02004092 * Return: true if the local client is known to be roaming (it is not served by
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02004093 * this node anymore) or not. If yes, the client is still present in the table
4094 * to keep the latter consistent with the node TTVN
4095 */
4096bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004097 u8 *addr, unsigned short vid)
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02004098{
4099 struct batadv_tt_local_entry *tt_local_entry;
4100 bool ret = false;
4101
Antonio Quartullic018ad32013-06-04 12:11:39 +02004102 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02004103 if (!tt_local_entry)
4104 goto out;
4105
4106 ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
Sven Eckelmann95c0db92016-01-17 11:01:25 +01004107 batadv_tt_local_entry_put(tt_local_entry);
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02004108out:
4109 return ret;
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02004110}
4111
Antonio Quartulli30cfd022012-07-05 23:38:29 +02004112bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
4113 struct batadv_orig_node *orig_node,
Antonio Quartullic018ad32013-06-04 12:11:39 +02004114 const unsigned char *addr,
Antonio Quartulli16052782013-06-04 12:11:41 +02004115 unsigned short vid)
Antonio Quartulli30cfd022012-07-05 23:38:29 +02004116{
4117 bool ret = false;
4118
Antonio Quartulli16052782013-06-04 12:11:41 +02004119 if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid,
Antonio Quartulli30cfd022012-07-05 23:38:29 +02004120 BATADV_TT_CLIENT_TEMP,
4121 atomic_read(&orig_node->last_ttvn)))
4122 goto out;
4123
4124 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02004125 "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n",
4126 addr, BATADV_PRINT_VID(vid), orig_node->orig);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02004127 ret = true;
4128out:
4129 return ret;
4130}
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004131
4132/**
Marek Lindnera19d3d82013-05-27 15:33:25 +08004133 * batadv_tt_local_resize_to_mtu - resize the local translation table fit the
4134 * maximum packet size that can be transported through the mesh
4135 * @soft_iface: netdev struct of the mesh interface
4136 *
4137 * Remove entries older than 'timeout' and half timeout if more entries need
4138 * to be removed.
4139 */
4140void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
4141{
4142 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
4143 int packet_size_max = atomic_read(&bat_priv->packet_size_max);
4144 int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
4145 bool reduced = false;
4146
4147 spin_lock_bh(&bat_priv->tt.commit_lock);
4148
4149 while (true) {
4150 table_size = batadv_tt_local_table_transmit_size(bat_priv);
4151 if (packet_size_max >= table_size)
4152 break;
4153
4154 batadv_tt_local_purge(bat_priv, timeout);
4155 batadv_tt_local_purge_pending_clients(bat_priv);
4156
4157 timeout /= 2;
4158 reduced = true;
4159 net_ratelimited_function(batadv_info, soft_iface,
4160 "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
4161 packet_size_max);
4162 }
4163
4164 /* commit these changes immediately, to avoid synchronization problem
4165 * with the TTVN
4166 */
4167 if (reduced)
4168 batadv_tt_local_commit_changes_nolock(bat_priv);
4169
4170 spin_unlock_bh(&bat_priv->tt.commit_lock);
4171}
4172
4173/**
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004174 * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
4175 * @bat_priv: the bat priv with all the soft interface information
4176 * @orig: the orig_node of the ogm
4177 * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
4178 * @tvlv_value: tvlv buffer containing the gateway data
4179 * @tvlv_value_len: tvlv buffer length
4180 */
4181static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
4182 struct batadv_orig_node *orig,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004183 u8 flags, void *tvlv_value,
4184 u16 tvlv_value_len)
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004185{
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004186 struct batadv_tvlv_tt_vlan_data *tt_vlan;
4187 struct batadv_tvlv_tt_change *tt_change;
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004188 struct batadv_tvlv_tt_data *tt_data;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004189 u16 num_entries, num_vlan;
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004190
4191 if (tvlv_value_len < sizeof(*tt_data))
4192 return;
4193
4194 tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
4195 tvlv_value_len -= sizeof(*tt_data);
4196
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004197 num_vlan = ntohs(tt_data->num_vlan);
4198
4199 if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan)
4200 return;
4201
4202 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
4203 tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan);
4204 tvlv_value_len -= sizeof(*tt_vlan) * num_vlan;
4205
Antonio Quartulli298e6e62013-05-28 13:14:27 +02004206 num_entries = batadv_tt_entries(tvlv_value_len);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004207
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004208 batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change,
4209 num_entries, tt_data->ttvn);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004210}
4211
4212/**
Marek Lindner335fbe02013-04-23 21:40:02 +08004213 * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv
4214 * container
4215 * @bat_priv: the bat priv with all the soft interface information
4216 * @src: mac address of tt tvlv sender
4217 * @dst: mac address of tt tvlv recipient
4218 * @tvlv_value: tvlv buffer containing the tt data
4219 * @tvlv_value_len: tvlv buffer length
4220 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02004221 * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS
Marek Lindner335fbe02013-04-23 21:40:02 +08004222 * otherwise.
4223 */
4224static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004225 u8 *src, u8 *dst,
Marek Lindner335fbe02013-04-23 21:40:02 +08004226 void *tvlv_value,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004227 u16 tvlv_value_len)
Marek Lindner335fbe02013-04-23 21:40:02 +08004228{
4229 struct batadv_tvlv_tt_data *tt_data;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004230 u16 tt_vlan_len, tt_num_entries;
Marek Lindner335fbe02013-04-23 21:40:02 +08004231 char tt_flag;
4232 bool ret;
4233
4234 if (tvlv_value_len < sizeof(*tt_data))
4235 return NET_RX_SUCCESS;
4236
4237 tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
4238 tvlv_value_len -= sizeof(*tt_data);
4239
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004240 tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data);
4241 tt_vlan_len *= ntohs(tt_data->num_vlan);
4242
4243 if (tvlv_value_len < tt_vlan_len)
4244 return NET_RX_SUCCESS;
4245
4246 tvlv_value_len -= tt_vlan_len;
4247 tt_num_entries = batadv_tt_entries(tvlv_value_len);
Marek Lindner335fbe02013-04-23 21:40:02 +08004248
4249 switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
4250 case BATADV_TT_REQUEST:
4251 batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX);
4252
4253 /* If this node cannot provide a TT response the tt_request is
4254 * forwarded
4255 */
4256 ret = batadv_send_tt_response(bat_priv, tt_data, src, dst);
4257 if (!ret) {
4258 if (tt_data->flags & BATADV_TT_FULL_TABLE)
4259 tt_flag = 'F';
4260 else
4261 tt_flag = '.';
4262
4263 batadv_dbg(BATADV_DBG_TT, bat_priv,
4264 "Routing TT_REQUEST to %pM [%c]\n",
4265 dst, tt_flag);
4266 /* tvlv API will re-route the packet */
4267 return NET_RX_DROP;
4268 }
4269 break;
4270 case BATADV_TT_RESPONSE:
4271 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
4272
4273 if (batadv_is_my_mac(bat_priv, dst)) {
4274 batadv_handle_tt_response(bat_priv, tt_data,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02004275 src, tt_num_entries);
Marek Lindner335fbe02013-04-23 21:40:02 +08004276 return NET_RX_SUCCESS;
4277 }
4278
4279 if (tt_data->flags & BATADV_TT_FULL_TABLE)
4280 tt_flag = 'F';
4281 else
4282 tt_flag = '.';
4283
4284 batadv_dbg(BATADV_DBG_TT, bat_priv,
4285 "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag);
4286
4287 /* tvlv API will re-route the packet */
4288 return NET_RX_DROP;
4289 }
4290
4291 return NET_RX_SUCCESS;
4292}
4293
4294/**
Marek Lindner122edaa2013-04-23 21:40:03 +08004295 * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container
4296 * @bat_priv: the bat priv with all the soft interface information
4297 * @src: mac address of tt tvlv sender
4298 * @dst: mac address of tt tvlv recipient
4299 * @tvlv_value: tvlv buffer containing the tt data
4300 * @tvlv_value_len: tvlv buffer length
4301 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02004302 * Return: NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS
Marek Lindner122edaa2013-04-23 21:40:03 +08004303 * otherwise.
4304 */
4305static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004306 u8 *src, u8 *dst,
Marek Lindner122edaa2013-04-23 21:40:03 +08004307 void *tvlv_value,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004308 u16 tvlv_value_len)
Marek Lindner122edaa2013-04-23 21:40:03 +08004309{
4310 struct batadv_tvlv_roam_adv *roaming_adv;
4311 struct batadv_orig_node *orig_node = NULL;
4312
4313 /* If this node is not the intended recipient of the
4314 * roaming advertisement the packet is forwarded
4315 * (the tvlv API will re-route the packet).
4316 */
4317 if (!batadv_is_my_mac(bat_priv, dst))
4318 return NET_RX_DROP;
4319
Marek Lindner122edaa2013-04-23 21:40:03 +08004320 if (tvlv_value_len < sizeof(*roaming_adv))
4321 goto out;
4322
4323 orig_node = batadv_orig_hash_find(bat_priv, src);
4324 if (!orig_node)
4325 goto out;
4326
4327 batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
4328 roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value;
4329
4330 batadv_dbg(BATADV_DBG_TT, bat_priv,
4331 "Received ROAMING_ADV from %pM (client %pM)\n",
4332 src, roaming_adv->client);
4333
4334 batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client,
Antonio Quartullic018ad32013-06-04 12:11:39 +02004335 ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM,
Marek Lindner122edaa2013-04-23 21:40:03 +08004336 atomic_read(&orig_node->last_ttvn) + 1);
4337
4338out:
4339 if (orig_node)
Sven Eckelmann5d967312016-01-17 11:01:09 +01004340 batadv_orig_node_put(orig_node);
Marek Lindner122edaa2013-04-23 21:40:03 +08004341 return NET_RX_SUCCESS;
4342}
4343
4344/**
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004345 * batadv_tt_init - initialise the translation table internals
4346 * @bat_priv: the bat priv with all the soft interface information
4347 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02004348 * Return: 0 on success or negative error number in case of failure.
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004349 */
4350int batadv_tt_init(struct batadv_priv *bat_priv)
4351{
4352 int ret;
4353
Antonio Quartulli0eb015682013-10-13 02:50:20 +02004354 /* synchronized flags must be remote */
4355 BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK));
4356
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004357 ret = batadv_tt_local_init(bat_priv);
4358 if (ret < 0)
4359 return ret;
4360
4361 ret = batadv_tt_global_init(bat_priv);
4362 if (ret < 0)
4363 return ret;
4364
4365 batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1,
Marek Lindner335fbe02013-04-23 21:40:02 +08004366 batadv_tt_tvlv_unicast_handler_v1,
4367 BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004368
Marek Lindner122edaa2013-04-23 21:40:03 +08004369 batadv_tvlv_handler_register(bat_priv, NULL,
4370 batadv_roam_tvlv_unicast_handler_v1,
4371 BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS);
4372
Marek Lindnere1bf0c12013-04-23 21:40:01 +08004373 INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
4374 queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
4375 msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
4376
4377 return 1;
4378}
Antonio Quartulli42cb0be2013-11-16 12:03:52 +01004379
4380/**
4381 * batadv_tt_global_is_isolated - check if a client is marked as isolated
4382 * @bat_priv: the bat priv with all the soft interface information
4383 * @addr: the mac address of the client
4384 * @vid: the identifier of the VLAN where this client is connected
4385 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +02004386 * Return: true if the client is marked with the TT_CLIENT_ISOLA flag, false
Antonio Quartulli42cb0be2013-11-16 12:03:52 +01004387 * otherwise
4388 */
4389bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +02004390 const u8 *addr, unsigned short vid)
Antonio Quartulli42cb0be2013-11-16 12:03:52 +01004391{
4392 struct batadv_tt_global_entry *tt;
4393 bool ret;
4394
4395 tt = batadv_tt_global_hash_find(bat_priv, addr, vid);
4396 if (!tt)
4397 return false;
4398
4399 ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
4400
Sven Eckelmann5dafd8a2016-01-17 11:01:26 +01004401 batadv_tt_global_entry_put(tt);
Antonio Quartulli42cb0be2013-11-16 12:03:52 +01004402
4403 return ret;
4404}
Sven Eckelmann86452f82016-06-25 16:44:06 +02004405
4406/**
4407 * batadv_tt_cache_init - Initialize tt memory object cache
4408 *
4409 * Return: 0 on success or negative error number in case of failure.
4410 */
4411int __init batadv_tt_cache_init(void)
4412{
4413 size_t tl_size = sizeof(struct batadv_tt_local_entry);
4414 size_t tg_size = sizeof(struct batadv_tt_global_entry);
4415 size_t tt_orig_size = sizeof(struct batadv_tt_orig_list_entry);
4416 size_t tt_change_size = sizeof(struct batadv_tt_change_node);
4417 size_t tt_req_size = sizeof(struct batadv_tt_req_node);
4418 size_t tt_roam_size = sizeof(struct batadv_tt_roam_node);
4419
4420 batadv_tl_cache = kmem_cache_create("batadv_tl_cache", tl_size, 0,
4421 SLAB_HWCACHE_ALIGN, NULL);
4422 if (!batadv_tl_cache)
4423 return -ENOMEM;
4424
4425 batadv_tg_cache = kmem_cache_create("batadv_tg_cache", tg_size, 0,
4426 SLAB_HWCACHE_ALIGN, NULL);
4427 if (!batadv_tg_cache)
4428 goto err_tt_tl_destroy;
4429
4430 batadv_tt_orig_cache = kmem_cache_create("batadv_tt_orig_cache",
4431 tt_orig_size, 0,
4432 SLAB_HWCACHE_ALIGN, NULL);
4433 if (!batadv_tt_orig_cache)
4434 goto err_tt_tg_destroy;
4435
4436 batadv_tt_change_cache = kmem_cache_create("batadv_tt_change_cache",
4437 tt_change_size, 0,
4438 SLAB_HWCACHE_ALIGN, NULL);
4439 if (!batadv_tt_change_cache)
4440 goto err_tt_orig_destroy;
4441
4442 batadv_tt_req_cache = kmem_cache_create("batadv_tt_req_cache",
4443 tt_req_size, 0,
4444 SLAB_HWCACHE_ALIGN, NULL);
4445 if (!batadv_tt_req_cache)
4446 goto err_tt_change_destroy;
4447
4448 batadv_tt_roam_cache = kmem_cache_create("batadv_tt_roam_cache",
4449 tt_roam_size, 0,
4450 SLAB_HWCACHE_ALIGN, NULL);
4451 if (!batadv_tt_roam_cache)
4452 goto err_tt_req_destroy;
4453
4454 return 0;
4455
4456err_tt_req_destroy:
4457 kmem_cache_destroy(batadv_tt_req_cache);
4458 batadv_tt_req_cache = NULL;
4459err_tt_change_destroy:
4460 kmem_cache_destroy(batadv_tt_change_cache);
4461 batadv_tt_change_cache = NULL;
4462err_tt_orig_destroy:
4463 kmem_cache_destroy(batadv_tt_orig_cache);
4464 batadv_tt_orig_cache = NULL;
4465err_tt_tg_destroy:
4466 kmem_cache_destroy(batadv_tg_cache);
4467 batadv_tg_cache = NULL;
4468err_tt_tl_destroy:
4469 kmem_cache_destroy(batadv_tl_cache);
4470 batadv_tl_cache = NULL;
4471
4472 return -ENOMEM;
4473}
4474
4475/**
4476 * batadv_tt_cache_destroy - Destroy tt memory object cache
4477 */
4478void batadv_tt_cache_destroy(void)
4479{
4480 kmem_cache_destroy(batadv_tl_cache);
4481 kmem_cache_destroy(batadv_tg_cache);
4482 kmem_cache_destroy(batadv_tt_orig_cache);
4483 kmem_cache_destroy(batadv_tt_change_cache);
4484 kmem_cache_destroy(batadv_tt_req_cache);
4485 kmem_cache_destroy(batadv_tt_roam_cache);
4486}