batman-adv: Prefix main local static functions with batadv_
[linux-2.6-block.git] / net / batman-adv / translation-table.c
CommitLineData
9cfc7bd6 1/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
c6c8fea2 2 *
35c133a0 3 * Marek Lindner, Simon Wunderlich, Antonio Quartulli
c6c8fea2
SE
4 *
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
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA
c6c8fea2
SE
18 */
19
20#include "main.h"
21#include "translation-table.h"
22#include "soft-interface.h"
32ae9b22 23#include "hard-interface.h"
a73105b8 24#include "send.h"
c6c8fea2
SE
25#include "hash.h"
26#include "originator.h"
a73105b8 27#include "routing.h"
20ff9d59 28#include "bridge_loop_avoidance.h"
c6c8fea2 29
a73105b8
AQ
30#include <linux/crc16.h>
31
a513088d
SE
32static void batadv_send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
33 struct orig_node *orig_node);
34static void batadv_tt_purge(struct work_struct *work);
35static void
36batadv_tt_global_del_orig_list(struct tt_global_entry *tt_global_entry);
c6c8fea2 37
7aadf889 38/* returns 1 if they are the same mac addr */
a513088d 39static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
7aadf889 40{
48100bac 41 const void *data1 = container_of(node, struct tt_common_entry,
747e4221 42 hash_entry);
7aadf889
ML
43
44 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
45}
46
a513088d 47static void batadv_tt_start_timer(struct bat_priv *bat_priv)
c6c8fea2 48{
a513088d 49 INIT_DELAYED_WORK(&bat_priv->tt_work, batadv_tt_purge);
3193e8fd 50 queue_delayed_work(batadv_event_workqueue, &bat_priv->tt_work,
a73105b8 51 msecs_to_jiffies(5000));
c6c8fea2
SE
52}
53
a513088d
SE
54static struct tt_common_entry *batadv_tt_hash_find(struct hashtable_t *hash,
55 const void *data)
7aadf889 56{
7aadf889
ML
57 struct hlist_head *head;
58 struct hlist_node *node;
48100bac 59 struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL;
c90681b8 60 uint32_t index;
7aadf889
ML
61
62 if (!hash)
63 return NULL;
64
da641193 65 index = batadv_choose_orig(data, hash->size);
7aadf889
ML
66 head = &hash->table[index];
67
68 rcu_read_lock();
48100bac 69 hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) {
1eda58bf 70 if (!batadv_compare_eth(tt_common_entry, data))
7aadf889
ML
71 continue;
72
48100bac 73 if (!atomic_inc_not_zero(&tt_common_entry->refcount))
7683fdc1
AQ
74 continue;
75
48100bac 76 tt_common_entry_tmp = tt_common_entry;
7aadf889
ML
77 break;
78 }
79 rcu_read_unlock();
80
48100bac 81 return tt_common_entry_tmp;
7aadf889
ML
82}
83
a513088d
SE
84static struct tt_local_entry *
85batadv_tt_local_hash_find(struct bat_priv *bat_priv, const void *data)
7aadf889 86{
48100bac
AQ
87 struct tt_common_entry *tt_common_entry;
88 struct tt_local_entry *tt_local_entry = NULL;
7aadf889 89
a513088d 90 tt_common_entry = batadv_tt_hash_find(bat_priv->tt_local_hash, data);
48100bac
AQ
91 if (tt_common_entry)
92 tt_local_entry = container_of(tt_common_entry,
93 struct tt_local_entry, common);
94 return tt_local_entry;
95}
7aadf889 96
a513088d
SE
97static struct tt_global_entry *
98batadv_tt_global_hash_find(struct bat_priv *bat_priv, const void *data)
48100bac
AQ
99{
100 struct tt_common_entry *tt_common_entry;
101 struct tt_global_entry *tt_global_entry = NULL;
7683fdc1 102
a513088d 103 tt_common_entry = batadv_tt_hash_find(bat_priv->tt_global_hash, data);
48100bac
AQ
104 if (tt_common_entry)
105 tt_global_entry = container_of(tt_common_entry,
106 struct tt_global_entry, common);
107 return tt_global_entry;
7aadf889 108
7aadf889
ML
109}
110
a513088d
SE
111static void
112batadv_tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
7683fdc1 113{
48100bac
AQ
114 if (atomic_dec_and_test(&tt_local_entry->common.refcount))
115 kfree_rcu(tt_local_entry, common.rcu);
7683fdc1
AQ
116}
117
a513088d 118static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu)
531027fc 119{
48100bac 120 struct tt_common_entry *tt_common_entry;
531027fc
SW
121 struct tt_global_entry *tt_global_entry;
122
48100bac
AQ
123 tt_common_entry = container_of(rcu, struct tt_common_entry, rcu);
124 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
125 common);
531027fc 126
531027fc
SW
127 kfree(tt_global_entry);
128}
129
a513088d
SE
130static void
131batadv_tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
7683fdc1 132{
db08e6e5 133 if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
a513088d 134 batadv_tt_global_del_orig_list(tt_global_entry);
48100bac 135 call_rcu(&tt_global_entry->common.rcu,
a513088d 136 batadv_tt_global_entry_free_rcu);
db08e6e5
SW
137 }
138}
139
a513088d 140static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
db08e6e5
SW
141{
142 struct tt_orig_list_entry *orig_entry;
143
144 orig_entry = container_of(rcu, struct tt_orig_list_entry, rcu);
7d211efc 145 batadv_orig_node_free_ref(orig_entry->orig_node);
db08e6e5
SW
146 kfree(orig_entry);
147}
148
a513088d
SE
149static void
150batadv_tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry)
db08e6e5 151{
29cb99de
AQ
152 /* to avoid race conditions, immediately decrease the tt counter */
153 atomic_dec(&orig_entry->orig_node->tt_size);
a513088d 154 call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
7683fdc1
AQ
155}
156
a513088d
SE
157static void batadv_tt_local_event(struct bat_priv *bat_priv,
158 const uint8_t *addr, uint8_t flags)
a73105b8
AQ
159{
160 struct tt_change_node *tt_change_node;
161
162 tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
163
164 if (!tt_change_node)
165 return;
166
ff66c975 167 tt_change_node->change.flags = flags;
a73105b8
AQ
168 memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
169
170 spin_lock_bh(&bat_priv->tt_changes_list_lock);
171 /* track the change in the OGMinterval list */
172 list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
173 atomic_inc(&bat_priv->tt_local_changes);
174 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
175
176 atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
177}
178
08c36d3e 179int batadv_tt_len(int changes_num)
a73105b8
AQ
180{
181 return changes_num * sizeof(struct tt_change);
182}
183
a513088d 184static int batadv_tt_local_init(struct bat_priv *bat_priv)
c6c8fea2 185{
2dafb49d 186 if (bat_priv->tt_local_hash)
5346c35e 187 return 0;
c6c8fea2 188
1a8eaf07 189 bat_priv->tt_local_hash = batadv_hash_new(1024);
c6c8fea2 190
2dafb49d 191 if (!bat_priv->tt_local_hash)
5346c35e 192 return -ENOMEM;
c6c8fea2 193
5346c35e 194 return 0;
c6c8fea2
SE
195}
196
08c36d3e
SE
197void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
198 int ifindex)
c6c8fea2
SE
199{
200 struct bat_priv *bat_priv = netdev_priv(soft_iface);
7683fdc1
AQ
201 struct tt_local_entry *tt_local_entry = NULL;
202 struct tt_global_entry *tt_global_entry = NULL;
db08e6e5
SW
203 struct hlist_head *head;
204 struct hlist_node *node;
205 struct tt_orig_list_entry *orig_entry;
80b3f58c 206 int hash_added;
c6c8fea2 207
a513088d 208 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
c6c8fea2 209
2dafb49d
AQ
210 if (tt_local_entry) {
211 tt_local_entry->last_seen = jiffies;
521251f2
AQ
212 /* possibly unset the TT_CLIENT_PENDING flag */
213 tt_local_entry->common.flags &= ~TT_CLIENT_PENDING;
7683fdc1 214 goto out;
c6c8fea2
SE
215 }
216
704509b8 217 tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
2dafb49d 218 if (!tt_local_entry)
7683fdc1 219 goto out;
a73105b8 220
1eda58bf
SE
221 batadv_dbg(DBG_TT, bat_priv,
222 "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
223 (uint8_t)atomic_read(&bat_priv->ttvn));
c6c8fea2 224
48100bac
AQ
225 memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
226 tt_local_entry->common.flags = NO_FLAGS;
9563877e 227 if (batadv_is_wifi_iface(ifindex))
48100bac
AQ
228 tt_local_entry->common.flags |= TT_CLIENT_WIFI;
229 atomic_set(&tt_local_entry->common.refcount, 2);
230 tt_local_entry->last_seen = jiffies;
c6c8fea2
SE
231
232 /* the batman interface mac address should never be purged */
1eda58bf 233 if (batadv_compare_eth(addr, soft_iface->dev_addr))
48100bac 234 tt_local_entry->common.flags |= TT_CLIENT_NOPURGE;
c6c8fea2 235
c40ed2bf
AQ
236 /* The local entry has to be marked as NEW to avoid to send it in
237 * a full table response going out before the next ttvn increment
9cfc7bd6
SE
238 * (consistency check)
239 */
c40ed2bf
AQ
240 tt_local_entry->common.flags |= TT_CLIENT_NEW;
241
a513088d 242 hash_added = batadv_hash_add(bat_priv->tt_local_hash, batadv_compare_tt,
da641193
SE
243 batadv_choose_orig,
244 &tt_local_entry->common,
c0a55929 245 &tt_local_entry->common.hash_entry);
80b3f58c
SW
246
247 if (unlikely(hash_added != 0)) {
248 /* remove the reference for the hash */
a513088d 249 batadv_tt_local_entry_free_ref(tt_local_entry);
80b3f58c
SW
250 goto out;
251 }
252
a513088d 253 batadv_tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
ff66c975 254
c6c8fea2 255 /* remove address from global hash if present */
a513088d 256 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
c6c8fea2 257
cc47f66e
AQ
258 /* Check whether it is a roaming! */
259 if (tt_global_entry) {
db08e6e5
SW
260 /* These node are probably going to update their tt table */
261 head = &tt_global_entry->orig_list;
262 rcu_read_lock();
263 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
264 orig_entry->orig_node->tt_poss_change = true;
265
a513088d
SE
266 batadv_send_roam_adv(bat_priv,
267 tt_global_entry->common.addr,
268 orig_entry->orig_node);
db08e6e5
SW
269 }
270 rcu_read_unlock();
271 /* The global entry has to be marked as ROAMING and
272 * has to be kept for consistency purpose
273 */
220b07e9 274 tt_global_entry->common.flags |= TT_CLIENT_ROAM;
03fc3070 275 tt_global_entry->roam_at = jiffies;
7683fdc1
AQ
276 }
277out:
278 if (tt_local_entry)
a513088d 279 batadv_tt_local_entry_free_ref(tt_local_entry);
7683fdc1 280 if (tt_global_entry)
a513088d 281 batadv_tt_global_entry_free_ref(tt_global_entry);
c6c8fea2
SE
282}
283
a513088d
SE
284static void batadv_tt_realloc_packet_buff(unsigned char **packet_buff,
285 int *packet_buff_len,
286 int min_packet_len,
287 int new_packet_len)
be9aa4c1
ML
288{
289 unsigned char *new_buff;
290
291 new_buff = kmalloc(new_packet_len, GFP_ATOMIC);
292
293 /* keep old buffer if kmalloc should fail */
294 if (new_buff) {
295 memcpy(new_buff, *packet_buff, min_packet_len);
296 kfree(*packet_buff);
297 *packet_buff = new_buff;
298 *packet_buff_len = new_packet_len;
299 }
300}
301
a513088d
SE
302static void batadv_tt_prepare_packet_buff(struct bat_priv *bat_priv,
303 unsigned char **packet_buff,
304 int *packet_buff_len,
305 int min_packet_len)
be9aa4c1
ML
306{
307 struct hard_iface *primary_if;
308 int req_len;
309
e5d89254 310 primary_if = batadv_primary_if_get_selected(bat_priv);
be9aa4c1
ML
311
312 req_len = min_packet_len;
08c36d3e 313 req_len += batadv_tt_len(atomic_read(&bat_priv->tt_local_changes));
be9aa4c1
ML
314
315 /* if we have too many changes for one packet don't send any
316 * and wait for the tt table request which will be fragmented
317 */
318 if ((!primary_if) || (req_len > primary_if->soft_iface->mtu))
319 req_len = min_packet_len;
320
a513088d
SE
321 batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len,
322 min_packet_len, req_len);
be9aa4c1
ML
323
324 if (primary_if)
e5d89254 325 batadv_hardif_free_ref(primary_if);
be9aa4c1
ML
326}
327
a513088d
SE
328static int batadv_tt_changes_fill_buff(struct bat_priv *bat_priv,
329 unsigned char **packet_buff,
330 int *packet_buff_len,
331 int min_packet_len)
c6c8fea2 332{
a73105b8 333 struct tt_change_node *entry, *safe;
be9aa4c1
ML
334 int count = 0, tot_changes = 0, new_len;
335 unsigned char *tt_buff;
336
a513088d
SE
337 batadv_tt_prepare_packet_buff(bat_priv, packet_buff,
338 packet_buff_len, min_packet_len);
c6c8fea2 339
be9aa4c1
ML
340 new_len = *packet_buff_len - min_packet_len;
341 tt_buff = *packet_buff + min_packet_len;
342
343 if (new_len > 0)
08c36d3e 344 tot_changes = new_len / batadv_tt_len(1);
c6c8fea2 345
a73105b8
AQ
346 spin_lock_bh(&bat_priv->tt_changes_list_lock);
347 atomic_set(&bat_priv->tt_local_changes, 0);
c6c8fea2 348
a73105b8 349 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
7c64fd98 350 list) {
a73105b8 351 if (count < tot_changes) {
08c36d3e 352 memcpy(tt_buff + batadv_tt_len(count),
a73105b8 353 &entry->change, sizeof(struct tt_change));
c6c8fea2
SE
354 count++;
355 }
a73105b8
AQ
356 list_del(&entry->list);
357 kfree(entry);
c6c8fea2 358 }
a73105b8
AQ
359 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
360
361 /* Keep the buffer for possible tt_request */
362 spin_lock_bh(&bat_priv->tt_buff_lock);
363 kfree(bat_priv->tt_buff);
364 bat_priv->tt_buff_len = 0;
365 bat_priv->tt_buff = NULL;
be9aa4c1
ML
366 /* check whether this new OGM has no changes due to size problems */
367 if (new_len > 0) {
368 /* if kmalloc() fails we will reply with the full table
a73105b8
AQ
369 * instead of providing the diff
370 */
be9aa4c1 371 bat_priv->tt_buff = kmalloc(new_len, GFP_ATOMIC);
a73105b8 372 if (bat_priv->tt_buff) {
be9aa4c1
ML
373 memcpy(bat_priv->tt_buff, tt_buff, new_len);
374 bat_priv->tt_buff_len = new_len;
a73105b8
AQ
375 }
376 }
377 spin_unlock_bh(&bat_priv->tt_buff_lock);
c6c8fea2 378
08ad76ec 379 return count;
c6c8fea2
SE
380}
381
08c36d3e 382int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea2
SE
383{
384 struct net_device *net_dev = (struct net_device *)seq->private;
385 struct bat_priv *bat_priv = netdev_priv(net_dev);
2dafb49d 386 struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac 387 struct tt_common_entry *tt_common_entry;
32ae9b22 388 struct hard_iface *primary_if;
7aadf889 389 struct hlist_node *node;
c6c8fea2 390 struct hlist_head *head;
c90681b8
AQ
391 uint32_t i;
392 int ret = 0;
32ae9b22 393
e5d89254 394 primary_if = batadv_primary_if_get_selected(bat_priv);
32ae9b22 395 if (!primary_if) {
86ceb360
SE
396 ret = seq_printf(seq,
397 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
32ae9b22
ML
398 net_dev->name);
399 goto out;
400 }
c6c8fea2 401
32ae9b22 402 if (primary_if->if_status != IF_ACTIVE) {
86ceb360
SE
403 ret = seq_printf(seq,
404 "BATMAN mesh %s disabled - primary interface not active\n",
32ae9b22
ML
405 net_dev->name);
406 goto out;
c6c8fea2
SE
407 }
408
86ceb360
SE
409 seq_printf(seq,
410 "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
a73105b8 411 net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
c6c8fea2 412
c6c8fea2
SE
413 for (i = 0; i < hash->size; i++) {
414 head = &hash->table[i];
415
7aadf889 416 rcu_read_lock();
48100bac 417 hlist_for_each_entry_rcu(tt_common_entry, node,
7aadf889 418 head, hash_entry) {
d099c2c5 419 seq_printf(seq, " * %pM [%c%c%c%c%c]\n",
7c64fd98
SE
420 tt_common_entry->addr,
421 (tt_common_entry->flags &
422 TT_CLIENT_ROAM ? 'R' : '.'),
423 (tt_common_entry->flags &
424 TT_CLIENT_NOPURGE ? 'P' : '.'),
425 (tt_common_entry->flags &
426 TT_CLIENT_NEW ? 'N' : '.'),
427 (tt_common_entry->flags &
428 TT_CLIENT_PENDING ? 'X' : '.'),
429 (tt_common_entry->flags &
430 TT_CLIENT_WIFI ? 'W' : '.'));
c6c8fea2 431 }
7aadf889 432 rcu_read_unlock();
c6c8fea2 433 }
32ae9b22
ML
434out:
435 if (primary_if)
e5d89254 436 batadv_hardif_free_ref(primary_if);
32ae9b22 437 return ret;
c6c8fea2
SE
438}
439
a513088d
SE
440static void batadv_tt_local_set_pending(struct bat_priv *bat_priv,
441 struct tt_local_entry *tt_local_entry,
442 uint16_t flags, const char *message)
c6c8fea2 443{
a513088d
SE
444 batadv_tt_local_event(bat_priv, tt_local_entry->common.addr,
445 tt_local_entry->common.flags | flags);
a73105b8 446
015758d0
AQ
447 /* The local client has to be marked as "pending to be removed" but has
448 * to be kept in the table in order to send it in a full table
9cfc7bd6
SE
449 * response issued before the net ttvn increment (consistency check)
450 */
48100bac 451 tt_local_entry->common.flags |= TT_CLIENT_PENDING;
c566dbbe 452
1eda58bf
SE
453 batadv_dbg(DBG_TT, bat_priv,
454 "Local tt entry (%pM) pending to be removed: %s\n",
455 tt_local_entry->common.addr, message);
c6c8fea2
SE
456}
457
08c36d3e
SE
458void batadv_tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
459 const char *message, bool roaming)
c6c8fea2 460{
7683fdc1 461 struct tt_local_entry *tt_local_entry = NULL;
c6c8fea2 462
a513088d 463 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
7683fdc1
AQ
464 if (!tt_local_entry)
465 goto out;
466
a513088d
SE
467 batadv_tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
468 (roaming ? TT_CLIENT_ROAM : NO_FLAGS),
469 message);
7683fdc1
AQ
470out:
471 if (tt_local_entry)
a513088d 472 batadv_tt_local_entry_free_ref(tt_local_entry);
c6c8fea2
SE
473}
474
a513088d 475static void batadv_tt_local_purge(struct bat_priv *bat_priv)
c6c8fea2 476{
2dafb49d
AQ
477 struct hashtable_t *hash = bat_priv->tt_local_hash;
478 struct tt_local_entry *tt_local_entry;
48100bac 479 struct tt_common_entry *tt_common_entry;
7aadf889 480 struct hlist_node *node, *node_tmp;
c6c8fea2 481 struct hlist_head *head;
7683fdc1 482 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 483 uint32_t i;
c6c8fea2 484
c6c8fea2
SE
485 for (i = 0; i < hash->size; i++) {
486 head = &hash->table[i];
7683fdc1 487 list_lock = &hash->list_locks[i];
c6c8fea2 488
7683fdc1 489 spin_lock_bh(list_lock);
48100bac 490 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
7aadf889 491 head, hash_entry) {
48100bac
AQ
492 tt_local_entry = container_of(tt_common_entry,
493 struct tt_local_entry,
494 common);
495 if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE)
7aadf889 496 continue;
c6c8fea2 497
058d0e26 498 /* entry already marked for deletion */
48100bac 499 if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
058d0e26
AQ
500 continue;
501
1eda58bf
SE
502 if (!batadv_has_timed_out(tt_local_entry->last_seen,
503 TT_LOCAL_TIMEOUT))
7aadf889
ML
504 continue;
505
a513088d
SE
506 batadv_tt_local_set_pending(bat_priv, tt_local_entry,
507 TT_CLIENT_DEL, "timed out");
c6c8fea2 508 }
7683fdc1 509 spin_unlock_bh(list_lock);
c6c8fea2
SE
510 }
511
c6c8fea2
SE
512}
513
a513088d 514static void batadv_tt_local_table_free(struct bat_priv *bat_priv)
c6c8fea2 515{
a73105b8 516 struct hashtable_t *hash;
a73105b8 517 spinlock_t *list_lock; /* protects write access to the hash lists */
48100bac 518 struct tt_common_entry *tt_common_entry;
a73105b8 519 struct tt_local_entry *tt_local_entry;
7683fdc1
AQ
520 struct hlist_node *node, *node_tmp;
521 struct hlist_head *head;
c90681b8 522 uint32_t i;
a73105b8 523
2dafb49d 524 if (!bat_priv->tt_local_hash)
c6c8fea2
SE
525 return;
526
a73105b8
AQ
527 hash = bat_priv->tt_local_hash;
528
529 for (i = 0; i < hash->size; i++) {
530 head = &hash->table[i];
531 list_lock = &hash->list_locks[i];
532
533 spin_lock_bh(list_lock);
48100bac 534 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
a73105b8
AQ
535 head, hash_entry) {
536 hlist_del_rcu(node);
48100bac
AQ
537 tt_local_entry = container_of(tt_common_entry,
538 struct tt_local_entry,
539 common);
a513088d 540 batadv_tt_local_entry_free_ref(tt_local_entry);
a73105b8
AQ
541 }
542 spin_unlock_bh(list_lock);
543 }
544
1a8eaf07 545 batadv_hash_destroy(hash);
a73105b8 546
2dafb49d 547 bat_priv->tt_local_hash = NULL;
c6c8fea2
SE
548}
549
a513088d 550static int batadv_tt_global_init(struct bat_priv *bat_priv)
c6c8fea2 551{
2dafb49d 552 if (bat_priv->tt_global_hash)
5346c35e 553 return 0;
c6c8fea2 554
1a8eaf07 555 bat_priv->tt_global_hash = batadv_hash_new(1024);
c6c8fea2 556
2dafb49d 557 if (!bat_priv->tt_global_hash)
5346c35e 558 return -ENOMEM;
c6c8fea2 559
5346c35e 560 return 0;
c6c8fea2
SE
561}
562
a513088d 563static void batadv_tt_changes_list_free(struct bat_priv *bat_priv)
c6c8fea2 564{
a73105b8 565 struct tt_change_node *entry, *safe;
c6c8fea2 566
a73105b8 567 spin_lock_bh(&bat_priv->tt_changes_list_lock);
c6c8fea2 568
a73105b8
AQ
569 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
570 list) {
571 list_del(&entry->list);
572 kfree(entry);
573 }
c6c8fea2 574
a73105b8
AQ
575 atomic_set(&bat_priv->tt_local_changes, 0);
576 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
577}
c6c8fea2 578
db08e6e5
SW
579/* find out if an orig_node is already in the list of a tt_global_entry.
580 * returns 1 if found, 0 otherwise
581 */
a513088d
SE
582static bool batadv_tt_global_entry_has_orig(const struct tt_global_entry *entry,
583 const struct orig_node *orig_node)
db08e6e5
SW
584{
585 struct tt_orig_list_entry *tmp_orig_entry;
586 const struct hlist_head *head;
587 struct hlist_node *node;
588 bool found = false;
589
590 rcu_read_lock();
591 head = &entry->orig_list;
592 hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) {
593 if (tmp_orig_entry->orig_node == orig_node) {
594 found = true;
595 break;
596 }
597 }
598 rcu_read_unlock();
599 return found;
600}
601
a513088d
SE
602static void
603batadv_tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry,
604 struct orig_node *orig_node, int ttvn)
db08e6e5
SW
605{
606 struct tt_orig_list_entry *orig_entry;
607
608 orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
609 if (!orig_entry)
610 return;
611
612 INIT_HLIST_NODE(&orig_entry->list);
613 atomic_inc(&orig_node->refcount);
614 atomic_inc(&orig_node->tt_size);
615 orig_entry->orig_node = orig_node;
616 orig_entry->ttvn = ttvn;
617
618 spin_lock_bh(&tt_global_entry->list_lock);
619 hlist_add_head_rcu(&orig_entry->list,
620 &tt_global_entry->orig_list);
621 spin_unlock_bh(&tt_global_entry->list_lock);
622}
623
a73105b8 624/* caller must hold orig_node refcount */
08c36d3e
SE
625int batadv_tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
626 const unsigned char *tt_addr, uint8_t ttvn,
627 bool roaming, bool wifi)
a73105b8 628{
db08e6e5 629 struct tt_global_entry *tt_global_entry = NULL;
7683fdc1 630 int ret = 0;
80b3f58c 631 int hash_added;
c0a55929 632 struct tt_common_entry *common;
c6c8fea2 633
a513088d 634 tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr);
a73105b8
AQ
635
636 if (!tt_global_entry) {
db08e6e5
SW
637 tt_global_entry = kzalloc(sizeof(*tt_global_entry),
638 GFP_ATOMIC);
a73105b8 639 if (!tt_global_entry)
7683fdc1
AQ
640 goto out;
641
c0a55929
SE
642 common = &tt_global_entry->common;
643 memcpy(common->addr, tt_addr, ETH_ALEN);
db08e6e5 644
c0a55929 645 common->flags = NO_FLAGS;
cc47f66e 646 tt_global_entry->roam_at = 0;
c0a55929 647 atomic_set(&common->refcount, 2);
db08e6e5
SW
648
649 INIT_HLIST_HEAD(&tt_global_entry->orig_list);
650 spin_lock_init(&tt_global_entry->list_lock);
7683fdc1 651
c0a55929 652 hash_added = batadv_hash_add(bat_priv->tt_global_hash,
a513088d
SE
653 batadv_compare_tt,
654 batadv_choose_orig, common,
655 &common->hash_entry);
80b3f58c
SW
656
657 if (unlikely(hash_added != 0)) {
658 /* remove the reference for the hash */
a513088d 659 batadv_tt_global_entry_free_ref(tt_global_entry);
80b3f58c
SW
660 goto out_remove;
661 }
db08e6e5 662
a513088d
SE
663 batadv_tt_global_add_orig_entry(tt_global_entry, orig_node,
664 ttvn);
a73105b8 665 } else {
db08e6e5
SW
666 /* there is already a global entry, use this one. */
667
668 /* If there is the TT_CLIENT_ROAM flag set, there is only one
669 * originator left in the list and we previously received a
670 * delete + roaming change for this originator.
671 *
672 * We should first delete the old originator before adding the
673 * new one.
674 */
675 if (tt_global_entry->common.flags & TT_CLIENT_ROAM) {
a513088d 676 batadv_tt_global_del_orig_list(tt_global_entry);
db08e6e5
SW
677 tt_global_entry->common.flags &= ~TT_CLIENT_ROAM;
678 tt_global_entry->roam_at = 0;
a73105b8 679 }
db08e6e5 680
a513088d
SE
681 if (!batadv_tt_global_entry_has_orig(tt_global_entry,
682 orig_node))
683 batadv_tt_global_add_orig_entry(tt_global_entry,
684 orig_node, ttvn);
a73105b8 685 }
c6c8fea2 686
bc279080 687 if (wifi)
48100bac 688 tt_global_entry->common.flags |= TT_CLIENT_WIFI;
bc279080 689
1eda58bf
SE
690 batadv_dbg(DBG_TT, bat_priv,
691 "Creating new global tt entry: %pM (via %pM)\n",
692 tt_global_entry->common.addr, orig_node->orig);
c6c8fea2 693
80b3f58c 694out_remove:
a73105b8 695 /* remove address from local hash if present */
08c36d3e
SE
696 batadv_tt_local_remove(bat_priv, tt_global_entry->common.addr,
697 "global tt received", roaming);
7683fdc1
AQ
698 ret = 1;
699out:
700 if (tt_global_entry)
a513088d 701 batadv_tt_global_entry_free_ref(tt_global_entry);
7683fdc1 702 return ret;
c6c8fea2
SE
703}
704
db08e6e5
SW
705/* print all orig nodes who announce the address for this global entry.
706 * it is assumed that the caller holds rcu_read_lock();
707 */
a513088d
SE
708static void
709batadv_tt_global_print_entry(struct tt_global_entry *tt_global_entry,
710 struct seq_file *seq)
db08e6e5
SW
711{
712 struct hlist_head *head;
713 struct hlist_node *node;
714 struct tt_orig_list_entry *orig_entry;
715 struct tt_common_entry *tt_common_entry;
716 uint16_t flags;
717 uint8_t last_ttvn;
718
719 tt_common_entry = &tt_global_entry->common;
720
721 head = &tt_global_entry->orig_list;
722
723 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
724 flags = tt_common_entry->flags;
725 last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
726 seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n",
727 tt_global_entry->common.addr, orig_entry->ttvn,
728 orig_entry->orig_node->orig, last_ttvn,
729 (flags & TT_CLIENT_ROAM ? 'R' : '.'),
730 (flags & TT_CLIENT_WIFI ? 'W' : '.'));
731 }
732}
733
08c36d3e 734int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea2
SE
735{
736 struct net_device *net_dev = (struct net_device *)seq->private;
737 struct bat_priv *bat_priv = netdev_priv(net_dev);
2dafb49d 738 struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac 739 struct tt_common_entry *tt_common_entry;
2dafb49d 740 struct tt_global_entry *tt_global_entry;
32ae9b22 741 struct hard_iface *primary_if;
7aadf889 742 struct hlist_node *node;
c6c8fea2 743 struct hlist_head *head;
c90681b8
AQ
744 uint32_t i;
745 int ret = 0;
32ae9b22 746
e5d89254 747 primary_if = batadv_primary_if_get_selected(bat_priv);
32ae9b22 748 if (!primary_if) {
86ceb360
SE
749 ret = seq_printf(seq,
750 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
32ae9b22
ML
751 net_dev->name);
752 goto out;
753 }
c6c8fea2 754
32ae9b22 755 if (primary_if->if_status != IF_ACTIVE) {
86ceb360
SE
756 ret = seq_printf(seq,
757 "BATMAN mesh %s disabled - primary interface not active\n",
32ae9b22
ML
758 net_dev->name);
759 goto out;
c6c8fea2
SE
760 }
761
2dafb49d
AQ
762 seq_printf(seq,
763 "Globally announced TT entries received via the mesh %s\n",
c6c8fea2 764 net_dev->name);
df6edb9e
AQ
765 seq_printf(seq, " %-13s %s %-15s %s %s\n",
766 "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
c6c8fea2 767
c6c8fea2
SE
768 for (i = 0; i < hash->size; i++) {
769 head = &hash->table[i];
770
7aadf889 771 rcu_read_lock();
48100bac 772 hlist_for_each_entry_rcu(tt_common_entry, node,
7aadf889 773 head, hash_entry) {
48100bac
AQ
774 tt_global_entry = container_of(tt_common_entry,
775 struct tt_global_entry,
776 common);
a513088d 777 batadv_tt_global_print_entry(tt_global_entry, seq);
c6c8fea2 778 }
7aadf889 779 rcu_read_unlock();
c6c8fea2 780 }
32ae9b22
ML
781out:
782 if (primary_if)
e5d89254 783 batadv_hardif_free_ref(primary_if);
32ae9b22 784 return ret;
c6c8fea2
SE
785}
786
db08e6e5 787/* deletes the orig list of a tt_global_entry */
a513088d
SE
788static void
789batadv_tt_global_del_orig_list(struct tt_global_entry *tt_global_entry)
c6c8fea2 790{
db08e6e5
SW
791 struct hlist_head *head;
792 struct hlist_node *node, *safe;
793 struct tt_orig_list_entry *orig_entry;
a73105b8 794
db08e6e5
SW
795 spin_lock_bh(&tt_global_entry->list_lock);
796 head = &tt_global_entry->orig_list;
797 hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
798 hlist_del_rcu(node);
a513088d 799 batadv_tt_orig_list_entry_free_ref(orig_entry);
db08e6e5
SW
800 }
801 spin_unlock_bh(&tt_global_entry->list_lock);
c6c8fea2 802
db08e6e5
SW
803}
804
a513088d
SE
805static void
806batadv_tt_global_del_orig_entry(struct bat_priv *bat_priv,
807 struct tt_global_entry *tt_global_entry,
808 struct orig_node *orig_node,
809 const char *message)
db08e6e5
SW
810{
811 struct hlist_head *head;
812 struct hlist_node *node, *safe;
813 struct tt_orig_list_entry *orig_entry;
814
815 spin_lock_bh(&tt_global_entry->list_lock);
816 head = &tt_global_entry->orig_list;
817 hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
818 if (orig_entry->orig_node == orig_node) {
1eda58bf
SE
819 batadv_dbg(DBG_TT, bat_priv,
820 "Deleting %pM from global tt entry %pM: %s\n",
821 orig_node->orig,
822 tt_global_entry->common.addr, message);
db08e6e5 823 hlist_del_rcu(node);
a513088d 824 batadv_tt_orig_list_entry_free_ref(orig_entry);
db08e6e5
SW
825 }
826 }
827 spin_unlock_bh(&tt_global_entry->list_lock);
828}
829
a513088d
SE
830static void batadv_tt_global_del_struct(struct bat_priv *bat_priv,
831 struct tt_global_entry *tt_global_entry,
832 const char *message)
db08e6e5 833{
1eda58bf
SE
834 batadv_dbg(DBG_TT, bat_priv, "Deleting global tt entry %pM: %s\n",
835 tt_global_entry->common.addr, message);
7683fdc1 836
a513088d 837 batadv_hash_remove(bat_priv->tt_global_hash, batadv_compare_tt,
da641193 838 batadv_choose_orig, tt_global_entry->common.addr);
a513088d 839 batadv_tt_global_entry_free_ref(tt_global_entry);
db08e6e5 840
c6c8fea2
SE
841}
842
db08e6e5
SW
843/* If the client is to be deleted, we check if it is the last origantor entry
844 * within tt_global entry. If yes, we set the TT_CLIENT_ROAM flag and the timer,
845 * otherwise we simply remove the originator scheduled for deletion.
846 */
a513088d
SE
847static void
848batadv_tt_global_del_roaming(struct bat_priv *bat_priv,
849 struct tt_global_entry *tt_global_entry,
850 struct orig_node *orig_node, const char *message)
db08e6e5
SW
851{
852 bool last_entry = true;
853 struct hlist_head *head;
854 struct hlist_node *node;
855 struct tt_orig_list_entry *orig_entry;
856
857 /* no local entry exists, case 1:
858 * Check if this is the last one or if other entries exist.
859 */
860
861 rcu_read_lock();
862 head = &tt_global_entry->orig_list;
863 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
864 if (orig_entry->orig_node != orig_node) {
865 last_entry = false;
866 break;
867 }
868 }
869 rcu_read_unlock();
870
871 if (last_entry) {
872 /* its the last one, mark for roaming. */
873 tt_global_entry->common.flags |= TT_CLIENT_ROAM;
874 tt_global_entry->roam_at = jiffies;
875 } else
876 /* there is another entry, we can simply delete this
877 * one and can still use the other one.
878 */
a513088d
SE
879 batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
880 orig_node, message);
db08e6e5
SW
881}
882
883
884
a513088d
SE
885static void batadv_tt_global_del(struct bat_priv *bat_priv,
886 struct orig_node *orig_node,
887 const unsigned char *addr,
888 const char *message, bool roaming)
a73105b8 889{
7683fdc1 890 struct tt_global_entry *tt_global_entry = NULL;
a513088d 891 struct tt_local_entry *local_entry = NULL;
a73105b8 892
a513088d 893 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
db08e6e5 894 if (!tt_global_entry)
7683fdc1 895 goto out;
a73105b8 896
db08e6e5 897 if (!roaming) {
a513088d
SE
898 batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
899 orig_node, message);
db08e6e5
SW
900
901 if (hlist_empty(&tt_global_entry->orig_list))
a513088d
SE
902 batadv_tt_global_del_struct(bat_priv, tt_global_entry,
903 message);
db08e6e5
SW
904
905 goto out;
906 }
92f90f56
SE
907
908 /* if we are deleting a global entry due to a roam
909 * event, there are two possibilities:
db08e6e5
SW
910 * 1) the client roamed from node A to node B => if there
911 * is only one originator left for this client, we mark
92f90f56
SE
912 * it with TT_CLIENT_ROAM, we start a timer and we
913 * wait for node B to claim it. In case of timeout
914 * the entry is purged.
db08e6e5
SW
915 *
916 * If there are other originators left, we directly delete
917 * the originator.
92f90f56 918 * 2) the client roamed to us => we can directly delete
9cfc7bd6
SE
919 * the global entry, since it is useless now.
920 */
a513088d
SE
921 local_entry = batadv_tt_local_hash_find(bat_priv,
922 tt_global_entry->common.addr);
923 if (local_entry) {
db08e6e5 924 /* local entry exists, case 2: client roamed to us. */
a513088d
SE
925 batadv_tt_global_del_orig_list(tt_global_entry);
926 batadv_tt_global_del_struct(bat_priv, tt_global_entry, message);
db08e6e5
SW
927 } else
928 /* no local entry exists, case 1: check for roaming */
a513088d
SE
929 batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
930 orig_node, message);
92f90f56 931
92f90f56 932
cc47f66e 933out:
7683fdc1 934 if (tt_global_entry)
a513088d
SE
935 batadv_tt_global_entry_free_ref(tt_global_entry);
936 if (local_entry)
937 batadv_tt_local_entry_free_ref(local_entry);
a73105b8
AQ
938}
939
08c36d3e
SE
940void batadv_tt_global_del_orig(struct bat_priv *bat_priv,
941 struct orig_node *orig_node, const char *message)
c6c8fea2 942{
a513088d 943 struct tt_global_entry *global_entry;
48100bac 944 struct tt_common_entry *tt_common_entry;
c90681b8 945 uint32_t i;
a73105b8
AQ
946 struct hashtable_t *hash = bat_priv->tt_global_hash;
947 struct hlist_node *node, *safe;
948 struct hlist_head *head;
7683fdc1 949 spinlock_t *list_lock; /* protects write access to the hash lists */
c6c8fea2 950
6e801494
SW
951 if (!hash)
952 return;
953
a73105b8
AQ
954 for (i = 0; i < hash->size; i++) {
955 head = &hash->table[i];
7683fdc1 956 list_lock = &hash->list_locks[i];
c6c8fea2 957
7683fdc1 958 spin_lock_bh(list_lock);
48100bac 959 hlist_for_each_entry_safe(tt_common_entry, node, safe,
7c64fd98 960 head, hash_entry) {
a513088d
SE
961 global_entry = container_of(tt_common_entry,
962 struct tt_global_entry,
963 common);
db08e6e5 964
a513088d
SE
965 batadv_tt_global_del_orig_entry(bat_priv, global_entry,
966 orig_node, message);
db08e6e5 967
a513088d 968 if (hlist_empty(&global_entry->orig_list)) {
1eda58bf
SE
969 batadv_dbg(DBG_TT, bat_priv,
970 "Deleting global tt entry %pM: %s\n",
a513088d 971 global_entry->common.addr, message);
7683fdc1 972 hlist_del_rcu(node);
a513088d 973 batadv_tt_global_entry_free_ref(global_entry);
7683fdc1 974 }
a73105b8 975 }
7683fdc1 976 spin_unlock_bh(list_lock);
c6c8fea2 977 }
17071578 978 orig_node->tt_initialised = false;
c6c8fea2
SE
979}
980
a513088d 981static void batadv_tt_global_roam_purge(struct bat_priv *bat_priv)
cc47f66e
AQ
982{
983 struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac 984 struct tt_common_entry *tt_common_entry;
cc47f66e
AQ
985 struct tt_global_entry *tt_global_entry;
986 struct hlist_node *node, *node_tmp;
987 struct hlist_head *head;
7683fdc1 988 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 989 uint32_t i;
cc47f66e 990
cc47f66e
AQ
991 for (i = 0; i < hash->size; i++) {
992 head = &hash->table[i];
7683fdc1 993 list_lock = &hash->list_locks[i];
cc47f66e 994
7683fdc1 995 spin_lock_bh(list_lock);
48100bac 996 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
cc47f66e 997 head, hash_entry) {
48100bac
AQ
998 tt_global_entry = container_of(tt_common_entry,
999 struct tt_global_entry,
1000 common);
1001 if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
cc47f66e 1002 continue;
1eda58bf
SE
1003 if (!batadv_has_timed_out(tt_global_entry->roam_at,
1004 TT_CLIENT_ROAM_TIMEOUT))
cc47f66e
AQ
1005 continue;
1006
1eda58bf
SE
1007 batadv_dbg(DBG_TT, bat_priv,
1008 "Deleting global tt entry (%pM): Roaming timeout\n",
1009 tt_global_entry->common.addr);
db08e6e5 1010
7683fdc1 1011 hlist_del_rcu(node);
a513088d 1012 batadv_tt_global_entry_free_ref(tt_global_entry);
cc47f66e 1013 }
7683fdc1 1014 spin_unlock_bh(list_lock);
cc47f66e
AQ
1015 }
1016
cc47f66e
AQ
1017}
1018
a513088d 1019static void batadv_tt_global_table_free(struct bat_priv *bat_priv)
c6c8fea2 1020{
7683fdc1
AQ
1021 struct hashtable_t *hash;
1022 spinlock_t *list_lock; /* protects write access to the hash lists */
48100bac 1023 struct tt_common_entry *tt_common_entry;
7683fdc1
AQ
1024 struct tt_global_entry *tt_global_entry;
1025 struct hlist_node *node, *node_tmp;
1026 struct hlist_head *head;
c90681b8 1027 uint32_t i;
7683fdc1 1028
2dafb49d 1029 if (!bat_priv->tt_global_hash)
c6c8fea2
SE
1030 return;
1031
7683fdc1
AQ
1032 hash = bat_priv->tt_global_hash;
1033
1034 for (i = 0; i < hash->size; i++) {
1035 head = &hash->table[i];
1036 list_lock = &hash->list_locks[i];
1037
1038 spin_lock_bh(list_lock);
48100bac 1039 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
7683fdc1
AQ
1040 head, hash_entry) {
1041 hlist_del_rcu(node);
48100bac
AQ
1042 tt_global_entry = container_of(tt_common_entry,
1043 struct tt_global_entry,
1044 common);
a513088d 1045 batadv_tt_global_entry_free_ref(tt_global_entry);
7683fdc1
AQ
1046 }
1047 spin_unlock_bh(list_lock);
1048 }
1049
1a8eaf07 1050 batadv_hash_destroy(hash);
7683fdc1 1051
2dafb49d 1052 bat_priv->tt_global_hash = NULL;
c6c8fea2
SE
1053}
1054
a513088d
SE
1055static bool _batadv_is_ap_isolated(struct tt_local_entry *tt_local_entry,
1056 struct tt_global_entry *tt_global_entry)
59b699cd
AQ
1057{
1058 bool ret = false;
1059
48100bac
AQ
1060 if (tt_local_entry->common.flags & TT_CLIENT_WIFI &&
1061 tt_global_entry->common.flags & TT_CLIENT_WIFI)
59b699cd
AQ
1062 ret = true;
1063
1064 return ret;
1065}
1066
08c36d3e
SE
1067struct orig_node *batadv_transtable_search(struct bat_priv *bat_priv,
1068 const uint8_t *src,
1069 const uint8_t *addr)
c6c8fea2 1070{
3d393e47
AQ
1071 struct tt_local_entry *tt_local_entry = NULL;
1072 struct tt_global_entry *tt_global_entry = NULL;
7b36e8ee 1073 struct orig_node *orig_node = NULL;
db08e6e5
SW
1074 struct neigh_node *router = NULL;
1075 struct hlist_head *head;
1076 struct hlist_node *node;
1077 struct tt_orig_list_entry *orig_entry;
1078 int best_tq;
c6c8fea2 1079
3d393e47 1080 if (src && atomic_read(&bat_priv->ap_isolation)) {
a513088d 1081 tt_local_entry = batadv_tt_local_hash_find(bat_priv, src);
3d393e47
AQ
1082 if (!tt_local_entry)
1083 goto out;
1084 }
7aadf889 1085
a513088d 1086 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
2dafb49d 1087 if (!tt_global_entry)
7b36e8ee 1088 goto out;
7aadf889 1089
3d393e47 1090 /* check whether the clients should not communicate due to AP
9cfc7bd6
SE
1091 * isolation
1092 */
a513088d
SE
1093 if (tt_local_entry &&
1094 _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
3d393e47
AQ
1095 goto out;
1096
db08e6e5 1097 best_tq = 0;
c6c8fea2 1098
db08e6e5
SW
1099 rcu_read_lock();
1100 head = &tt_global_entry->orig_list;
1101 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
7d211efc 1102 router = batadv_orig_node_get_router(orig_entry->orig_node);
db08e6e5
SW
1103 if (!router)
1104 continue;
c6c8fea2 1105
db08e6e5
SW
1106 if (router->tq_avg > best_tq) {
1107 orig_node = orig_entry->orig_node;
1108 best_tq = router->tq_avg;
1109 }
7d211efc 1110 batadv_neigh_node_free_ref(router);
db08e6e5
SW
1111 }
1112 /* found anything? */
1113 if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
1114 orig_node = NULL;
1115 rcu_read_unlock();
7b36e8ee 1116out:
3d393e47 1117 if (tt_global_entry)
a513088d 1118 batadv_tt_global_entry_free_ref(tt_global_entry);
3d393e47 1119 if (tt_local_entry)
a513088d 1120 batadv_tt_local_entry_free_ref(tt_local_entry);
3d393e47 1121
7b36e8ee 1122 return orig_node;
c6c8fea2 1123}
a73105b8
AQ
1124
1125/* Calculates the checksum of the local table of a given orig_node */
a513088d
SE
1126static uint16_t batadv_tt_global_crc(struct bat_priv *bat_priv,
1127 struct orig_node *orig_node)
a73105b8
AQ
1128{
1129 uint16_t total = 0, total_one;
1130 struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac 1131 struct tt_common_entry *tt_common_entry;
a73105b8
AQ
1132 struct tt_global_entry *tt_global_entry;
1133 struct hlist_node *node;
1134 struct hlist_head *head;
c90681b8
AQ
1135 uint32_t i;
1136 int j;
a73105b8
AQ
1137
1138 for (i = 0; i < hash->size; i++) {
1139 head = &hash->table[i];
1140
1141 rcu_read_lock();
48100bac 1142 hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8 1143 head, hash_entry) {
48100bac
AQ
1144 tt_global_entry = container_of(tt_common_entry,
1145 struct tt_global_entry,
1146 common);
db08e6e5
SW
1147 /* Roaming clients are in the global table for
1148 * consistency only. They don't have to be
1149 * taken into account while computing the
1150 * global crc
1151 */
1152 if (tt_global_entry->common.flags & TT_CLIENT_ROAM)
1153 continue;
1154
1155 /* find out if this global entry is announced by this
1156 * originator
1157 */
a513088d
SE
1158 if (!batadv_tt_global_entry_has_orig(tt_global_entry,
1159 orig_node))
db08e6e5
SW
1160 continue;
1161
1162 total_one = 0;
1163 for (j = 0; j < ETH_ALEN; j++)
1164 total_one = crc16_byte(total_one,
1165 tt_global_entry->common.addr[j]);
1166 total ^= total_one;
a73105b8
AQ
1167 }
1168 rcu_read_unlock();
1169 }
1170
1171 return total;
1172}
1173
1174/* Calculates the checksum of the local table */
be9aa4c1 1175static uint16_t batadv_tt_local_crc(struct bat_priv *bat_priv)
a73105b8
AQ
1176{
1177 uint16_t total = 0, total_one;
1178 struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac 1179 struct tt_common_entry *tt_common_entry;
a73105b8
AQ
1180 struct hlist_node *node;
1181 struct hlist_head *head;
c90681b8
AQ
1182 uint32_t i;
1183 int j;
a73105b8
AQ
1184
1185 for (i = 0; i < hash->size; i++) {
1186 head = &hash->table[i];
1187
1188 rcu_read_lock();
48100bac 1189 hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8 1190 head, hash_entry) {
058d0e26 1191 /* not yet committed clients have not to be taken into
9cfc7bd6
SE
1192 * account while computing the CRC
1193 */
48100bac 1194 if (tt_common_entry->flags & TT_CLIENT_NEW)
058d0e26 1195 continue;
a73105b8
AQ
1196 total_one = 0;
1197 for (j = 0; j < ETH_ALEN; j++)
1198 total_one = crc16_byte(total_one,
48100bac 1199 tt_common_entry->addr[j]);
a73105b8
AQ
1200 total ^= total_one;
1201 }
a73105b8
AQ
1202 rcu_read_unlock();
1203 }
1204
1205 return total;
1206}
1207
a513088d 1208static void batadv_tt_req_list_free(struct bat_priv *bat_priv)
a73105b8
AQ
1209{
1210 struct tt_req_node *node, *safe;
1211
1212 spin_lock_bh(&bat_priv->tt_req_list_lock);
1213
1214 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1215 list_del(&node->list);
1216 kfree(node);
1217 }
1218
1219 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1220}
1221
a513088d
SE
1222static void batadv_tt_save_orig_buffer(struct bat_priv *bat_priv,
1223 struct orig_node *orig_node,
1224 const unsigned char *tt_buff,
1225 uint8_t tt_num_changes)
a73105b8 1226{
08c36d3e 1227 uint16_t tt_buff_len = batadv_tt_len(tt_num_changes);
a73105b8
AQ
1228
1229 /* Replace the old buffer only if I received something in the
9cfc7bd6
SE
1230 * last OGM (the OGM could carry no changes)
1231 */
a73105b8
AQ
1232 spin_lock_bh(&orig_node->tt_buff_lock);
1233 if (tt_buff_len > 0) {
1234 kfree(orig_node->tt_buff);
1235 orig_node->tt_buff_len = 0;
1236 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
1237 if (orig_node->tt_buff) {
1238 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
1239 orig_node->tt_buff_len = tt_buff_len;
1240 }
1241 }
1242 spin_unlock_bh(&orig_node->tt_buff_lock);
1243}
1244
a513088d 1245static void batadv_tt_req_purge(struct bat_priv *bat_priv)
a73105b8
AQ
1246{
1247 struct tt_req_node *node, *safe;
1248
1249 spin_lock_bh(&bat_priv->tt_req_list_lock);
1250 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1eda58bf 1251 if (batadv_has_timed_out(node->issued_at, TT_REQUEST_TIMEOUT)) {
a73105b8
AQ
1252 list_del(&node->list);
1253 kfree(node);
1254 }
1255 }
1256 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1257}
1258
1259/* returns the pointer to the new tt_req_node struct if no request
9cfc7bd6
SE
1260 * has already been issued for this orig_node, NULL otherwise
1261 */
a513088d
SE
1262static struct tt_req_node *batadv_new_tt_req_node(struct bat_priv *bat_priv,
1263 struct orig_node *orig_node)
a73105b8
AQ
1264{
1265 struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
1266
1267 spin_lock_bh(&bat_priv->tt_req_list_lock);
1268 list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
1eda58bf
SE
1269 if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
1270 !batadv_has_timed_out(tt_req_node_tmp->issued_at,
1271 TT_REQUEST_TIMEOUT))
a73105b8
AQ
1272 goto unlock;
1273 }
1274
1275 tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
1276 if (!tt_req_node)
1277 goto unlock;
1278
1279 memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
1280 tt_req_node->issued_at = jiffies;
1281
1282 list_add(&tt_req_node->list, &bat_priv->tt_req_list);
1283unlock:
1284 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1285 return tt_req_node;
1286}
1287
058d0e26 1288/* data_ptr is useless here, but has to be kept to respect the prototype */
a513088d
SE
1289static int batadv_tt_local_valid_entry(const void *entry_ptr,
1290 const void *data_ptr)
058d0e26 1291{
48100bac 1292 const struct tt_common_entry *tt_common_entry = entry_ptr;
058d0e26 1293
48100bac 1294 if (tt_common_entry->flags & TT_CLIENT_NEW)
058d0e26
AQ
1295 return 0;
1296 return 1;
1297}
1298
a513088d
SE
1299static int batadv_tt_global_valid(const void *entry_ptr,
1300 const void *data_ptr)
a73105b8 1301{
48100bac
AQ
1302 const struct tt_common_entry *tt_common_entry = entry_ptr;
1303 const struct tt_global_entry *tt_global_entry;
a73105b8
AQ
1304 const struct orig_node *orig_node = data_ptr;
1305
48100bac 1306 if (tt_common_entry->flags & TT_CLIENT_ROAM)
cc47f66e
AQ
1307 return 0;
1308
48100bac
AQ
1309 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
1310 common);
1311
a513088d 1312 return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node);
a73105b8
AQ
1313}
1314
a513088d
SE
1315static struct sk_buff *
1316batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
1317 struct hashtable_t *hash,
1318 struct hard_iface *primary_if,
1319 int (*valid_cb)(const void *, const void *),
1320 void *cb_data)
a73105b8 1321{
48100bac 1322 struct tt_common_entry *tt_common_entry;
a73105b8
AQ
1323 struct tt_query_packet *tt_response;
1324 struct tt_change *tt_change;
1325 struct hlist_node *node;
1326 struct hlist_head *head;
1327 struct sk_buff *skb = NULL;
1328 uint16_t tt_tot, tt_count;
1329 ssize_t tt_query_size = sizeof(struct tt_query_packet);
c90681b8 1330 uint32_t i;
a73105b8
AQ
1331
1332 if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
1333 tt_len = primary_if->soft_iface->mtu - tt_query_size;
1334 tt_len -= tt_len % sizeof(struct tt_change);
1335 }
1336 tt_tot = tt_len / sizeof(struct tt_change);
1337
1338 skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
1339 if (!skb)
1340 goto out;
1341
1342 skb_reserve(skb, ETH_HLEN);
1343 tt_response = (struct tt_query_packet *)skb_put(skb,
1344 tt_query_size + tt_len);
1345 tt_response->ttvn = ttvn;
a73105b8
AQ
1346
1347 tt_change = (struct tt_change *)(skb->data + tt_query_size);
1348 tt_count = 0;
1349
1350 rcu_read_lock();
1351 for (i = 0; i < hash->size; i++) {
1352 head = &hash->table[i];
1353
48100bac 1354 hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8
AQ
1355 head, hash_entry) {
1356 if (tt_count == tt_tot)
1357 break;
1358
48100bac 1359 if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
a73105b8
AQ
1360 continue;
1361
48100bac
AQ
1362 memcpy(tt_change->addr, tt_common_entry->addr,
1363 ETH_ALEN);
a73105b8
AQ
1364 tt_change->flags = NO_FLAGS;
1365
1366 tt_count++;
1367 tt_change++;
1368 }
1369 }
1370 rcu_read_unlock();
1371
9d852393 1372 /* store in the message the number of entries we have successfully
9cfc7bd6
SE
1373 * copied
1374 */
9d852393
AQ
1375 tt_response->tt_data = htons(tt_count);
1376
a73105b8
AQ
1377out:
1378 return skb;
1379}
1380
a513088d
SE
1381static int batadv_send_tt_request(struct bat_priv *bat_priv,
1382 struct orig_node *dst_orig_node,
1383 uint8_t ttvn, uint16_t tt_crc,
1384 bool full_table)
a73105b8
AQ
1385{
1386 struct sk_buff *skb = NULL;
1387 struct tt_query_packet *tt_request;
1388 struct neigh_node *neigh_node = NULL;
1389 struct hard_iface *primary_if;
1390 struct tt_req_node *tt_req_node = NULL;
1391 int ret = 1;
1392
e5d89254 1393 primary_if = batadv_primary_if_get_selected(bat_priv);
a73105b8
AQ
1394 if (!primary_if)
1395 goto out;
1396
1397 /* The new tt_req will be issued only if I'm not waiting for a
9cfc7bd6
SE
1398 * reply from the same orig_node yet
1399 */
a513088d 1400 tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node);
a73105b8
AQ
1401 if (!tt_req_node)
1402 goto out;
1403
1404 skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
1405 if (!skb)
1406 goto out;
1407
1408 skb_reserve(skb, ETH_HLEN);
1409
1410 tt_request = (struct tt_query_packet *)skb_put(skb,
1411 sizeof(struct tt_query_packet));
1412
76543d14
SE
1413 tt_request->header.packet_type = BAT_TT_QUERY;
1414 tt_request->header.version = COMPAT_VERSION;
a73105b8
AQ
1415 memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1416 memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
76543d14 1417 tt_request->header.ttl = TTL;
a73105b8 1418 tt_request->ttvn = ttvn;
6d2003fc 1419 tt_request->tt_data = htons(tt_crc);
a73105b8
AQ
1420 tt_request->flags = TT_REQUEST;
1421
1422 if (full_table)
1423 tt_request->flags |= TT_FULL_TABLE;
1424
7d211efc 1425 neigh_node = batadv_orig_node_get_router(dst_orig_node);
a73105b8
AQ
1426 if (!neigh_node)
1427 goto out;
1428
1eda58bf
SE
1429 batadv_dbg(DBG_TT, bat_priv,
1430 "Sending TT_REQUEST to %pM via %pM [%c]\n",
1431 dst_orig_node->orig, neigh_node->addr,
1432 (full_table ? 'F' : '.'));
a73105b8 1433
f8214865
MH
1434 batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_TX);
1435
9455e34c 1436 batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
a73105b8
AQ
1437 ret = 0;
1438
1439out:
1440 if (neigh_node)
7d211efc 1441 batadv_neigh_node_free_ref(neigh_node);
a73105b8 1442 if (primary_if)
e5d89254 1443 batadv_hardif_free_ref(primary_if);
a73105b8
AQ
1444 if (ret)
1445 kfree_skb(skb);
1446 if (ret && tt_req_node) {
1447 spin_lock_bh(&bat_priv->tt_req_list_lock);
1448 list_del(&tt_req_node->list);
1449 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1450 kfree(tt_req_node);
1451 }
1452 return ret;
1453}
1454
a513088d
SE
1455static bool batadv_send_other_tt_response(struct bat_priv *bat_priv,
1456 struct tt_query_packet *tt_request)
a73105b8
AQ
1457{
1458 struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
1459 struct neigh_node *neigh_node = NULL;
1460 struct hard_iface *primary_if = NULL;
1461 uint8_t orig_ttvn, req_ttvn, ttvn;
1462 int ret = false;
1463 unsigned char *tt_buff;
1464 bool full_table;
1465 uint16_t tt_len, tt_tot;
1466 struct sk_buff *skb = NULL;
1467 struct tt_query_packet *tt_response;
1468
1eda58bf
SE
1469 batadv_dbg(DBG_TT, bat_priv,
1470 "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
1471 tt_request->src, tt_request->ttvn, tt_request->dst,
1472 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
a73105b8
AQ
1473
1474 /* Let's get the orig node of the REAL destination */
da641193 1475 req_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->dst);
a73105b8
AQ
1476 if (!req_dst_orig_node)
1477 goto out;
1478
da641193 1479 res_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->src);
a73105b8
AQ
1480 if (!res_dst_orig_node)
1481 goto out;
1482
7d211efc 1483 neigh_node = batadv_orig_node_get_router(res_dst_orig_node);
a73105b8
AQ
1484 if (!neigh_node)
1485 goto out;
1486
e5d89254 1487 primary_if = batadv_primary_if_get_selected(bat_priv);
a73105b8
AQ
1488 if (!primary_if)
1489 goto out;
1490
1491 orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1492 req_ttvn = tt_request->ttvn;
1493
015758d0 1494 /* I don't have the requested data */
a73105b8 1495 if (orig_ttvn != req_ttvn ||
f25bd58a 1496 tt_request->tt_data != htons(req_dst_orig_node->tt_crc))
a73105b8
AQ
1497 goto out;
1498
015758d0 1499 /* If the full table has been explicitly requested */
a73105b8
AQ
1500 if (tt_request->flags & TT_FULL_TABLE ||
1501 !req_dst_orig_node->tt_buff)
1502 full_table = true;
1503 else
1504 full_table = false;
1505
1506 /* In this version, fragmentation is not implemented, then
9cfc7bd6
SE
1507 * I'll send only one packet with as much TT entries as I can
1508 */
a73105b8
AQ
1509 if (!full_table) {
1510 spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1511 tt_len = req_dst_orig_node->tt_buff_len;
1512 tt_tot = tt_len / sizeof(struct tt_change);
1513
1514 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1515 tt_len + ETH_HLEN);
1516 if (!skb)
1517 goto unlock;
1518
1519 skb_reserve(skb, ETH_HLEN);
1520 tt_response = (struct tt_query_packet *)skb_put(skb,
1521 sizeof(struct tt_query_packet) + tt_len);
1522 tt_response->ttvn = req_ttvn;
1523 tt_response->tt_data = htons(tt_tot);
1524
1525 tt_buff = skb->data + sizeof(struct tt_query_packet);
1526 /* Copy the last orig_node's OGM buffer */
1527 memcpy(tt_buff, req_dst_orig_node->tt_buff,
1528 req_dst_orig_node->tt_buff_len);
1529
1530 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1531 } else {
1532 tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
1533 sizeof(struct tt_change);
1534 ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1535
a513088d
SE
1536 skb = batadv_tt_response_fill_table(tt_len, ttvn,
1537 bat_priv->tt_global_hash,
1538 primary_if,
1539 batadv_tt_global_valid,
1540 req_dst_orig_node);
a73105b8
AQ
1541 if (!skb)
1542 goto out;
1543
1544 tt_response = (struct tt_query_packet *)skb->data;
1545 }
1546
76543d14
SE
1547 tt_response->header.packet_type = BAT_TT_QUERY;
1548 tt_response->header.version = COMPAT_VERSION;
1549 tt_response->header.ttl = TTL;
a73105b8
AQ
1550 memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
1551 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1552 tt_response->flags = TT_RESPONSE;
1553
1554 if (full_table)
1555 tt_response->flags |= TT_FULL_TABLE;
1556
1eda58bf
SE
1557 batadv_dbg(DBG_TT, bat_priv,
1558 "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
1559 res_dst_orig_node->orig, neigh_node->addr,
1560 req_dst_orig_node->orig, req_ttvn);
a73105b8 1561
f8214865
MH
1562 batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
1563
9455e34c 1564 batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
a73105b8
AQ
1565 ret = true;
1566 goto out;
1567
1568unlock:
1569 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1570
1571out:
1572 if (res_dst_orig_node)
7d211efc 1573 batadv_orig_node_free_ref(res_dst_orig_node);
a73105b8 1574 if (req_dst_orig_node)
7d211efc 1575 batadv_orig_node_free_ref(req_dst_orig_node);
a73105b8 1576 if (neigh_node)
7d211efc 1577 batadv_neigh_node_free_ref(neigh_node);
a73105b8 1578 if (primary_if)
e5d89254 1579 batadv_hardif_free_ref(primary_if);
a73105b8
AQ
1580 if (!ret)
1581 kfree_skb(skb);
1582 return ret;
1583
1584}
a513088d
SE
1585static bool batadv_send_my_tt_response(struct bat_priv *bat_priv,
1586 struct tt_query_packet *tt_request)
a73105b8
AQ
1587{
1588 struct orig_node *orig_node = NULL;
1589 struct neigh_node *neigh_node = NULL;
1590 struct hard_iface *primary_if = NULL;
1591 uint8_t my_ttvn, req_ttvn, ttvn;
1592 int ret = false;
1593 unsigned char *tt_buff;
1594 bool full_table;
1595 uint16_t tt_len, tt_tot;
1596 struct sk_buff *skb = NULL;
1597 struct tt_query_packet *tt_response;
1598
1eda58bf
SE
1599 batadv_dbg(DBG_TT, bat_priv,
1600 "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
1601 tt_request->src, tt_request->ttvn,
1602 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
a73105b8
AQ
1603
1604
1605 my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1606 req_ttvn = tt_request->ttvn;
1607
da641193 1608 orig_node = batadv_orig_hash_find(bat_priv, tt_request->src);
a73105b8
AQ
1609 if (!orig_node)
1610 goto out;
1611
7d211efc 1612 neigh_node = batadv_orig_node_get_router(orig_node);
a73105b8
AQ
1613 if (!neigh_node)
1614 goto out;
1615
e5d89254 1616 primary_if = batadv_primary_if_get_selected(bat_priv);
a73105b8
AQ
1617 if (!primary_if)
1618 goto out;
1619
1620 /* If the full table has been explicitly requested or the gap
9cfc7bd6
SE
1621 * is too big send the whole local translation table
1622 */
a73105b8
AQ
1623 if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
1624 !bat_priv->tt_buff)
1625 full_table = true;
1626 else
1627 full_table = false;
1628
1629 /* In this version, fragmentation is not implemented, then
9cfc7bd6
SE
1630 * I'll send only one packet with as much TT entries as I can
1631 */
a73105b8
AQ
1632 if (!full_table) {
1633 spin_lock_bh(&bat_priv->tt_buff_lock);
1634 tt_len = bat_priv->tt_buff_len;
1635 tt_tot = tt_len / sizeof(struct tt_change);
1636
1637 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1638 tt_len + ETH_HLEN);
1639 if (!skb)
1640 goto unlock;
1641
1642 skb_reserve(skb, ETH_HLEN);
1643 tt_response = (struct tt_query_packet *)skb_put(skb,
1644 sizeof(struct tt_query_packet) + tt_len);
1645 tt_response->ttvn = req_ttvn;
1646 tt_response->tt_data = htons(tt_tot);
1647
1648 tt_buff = skb->data + sizeof(struct tt_query_packet);
1649 memcpy(tt_buff, bat_priv->tt_buff,
1650 bat_priv->tt_buff_len);
1651 spin_unlock_bh(&bat_priv->tt_buff_lock);
1652 } else {
1653 tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
1654 sizeof(struct tt_change);
1655 ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1656
a513088d
SE
1657 skb = batadv_tt_response_fill_table(tt_len, ttvn,
1658 bat_priv->tt_local_hash,
1659 primary_if,
1660 batadv_tt_local_valid_entry,
1661 NULL);
a73105b8
AQ
1662 if (!skb)
1663 goto out;
1664
1665 tt_response = (struct tt_query_packet *)skb->data;
1666 }
1667
76543d14
SE
1668 tt_response->header.packet_type = BAT_TT_QUERY;
1669 tt_response->header.version = COMPAT_VERSION;
1670 tt_response->header.ttl = TTL;
a73105b8
AQ
1671 memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1672 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1673 tt_response->flags = TT_RESPONSE;
1674
1675 if (full_table)
1676 tt_response->flags |= TT_FULL_TABLE;
1677
1eda58bf
SE
1678 batadv_dbg(DBG_TT, bat_priv,
1679 "Sending TT_RESPONSE to %pM via %pM [%c]\n",
1680 orig_node->orig, neigh_node->addr,
1681 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
a73105b8 1682
f8214865
MH
1683 batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
1684
9455e34c 1685 batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
a73105b8
AQ
1686 ret = true;
1687 goto out;
1688
1689unlock:
1690 spin_unlock_bh(&bat_priv->tt_buff_lock);
1691out:
1692 if (orig_node)
7d211efc 1693 batadv_orig_node_free_ref(orig_node);
a73105b8 1694 if (neigh_node)
7d211efc 1695 batadv_neigh_node_free_ref(neigh_node);
a73105b8 1696 if (primary_if)
e5d89254 1697 batadv_hardif_free_ref(primary_if);
a73105b8
AQ
1698 if (!ret)
1699 kfree_skb(skb);
1700 /* This packet was for me, so it doesn't need to be re-routed */
1701 return true;
1702}
1703
08c36d3e
SE
1704bool batadv_send_tt_response(struct bat_priv *bat_priv,
1705 struct tt_query_packet *tt_request)
a73105b8 1706{
3193e8fd 1707 if (batadv_is_my_mac(tt_request->dst)) {
20ff9d59 1708 /* don't answer backbone gws! */
08adf151 1709 if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src))
20ff9d59
SW
1710 return true;
1711
a513088d 1712 return batadv_send_my_tt_response(bat_priv, tt_request);
20ff9d59 1713 } else {
a513088d 1714 return batadv_send_other_tt_response(bat_priv, tt_request);
20ff9d59 1715 }
a73105b8
AQ
1716}
1717
a513088d
SE
1718static void _batadv_tt_update_changes(struct bat_priv *bat_priv,
1719 struct orig_node *orig_node,
1720 struct tt_change *tt_change,
1721 uint16_t tt_num_changes, uint8_t ttvn)
a73105b8
AQ
1722{
1723 int i;
08c36d3e 1724 int is_wifi;
a513088d 1725 int roams;
a73105b8
AQ
1726
1727 for (i = 0; i < tt_num_changes; i++) {
08c36d3e 1728 if ((tt_change + i)->flags & TT_CLIENT_DEL) {
a513088d
SE
1729 roams = (tt_change + i)->flags & TT_CLIENT_ROAM;
1730 batadv_tt_global_del(bat_priv, orig_node,
1731 (tt_change + i)->addr,
1732 "tt removed by changes",
1733 roams);
08c36d3e
SE
1734 } else {
1735 is_wifi = (tt_change + i)->flags & TT_CLIENT_WIFI;
1736 if (!batadv_tt_global_add(bat_priv, orig_node,
1737 (tt_change + i)->addr, ttvn,
1738 false, is_wifi))
a73105b8
AQ
1739 /* In case of problem while storing a
1740 * global_entry, we stop the updating
1741 * procedure without committing the
1742 * ttvn change. This will avoid to send
1743 * corrupted data on tt_request
1744 */
1745 return;
08c36d3e 1746 }
a73105b8 1747 }
17071578 1748 orig_node->tt_initialised = true;
a73105b8
AQ
1749}
1750
a513088d
SE
1751static void batadv_tt_fill_gtable(struct bat_priv *bat_priv,
1752 struct tt_query_packet *tt_response)
a73105b8
AQ
1753{
1754 struct orig_node *orig_node = NULL;
1755
da641193 1756 orig_node = batadv_orig_hash_find(bat_priv, tt_response->src);
a73105b8
AQ
1757 if (!orig_node)
1758 goto out;
1759
1760 /* Purge the old table first.. */
08c36d3e 1761 batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table");
a73105b8 1762
a513088d
SE
1763 _batadv_tt_update_changes(bat_priv, orig_node,
1764 (struct tt_change *)(tt_response + 1),
1765 ntohs(tt_response->tt_data),
1766 tt_response->ttvn);
a73105b8
AQ
1767
1768 spin_lock_bh(&orig_node->tt_buff_lock);
1769 kfree(orig_node->tt_buff);
1770 orig_node->tt_buff_len = 0;
1771 orig_node->tt_buff = NULL;
1772 spin_unlock_bh(&orig_node->tt_buff_lock);
1773
1774 atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
1775
1776out:
1777 if (orig_node)
7d211efc 1778 batadv_orig_node_free_ref(orig_node);
a73105b8
AQ
1779}
1780
a513088d
SE
1781static void batadv_tt_update_changes(struct bat_priv *bat_priv,
1782 struct orig_node *orig_node,
1783 uint16_t tt_num_changes, uint8_t ttvn,
1784 struct tt_change *tt_change)
a73105b8 1785{
a513088d
SE
1786 _batadv_tt_update_changes(bat_priv, orig_node, tt_change,
1787 tt_num_changes, ttvn);
a73105b8 1788
a513088d
SE
1789 batadv_tt_save_orig_buffer(bat_priv, orig_node,
1790 (unsigned char *)tt_change, tt_num_changes);
a73105b8
AQ
1791 atomic_set(&orig_node->last_ttvn, ttvn);
1792}
1793
08c36d3e 1794bool batadv_is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
a73105b8 1795{
7683fdc1
AQ
1796 struct tt_local_entry *tt_local_entry = NULL;
1797 bool ret = false;
a73105b8 1798
a513088d 1799 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
7683fdc1
AQ
1800 if (!tt_local_entry)
1801 goto out;
058d0e26 1802 /* Check if the client has been logically deleted (but is kept for
9cfc7bd6
SE
1803 * consistency purpose)
1804 */
48100bac 1805 if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
058d0e26 1806 goto out;
7683fdc1
AQ
1807 ret = true;
1808out:
a73105b8 1809 if (tt_local_entry)
a513088d 1810 batadv_tt_local_entry_free_ref(tt_local_entry);
7683fdc1 1811 return ret;
a73105b8
AQ
1812}
1813
08c36d3e
SE
1814void batadv_handle_tt_response(struct bat_priv *bat_priv,
1815 struct tt_query_packet *tt_response)
a73105b8
AQ
1816{
1817 struct tt_req_node *node, *safe;
1818 struct orig_node *orig_node = NULL;
1819
1eda58bf
SE
1820 batadv_dbg(DBG_TT, bat_priv,
1821 "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
1822 tt_response->src, tt_response->ttvn,
1823 ntohs(tt_response->tt_data),
1824 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
a73105b8 1825
20ff9d59 1826 /* we should have never asked a backbone gw */
08adf151 1827 if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src))
20ff9d59
SW
1828 goto out;
1829
da641193 1830 orig_node = batadv_orig_hash_find(bat_priv, tt_response->src);
a73105b8
AQ
1831 if (!orig_node)
1832 goto out;
1833
1834 if (tt_response->flags & TT_FULL_TABLE)
a513088d 1835 batadv_tt_fill_gtable(bat_priv, tt_response);
a73105b8 1836 else
a513088d
SE
1837 batadv_tt_update_changes(bat_priv, orig_node,
1838 ntohs(tt_response->tt_data),
1839 tt_response->ttvn,
1840 (struct tt_change *)(tt_response + 1));
a73105b8
AQ
1841
1842 /* Delete the tt_req_node from pending tt_requests list */
1843 spin_lock_bh(&bat_priv->tt_req_list_lock);
1844 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1eda58bf 1845 if (!batadv_compare_eth(node->addr, tt_response->src))
a73105b8
AQ
1846 continue;
1847 list_del(&node->list);
1848 kfree(node);
1849 }
1850 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1851
1852 /* Recalculate the CRC for this orig_node and store it */
a513088d 1853 orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
cc47f66e 1854 /* Roaming phase is over: tables are in sync again. I can
9cfc7bd6
SE
1855 * unset the flag
1856 */
cc47f66e 1857 orig_node->tt_poss_change = false;
a73105b8
AQ
1858out:
1859 if (orig_node)
7d211efc 1860 batadv_orig_node_free_ref(orig_node);
a73105b8
AQ
1861}
1862
08c36d3e 1863int batadv_tt_init(struct bat_priv *bat_priv)
a73105b8 1864{
5346c35e 1865 int ret;
a73105b8 1866
a513088d 1867 ret = batadv_tt_local_init(bat_priv);
5346c35e
SE
1868 if (ret < 0)
1869 return ret;
1870
a513088d 1871 ret = batadv_tt_global_init(bat_priv);
5346c35e
SE
1872 if (ret < 0)
1873 return ret;
a73105b8 1874
a513088d 1875 batadv_tt_start_timer(bat_priv);
a73105b8
AQ
1876
1877 return 1;
1878}
1879
a513088d 1880static void batadv_tt_roam_list_free(struct bat_priv *bat_priv)
a73105b8 1881{
cc47f66e 1882 struct tt_roam_node *node, *safe;
a73105b8 1883
cc47f66e 1884 spin_lock_bh(&bat_priv->tt_roam_list_lock);
a73105b8 1885
cc47f66e
AQ
1886 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1887 list_del(&node->list);
1888 kfree(node);
1889 }
1890
1891 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1892}
1893
a513088d 1894static void batadv_tt_roam_purge(struct bat_priv *bat_priv)
cc47f66e
AQ
1895{
1896 struct tt_roam_node *node, *safe;
1897
1898 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1899 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1eda58bf 1900 if (!batadv_has_timed_out(node->first_time, ROAMING_MAX_TIME))
cc47f66e
AQ
1901 continue;
1902
1903 list_del(&node->list);
1904 kfree(node);
1905 }
1906 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1907}
1908
1909/* This function checks whether the client already reached the
1910 * maximum number of possible roaming phases. In this case the ROAMING_ADV
1911 * will not be sent.
1912 *
9cfc7bd6
SE
1913 * returns true if the ROAMING_ADV can be sent, false otherwise
1914 */
a513088d
SE
1915static bool batadv_tt_check_roam_count(struct bat_priv *bat_priv,
1916 uint8_t *client)
cc47f66e
AQ
1917{
1918 struct tt_roam_node *tt_roam_node;
1919 bool ret = false;
1920
1921 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1922 /* The new tt_req will be issued only if I'm not waiting for a
9cfc7bd6
SE
1923 * reply from the same orig_node yet
1924 */
cc47f66e 1925 list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
1eda58bf 1926 if (!batadv_compare_eth(tt_roam_node->addr, client))
cc47f66e
AQ
1927 continue;
1928
1eda58bf
SE
1929 if (batadv_has_timed_out(tt_roam_node->first_time,
1930 ROAMING_MAX_TIME))
cc47f66e
AQ
1931 continue;
1932
1933 if (!atomic_dec_not_zero(&tt_roam_node->counter))
1934 /* Sorry, you roamed too many times! */
1935 goto unlock;
1936 ret = true;
1937 break;
1938 }
1939
1940 if (!ret) {
1941 tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
1942 if (!tt_roam_node)
1943 goto unlock;
1944
1945 tt_roam_node->first_time = jiffies;
1946 atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
1947 memcpy(tt_roam_node->addr, client, ETH_ALEN);
1948
1949 list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
1950 ret = true;
1951 }
1952
1953unlock:
1954 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1955 return ret;
1956}
1957
a513088d
SE
1958static void batadv_send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
1959 struct orig_node *orig_node)
cc47f66e
AQ
1960{
1961 struct neigh_node *neigh_node = NULL;
1962 struct sk_buff *skb = NULL;
1963 struct roam_adv_packet *roam_adv_packet;
1964 int ret = 1;
1965 struct hard_iface *primary_if;
1966
1967 /* before going on we have to check whether the client has
9cfc7bd6
SE
1968 * already roamed to us too many times
1969 */
a513088d 1970 if (!batadv_tt_check_roam_count(bat_priv, client))
cc47f66e
AQ
1971 goto out;
1972
1973 skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
1974 if (!skb)
1975 goto out;
1976
1977 skb_reserve(skb, ETH_HLEN);
1978
1979 roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
1980 sizeof(struct roam_adv_packet));
1981
76543d14
SE
1982 roam_adv_packet->header.packet_type = BAT_ROAM_ADV;
1983 roam_adv_packet->header.version = COMPAT_VERSION;
1984 roam_adv_packet->header.ttl = TTL;
e5d89254 1985 primary_if = batadv_primary_if_get_selected(bat_priv);
cc47f66e
AQ
1986 if (!primary_if)
1987 goto out;
1988 memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
e5d89254 1989 batadv_hardif_free_ref(primary_if);
cc47f66e
AQ
1990 memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
1991 memcpy(roam_adv_packet->client, client, ETH_ALEN);
1992
7d211efc 1993 neigh_node = batadv_orig_node_get_router(orig_node);
cc47f66e
AQ
1994 if (!neigh_node)
1995 goto out;
1996
1eda58bf
SE
1997 batadv_dbg(DBG_TT, bat_priv,
1998 "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
1999 orig_node->orig, client, neigh_node->addr);
cc47f66e 2000
f8214865
MH
2001 batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_TX);
2002
9455e34c 2003 batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
cc47f66e
AQ
2004 ret = 0;
2005
2006out:
2007 if (neigh_node)
7d211efc 2008 batadv_neigh_node_free_ref(neigh_node);
cc47f66e
AQ
2009 if (ret)
2010 kfree_skb(skb);
2011 return;
a73105b8
AQ
2012}
2013
a513088d 2014static void batadv_tt_purge(struct work_struct *work)
a73105b8
AQ
2015{
2016 struct delayed_work *delayed_work =
2017 container_of(work, struct delayed_work, work);
2018 struct bat_priv *bat_priv =
2019 container_of(delayed_work, struct bat_priv, tt_work);
2020
a513088d
SE
2021 batadv_tt_local_purge(bat_priv);
2022 batadv_tt_global_roam_purge(bat_priv);
2023 batadv_tt_req_purge(bat_priv);
2024 batadv_tt_roam_purge(bat_priv);
a73105b8 2025
a513088d 2026 batadv_tt_start_timer(bat_priv);
a73105b8 2027}
cc47f66e 2028
08c36d3e 2029void batadv_tt_free(struct bat_priv *bat_priv)
cc47f66e
AQ
2030{
2031 cancel_delayed_work_sync(&bat_priv->tt_work);
2032
a513088d
SE
2033 batadv_tt_local_table_free(bat_priv);
2034 batadv_tt_global_table_free(bat_priv);
2035 batadv_tt_req_list_free(bat_priv);
2036 batadv_tt_changes_list_free(bat_priv);
2037 batadv_tt_roam_list_free(bat_priv);
cc47f66e
AQ
2038
2039 kfree(bat_priv->tt_buff);
2040}
058d0e26 2041
697f2531 2042/* This function will enable or disable the specified flags for all the entries
9cfc7bd6
SE
2043 * in the given hash table and returns the number of modified entries
2044 */
a513088d
SE
2045static uint16_t batadv_tt_set_flags(struct hashtable_t *hash, uint16_t flags,
2046 bool enable)
058d0e26 2047{
c90681b8 2048 uint32_t i;
697f2531 2049 uint16_t changed_num = 0;
058d0e26
AQ
2050 struct hlist_head *head;
2051 struct hlist_node *node;
48100bac 2052 struct tt_common_entry *tt_common_entry;
058d0e26
AQ
2053
2054 if (!hash)
697f2531 2055 goto out;
058d0e26
AQ
2056
2057 for (i = 0; i < hash->size; i++) {
2058 head = &hash->table[i];
2059
2060 rcu_read_lock();
48100bac 2061 hlist_for_each_entry_rcu(tt_common_entry, node,
058d0e26 2062 head, hash_entry) {
697f2531
AQ
2063 if (enable) {
2064 if ((tt_common_entry->flags & flags) == flags)
2065 continue;
2066 tt_common_entry->flags |= flags;
2067 } else {
2068 if (!(tt_common_entry->flags & flags))
2069 continue;
2070 tt_common_entry->flags &= ~flags;
2071 }
2072 changed_num++;
058d0e26
AQ
2073 }
2074 rcu_read_unlock();
2075 }
697f2531
AQ
2076out:
2077 return changed_num;
058d0e26
AQ
2078}
2079
2080/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
a513088d 2081static void batadv_tt_local_purge_pending_clients(struct bat_priv *bat_priv)
058d0e26
AQ
2082{
2083 struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac 2084 struct tt_common_entry *tt_common_entry;
058d0e26
AQ
2085 struct tt_local_entry *tt_local_entry;
2086 struct hlist_node *node, *node_tmp;
2087 struct hlist_head *head;
2088 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 2089 uint32_t i;
058d0e26
AQ
2090
2091 if (!hash)
2092 return;
2093
2094 for (i = 0; i < hash->size; i++) {
2095 head = &hash->table[i];
2096 list_lock = &hash->list_locks[i];
2097
2098 spin_lock_bh(list_lock);
48100bac 2099 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
058d0e26 2100 head, hash_entry) {
48100bac 2101 if (!(tt_common_entry->flags & TT_CLIENT_PENDING))
058d0e26
AQ
2102 continue;
2103
1eda58bf
SE
2104 batadv_dbg(DBG_TT, bat_priv,
2105 "Deleting local tt entry (%pM): pending\n",
2106 tt_common_entry->addr);
058d0e26
AQ
2107
2108 atomic_dec(&bat_priv->num_local_tt);
2109 hlist_del_rcu(node);
48100bac
AQ
2110 tt_local_entry = container_of(tt_common_entry,
2111 struct tt_local_entry,
2112 common);
a513088d 2113 batadv_tt_local_entry_free_ref(tt_local_entry);
058d0e26
AQ
2114 }
2115 spin_unlock_bh(list_lock);
2116 }
2117
2118}
2119
a513088d
SE
2120static int batadv_tt_commit_changes(struct bat_priv *bat_priv,
2121 unsigned char **packet_buff,
2122 int *packet_buff_len, int packet_min_len)
058d0e26 2123{
be9aa4c1
ML
2124 uint16_t changed_num = 0;
2125
2126 if (atomic_read(&bat_priv->tt_local_changes) < 1)
2127 return -ENOENT;
2128
a513088d
SE
2129 changed_num = batadv_tt_set_flags(bat_priv->tt_local_hash,
2130 TT_CLIENT_NEW, false);
be9aa4c1
ML
2131
2132 /* all reset entries have to be counted as local entries */
697f2531 2133 atomic_add(changed_num, &bat_priv->num_local_tt);
a513088d 2134 batadv_tt_local_purge_pending_clients(bat_priv);
be9aa4c1 2135 bat_priv->tt_crc = batadv_tt_local_crc(bat_priv);
058d0e26
AQ
2136
2137 /* Increment the TTVN only once per OGM interval */
2138 atomic_inc(&bat_priv->ttvn);
1eda58bf
SE
2139 batadv_dbg(DBG_TT, bat_priv,
2140 "Local changes committed, updating to ttvn %u\n",
2141 (uint8_t)atomic_read(&bat_priv->ttvn));
058d0e26 2142 bat_priv->tt_poss_change = false;
be9aa4c1
ML
2143
2144 /* reset the sending counter */
2145 atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
2146
a513088d
SE
2147 return batadv_tt_changes_fill_buff(bat_priv, packet_buff,
2148 packet_buff_len, packet_min_len);
be9aa4c1
ML
2149}
2150
2151/* when calling this function (hard_iface == primary_if) has to be true */
2152int batadv_tt_append_diff(struct bat_priv *bat_priv,
2153 unsigned char **packet_buff, int *packet_buff_len,
2154 int packet_min_len)
2155{
2156 int tt_num_changes;
2157
2158 /* if at least one change happened */
a513088d
SE
2159 tt_num_changes = batadv_tt_commit_changes(bat_priv, packet_buff,
2160 packet_buff_len,
2161 packet_min_len);
be9aa4c1
ML
2162
2163 /* if the changes have been sent often enough */
2164 if ((tt_num_changes < 0) &&
2165 (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))) {
a513088d
SE
2166 batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len,
2167 packet_min_len, packet_min_len);
be9aa4c1
ML
2168 tt_num_changes = 0;
2169 }
2170
2171 return tt_num_changes;
058d0e26 2172}
59b699cd 2173
08c36d3e
SE
2174bool batadv_is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src,
2175 uint8_t *dst)
59b699cd
AQ
2176{
2177 struct tt_local_entry *tt_local_entry = NULL;
2178 struct tt_global_entry *tt_global_entry = NULL;
5870adc6 2179 bool ret = false;
59b699cd
AQ
2180
2181 if (!atomic_read(&bat_priv->ap_isolation))
5870adc6 2182 goto out;
59b699cd 2183
a513088d 2184 tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst);
59b699cd
AQ
2185 if (!tt_local_entry)
2186 goto out;
2187
a513088d 2188 tt_global_entry = batadv_tt_global_hash_find(bat_priv, src);
59b699cd
AQ
2189 if (!tt_global_entry)
2190 goto out;
2191
1f129fef 2192 if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
59b699cd
AQ
2193 goto out;
2194
5870adc6 2195 ret = true;
59b699cd
AQ
2196
2197out:
2198 if (tt_global_entry)
a513088d 2199 batadv_tt_global_entry_free_ref(tt_global_entry);
59b699cd 2200 if (tt_local_entry)
a513088d 2201 batadv_tt_local_entry_free_ref(tt_local_entry);
59b699cd
AQ
2202 return ret;
2203}
a943cac1 2204
08c36d3e
SE
2205void batadv_tt_update_orig(struct bat_priv *bat_priv,
2206 struct orig_node *orig_node,
2207 const unsigned char *tt_buff, uint8_t tt_num_changes,
2208 uint8_t ttvn, uint16_t tt_crc)
a943cac1
ML
2209{
2210 uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
2211 bool full_table = true;
2212
20ff9d59 2213 /* don't care about a backbone gateways updates. */
08adf151 2214 if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
20ff9d59
SW
2215 return;
2216
17071578 2217 /* orig table not initialised AND first diff is in the OGM OR the ttvn
9cfc7bd6
SE
2218 * increased by one -> we can apply the attached changes
2219 */
17071578
AQ
2220 if ((!orig_node->tt_initialised && ttvn == 1) ||
2221 ttvn - orig_ttvn == 1) {
a943cac1
ML
2222 /* the OGM could not contain the changes due to their size or
2223 * because they have already been sent TT_OGM_APPEND_MAX times.
9cfc7bd6
SE
2224 * In this case send a tt request
2225 */
a943cac1
ML
2226 if (!tt_num_changes) {
2227 full_table = false;
2228 goto request_table;
2229 }
2230
a513088d
SE
2231 batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
2232 ttvn, (struct tt_change *)tt_buff);
a943cac1
ML
2233
2234 /* Even if we received the precomputed crc with the OGM, we
2235 * prefer to recompute it to spot any possible inconsistency
9cfc7bd6
SE
2236 * in the global table
2237 */
a513088d 2238 orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
a943cac1
ML
2239
2240 /* The ttvn alone is not enough to guarantee consistency
2241 * because a single value could represent different states
2242 * (due to the wrap around). Thus a node has to check whether
2243 * the resulting table (after applying the changes) is still
2244 * consistent or not. E.g. a node could disconnect while its
2245 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
2246 * checking the CRC value is mandatory to detect the
9cfc7bd6
SE
2247 * inconsistency
2248 */
a943cac1
ML
2249 if (orig_node->tt_crc != tt_crc)
2250 goto request_table;
2251
2252 /* Roaming phase is over: tables are in sync again. I can
9cfc7bd6
SE
2253 * unset the flag
2254 */
a943cac1
ML
2255 orig_node->tt_poss_change = false;
2256 } else {
2257 /* if we missed more than one change or our tables are not
9cfc7bd6
SE
2258 * in sync anymore -> request fresh tt data
2259 */
17071578
AQ
2260 if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
2261 orig_node->tt_crc != tt_crc) {
a943cac1 2262request_table:
1eda58bf
SE
2263 batadv_dbg(DBG_TT, bat_priv,
2264 "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %u last_crc: %u num_changes: %u)\n",
2265 orig_node->orig, ttvn, orig_ttvn, tt_crc,
2266 orig_node->tt_crc, tt_num_changes);
a513088d
SE
2267 batadv_send_tt_request(bat_priv, orig_node, ttvn,
2268 tt_crc, full_table);
a943cac1
ML
2269 return;
2270 }
2271 }
2272}
3275e7cc
AQ
2273
2274/* returns true whether we know that the client has moved from its old
2275 * originator to another one. This entry is kept is still kept for consistency
2276 * purposes
2277 */
08c36d3e
SE
2278bool batadv_tt_global_client_is_roaming(struct bat_priv *bat_priv,
2279 uint8_t *addr)
3275e7cc
AQ
2280{
2281 struct tt_global_entry *tt_global_entry;
2282 bool ret = false;
2283
a513088d 2284 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
3275e7cc
AQ
2285 if (!tt_global_entry)
2286 goto out;
2287
2288 ret = tt_global_entry->common.flags & TT_CLIENT_ROAM;
a513088d 2289 batadv_tt_global_entry_free_ref(tt_global_entry);
3275e7cc
AQ
2290out:
2291 return ret;
2292}