batman-adv: generalise tt_local_reset_flags()
[deliverable/linux.git] / net / batman-adv / translation-table.c
CommitLineData
c6c8fea2 1/*
64afe353 2 * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
c6c8fea2
SE
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "translation-table.h"
24#include "soft-interface.h"
32ae9b22 25#include "hard-interface.h"
a73105b8 26#include "send.h"
c6c8fea2
SE
27#include "hash.h"
28#include "originator.h"
a73105b8 29#include "routing.h"
c6c8fea2 30
a73105b8
AQ
31#include <linux/crc16.h>
32
33static void _tt_global_del(struct bat_priv *bat_priv,
34 struct tt_global_entry *tt_global_entry,
35 const char *message);
36static void tt_purge(struct work_struct *work);
c6c8fea2 37
7aadf889 38/* returns 1 if they are the same mac addr */
48100bac 39static int 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
a73105b8 47static void tt_start_timer(struct bat_priv *bat_priv)
c6c8fea2 48{
a73105b8
AQ
49 INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
50 queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
51 msecs_to_jiffies(5000));
c6c8fea2
SE
52}
53
48100bac
AQ
54static struct tt_common_entry *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
65 index = choose_orig(data, hash->size);
66 head = &hash->table[index];
67
68 rcu_read_lock();
48100bac
AQ
69 hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) {
70 if (!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
48100bac
AQ
84static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
85 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
48100bac
AQ
90 tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data);
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
48100bac
AQ
97static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
98 const void *data)
99{
100 struct tt_common_entry *tt_common_entry;
101 struct tt_global_entry *tt_global_entry = NULL;
7683fdc1 102
48100bac
AQ
103 tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data);
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
a73105b8
AQ
111static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
112{
113 unsigned long deadline;
114 deadline = starting_time + msecs_to_jiffies(timeout);
115
116 return time_after(jiffies, deadline);
117}
118
7683fdc1
AQ
119static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
120{
48100bac
AQ
121 if (atomic_dec_and_test(&tt_local_entry->common.refcount))
122 kfree_rcu(tt_local_entry, common.rcu);
7683fdc1
AQ
123}
124
531027fc
SW
125static void tt_global_entry_free_rcu(struct rcu_head *rcu)
126{
48100bac 127 struct tt_common_entry *tt_common_entry;
531027fc
SW
128 struct tt_global_entry *tt_global_entry;
129
48100bac
AQ
130 tt_common_entry = container_of(rcu, struct tt_common_entry, rcu);
131 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
132 common);
531027fc
SW
133
134 if (tt_global_entry->orig_node)
135 orig_node_free_ref(tt_global_entry->orig_node);
136
137 kfree(tt_global_entry);
138}
139
7683fdc1
AQ
140static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
141{
48100bac
AQ
142 if (atomic_dec_and_test(&tt_global_entry->common.refcount))
143 call_rcu(&tt_global_entry->common.rcu,
144 tt_global_entry_free_rcu);
7683fdc1
AQ
145}
146
ff66c975
AQ
147static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
148 uint8_t flags)
a73105b8
AQ
149{
150 struct tt_change_node *tt_change_node;
151
152 tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
153
154 if (!tt_change_node)
155 return;
156
ff66c975 157 tt_change_node->change.flags = flags;
a73105b8
AQ
158 memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
159
160 spin_lock_bh(&bat_priv->tt_changes_list_lock);
161 /* track the change in the OGMinterval list */
162 list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
163 atomic_inc(&bat_priv->tt_local_changes);
164 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
165
166 atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
167}
168
169int tt_len(int changes_num)
170{
171 return changes_num * sizeof(struct tt_change);
172}
173
174static int tt_local_init(struct bat_priv *bat_priv)
c6c8fea2 175{
2dafb49d 176 if (bat_priv->tt_local_hash)
c6c8fea2
SE
177 return 1;
178
2dafb49d 179 bat_priv->tt_local_hash = hash_new(1024);
c6c8fea2 180
2dafb49d 181 if (!bat_priv->tt_local_hash)
c6c8fea2
SE
182 return 0;
183
c6c8fea2
SE
184 return 1;
185}
186
bc279080
AQ
187void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
188 int ifindex)
c6c8fea2
SE
189{
190 struct bat_priv *bat_priv = netdev_priv(soft_iface);
7683fdc1
AQ
191 struct tt_local_entry *tt_local_entry = NULL;
192 struct tt_global_entry *tt_global_entry = NULL;
c6c8fea2 193
2dafb49d 194 tt_local_entry = tt_local_hash_find(bat_priv, addr);
c6c8fea2 195
2dafb49d
AQ
196 if (tt_local_entry) {
197 tt_local_entry->last_seen = jiffies;
7683fdc1 198 goto out;
c6c8fea2
SE
199 }
200
704509b8 201 tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
2dafb49d 202 if (!tt_local_entry)
7683fdc1 203 goto out;
a73105b8 204
a73105b8
AQ
205 bat_dbg(DBG_TT, bat_priv,
206 "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
207 (uint8_t)atomic_read(&bat_priv->ttvn));
c6c8fea2 208
48100bac
AQ
209 memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
210 tt_local_entry->common.flags = NO_FLAGS;
bc279080 211 if (is_wifi_iface(ifindex))
48100bac
AQ
212 tt_local_entry->common.flags |= TT_CLIENT_WIFI;
213 atomic_set(&tt_local_entry->common.refcount, 2);
214 tt_local_entry->last_seen = jiffies;
c6c8fea2
SE
215
216 /* the batman interface mac address should never be purged */
39901e71 217 if (compare_eth(addr, soft_iface->dev_addr))
48100bac 218 tt_local_entry->common.flags |= TT_CLIENT_NOPURGE;
c6c8fea2 219
48100bac 220 tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
ff66c975 221
058d0e26
AQ
222 /* The local entry has to be marked as NEW to avoid to send it in
223 * a full table response going out before the next ttvn increment
224 * (consistency check) */
48100bac 225 tt_local_entry->common.flags |= TT_CLIENT_NEW;
058d0e26 226
48100bac
AQ
227 hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig,
228 &tt_local_entry->common, &tt_local_entry->common.hash_entry);
7683fdc1 229
c6c8fea2 230 /* remove address from global hash if present */
2dafb49d 231 tt_global_entry = tt_global_hash_find(bat_priv, addr);
c6c8fea2 232
cc47f66e
AQ
233 /* Check whether it is a roaming! */
234 if (tt_global_entry) {
cc47f66e
AQ
235 /* This node is probably going to update its tt table */
236 tt_global_entry->orig_node->tt_poss_change = true;
980d55b2
AQ
237 /* The global entry has to be marked as PENDING and has to be
238 * kept for consistency purpose */
48100bac
AQ
239 tt_global_entry->common.flags |= TT_CLIENT_PENDING;
240 send_roam_adv(bat_priv, tt_global_entry->common.addr,
7683fdc1
AQ
241 tt_global_entry->orig_node);
242 }
243out:
244 if (tt_local_entry)
245 tt_local_entry_free_ref(tt_local_entry);
246 if (tt_global_entry)
247 tt_global_entry_free_ref(tt_global_entry);
c6c8fea2
SE
248}
249
a73105b8
AQ
250int tt_changes_fill_buffer(struct bat_priv *bat_priv,
251 unsigned char *buff, int buff_len)
c6c8fea2 252{
a73105b8
AQ
253 int count = 0, tot_changes = 0;
254 struct tt_change_node *entry, *safe;
c6c8fea2 255
a73105b8
AQ
256 if (buff_len > 0)
257 tot_changes = buff_len / tt_len(1);
c6c8fea2 258
a73105b8
AQ
259 spin_lock_bh(&bat_priv->tt_changes_list_lock);
260 atomic_set(&bat_priv->tt_local_changes, 0);
c6c8fea2 261
a73105b8
AQ
262 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
263 list) {
264 if (count < tot_changes) {
265 memcpy(buff + tt_len(count),
266 &entry->change, sizeof(struct tt_change));
c6c8fea2
SE
267 count++;
268 }
a73105b8
AQ
269 list_del(&entry->list);
270 kfree(entry);
c6c8fea2 271 }
a73105b8
AQ
272 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
273
274 /* Keep the buffer for possible tt_request */
275 spin_lock_bh(&bat_priv->tt_buff_lock);
276 kfree(bat_priv->tt_buff);
277 bat_priv->tt_buff_len = 0;
278 bat_priv->tt_buff = NULL;
279 /* We check whether this new OGM has no changes due to size
280 * problems */
281 if (buff_len > 0) {
282 /**
283 * if kmalloc() fails we will reply with the full table
284 * instead of providing the diff
285 */
286 bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
287 if (bat_priv->tt_buff) {
288 memcpy(bat_priv->tt_buff, buff, buff_len);
289 bat_priv->tt_buff_len = buff_len;
290 }
291 }
292 spin_unlock_bh(&bat_priv->tt_buff_lock);
c6c8fea2 293
a73105b8 294 return tot_changes;
c6c8fea2
SE
295}
296
2dafb49d 297int tt_local_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea2
SE
298{
299 struct net_device *net_dev = (struct net_device *)seq->private;
300 struct bat_priv *bat_priv = netdev_priv(net_dev);
2dafb49d 301 struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac 302 struct tt_common_entry *tt_common_entry;
32ae9b22 303 struct hard_iface *primary_if;
7aadf889 304 struct hlist_node *node;
c6c8fea2 305 struct hlist_head *head;
c90681b8
AQ
306 uint32_t i;
307 int ret = 0;
32ae9b22
ML
308
309 primary_if = primary_if_get_selected(bat_priv);
310 if (!primary_if) {
311 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
312 "please specify interfaces to enable it\n",
313 net_dev->name);
314 goto out;
315 }
c6c8fea2 316
32ae9b22
ML
317 if (primary_if->if_status != IF_ACTIVE) {
318 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
319 "primary interface not active\n",
320 net_dev->name);
321 goto out;
c6c8fea2
SE
322 }
323
324 seq_printf(seq, "Locally retrieved addresses (from %s) "
a73105b8
AQ
325 "announced via TT (TTVN: %u):\n",
326 net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
c6c8fea2 327
c6c8fea2
SE
328 for (i = 0; i < hash->size; i++) {
329 head = &hash->table[i];
330
7aadf889 331 rcu_read_lock();
48100bac 332 hlist_for_each_entry_rcu(tt_common_entry, node,
7aadf889 333 head, hash_entry) {
d099c2c5 334 seq_printf(seq, " * %pM [%c%c%c%c%c]\n",
48100bac
AQ
335 tt_common_entry->addr,
336 (tt_common_entry->flags &
df6edb9e 337 TT_CLIENT_ROAM ? 'R' : '.'),
48100bac 338 (tt_common_entry->flags &
df6edb9e 339 TT_CLIENT_NOPURGE ? 'P' : '.'),
48100bac 340 (tt_common_entry->flags &
df6edb9e 341 TT_CLIENT_NEW ? 'N' : '.'),
48100bac 342 (tt_common_entry->flags &
df6edb9e 343 TT_CLIENT_PENDING ? 'X' : '.'),
48100bac 344 (tt_common_entry->flags &
df6edb9e 345 TT_CLIENT_WIFI ? 'W' : '.'));
c6c8fea2 346 }
7aadf889 347 rcu_read_unlock();
c6c8fea2 348 }
32ae9b22
ML
349out:
350 if (primary_if)
351 hardif_free_ref(primary_if);
352 return ret;
c6c8fea2
SE
353}
354
058d0e26
AQ
355static void tt_local_set_pending(struct bat_priv *bat_priv,
356 struct tt_local_entry *tt_local_entry,
357 uint16_t flags)
c6c8fea2 358{
48100bac
AQ
359 tt_local_event(bat_priv, tt_local_entry->common.addr,
360 tt_local_entry->common.flags | flags);
a73105b8 361
015758d0
AQ
362 /* The local client has to be marked as "pending to be removed" but has
363 * to be kept in the table in order to send it in a full table
058d0e26 364 * response issued before the net ttvn increment (consistency check) */
48100bac 365 tt_local_entry->common.flags |= TT_CLIENT_PENDING;
c6c8fea2
SE
366}
367
a73105b8 368void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
cc47f66e 369 const char *message, bool roaming)
c6c8fea2 370{
7683fdc1 371 struct tt_local_entry *tt_local_entry = NULL;
c6c8fea2 372
2dafb49d 373 tt_local_entry = tt_local_hash_find(bat_priv, addr);
7683fdc1
AQ
374 if (!tt_local_entry)
375 goto out;
376
058d0e26
AQ
377 tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
378 (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
379
380 bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
48100bac 381 "%s\n", tt_local_entry->common.addr, message);
7683fdc1
AQ
382out:
383 if (tt_local_entry)
384 tt_local_entry_free_ref(tt_local_entry);
c6c8fea2
SE
385}
386
a73105b8 387static void tt_local_purge(struct bat_priv *bat_priv)
c6c8fea2 388{
2dafb49d
AQ
389 struct hashtable_t *hash = bat_priv->tt_local_hash;
390 struct tt_local_entry *tt_local_entry;
48100bac 391 struct tt_common_entry *tt_common_entry;
7aadf889 392 struct hlist_node *node, *node_tmp;
c6c8fea2 393 struct hlist_head *head;
7683fdc1 394 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 395 uint32_t i;
c6c8fea2 396
c6c8fea2
SE
397 for (i = 0; i < hash->size; i++) {
398 head = &hash->table[i];
7683fdc1 399 list_lock = &hash->list_locks[i];
c6c8fea2 400
7683fdc1 401 spin_lock_bh(list_lock);
48100bac 402 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
7aadf889 403 head, hash_entry) {
48100bac
AQ
404 tt_local_entry = container_of(tt_common_entry,
405 struct tt_local_entry,
406 common);
407 if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE)
7aadf889 408 continue;
c6c8fea2 409
058d0e26 410 /* entry already marked for deletion */
48100bac 411 if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
058d0e26
AQ
412 continue;
413
a73105b8 414 if (!is_out_of_time(tt_local_entry->last_seen,
7683fdc1 415 TT_LOCAL_TIMEOUT * 1000))
7aadf889
ML
416 continue;
417
058d0e26
AQ
418 tt_local_set_pending(bat_priv, tt_local_entry,
419 TT_CLIENT_DEL);
420 bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
421 "pending to be removed: timed out\n",
48100bac 422 tt_local_entry->common.addr);
c6c8fea2 423 }
7683fdc1 424 spin_unlock_bh(list_lock);
c6c8fea2
SE
425 }
426
c6c8fea2
SE
427}
428
a73105b8 429static void tt_local_table_free(struct bat_priv *bat_priv)
c6c8fea2 430{
a73105b8 431 struct hashtable_t *hash;
a73105b8 432 spinlock_t *list_lock; /* protects write access to the hash lists */
48100bac 433 struct tt_common_entry *tt_common_entry;
a73105b8 434 struct tt_local_entry *tt_local_entry;
7683fdc1
AQ
435 struct hlist_node *node, *node_tmp;
436 struct hlist_head *head;
c90681b8 437 uint32_t i;
a73105b8 438
2dafb49d 439 if (!bat_priv->tt_local_hash)
c6c8fea2
SE
440 return;
441
a73105b8
AQ
442 hash = bat_priv->tt_local_hash;
443
444 for (i = 0; i < hash->size; i++) {
445 head = &hash->table[i];
446 list_lock = &hash->list_locks[i];
447
448 spin_lock_bh(list_lock);
48100bac 449 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
a73105b8
AQ
450 head, hash_entry) {
451 hlist_del_rcu(node);
48100bac
AQ
452 tt_local_entry = container_of(tt_common_entry,
453 struct tt_local_entry,
454 common);
7683fdc1 455 tt_local_entry_free_ref(tt_local_entry);
a73105b8
AQ
456 }
457 spin_unlock_bh(list_lock);
458 }
459
460 hash_destroy(hash);
461
2dafb49d 462 bat_priv->tt_local_hash = NULL;
c6c8fea2
SE
463}
464
a73105b8 465static int tt_global_init(struct bat_priv *bat_priv)
c6c8fea2 466{
2dafb49d 467 if (bat_priv->tt_global_hash)
c6c8fea2
SE
468 return 1;
469
2dafb49d 470 bat_priv->tt_global_hash = hash_new(1024);
c6c8fea2 471
2dafb49d 472 if (!bat_priv->tt_global_hash)
c6c8fea2
SE
473 return 0;
474
475 return 1;
476}
477
a73105b8 478static void tt_changes_list_free(struct bat_priv *bat_priv)
c6c8fea2 479{
a73105b8 480 struct tt_change_node *entry, *safe;
c6c8fea2 481
a73105b8 482 spin_lock_bh(&bat_priv->tt_changes_list_lock);
c6c8fea2 483
a73105b8
AQ
484 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
485 list) {
486 list_del(&entry->list);
487 kfree(entry);
488 }
c6c8fea2 489
a73105b8
AQ
490 atomic_set(&bat_priv->tt_local_changes, 0);
491 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
492}
c6c8fea2 493
a73105b8
AQ
494/* caller must hold orig_node refcount */
495int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
bc279080
AQ
496 const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
497 bool wifi)
a73105b8
AQ
498{
499 struct tt_global_entry *tt_global_entry;
a73105b8 500 struct orig_node *orig_node_tmp;
7683fdc1 501 int ret = 0;
c6c8fea2 502
a73105b8
AQ
503 tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
504
505 if (!tt_global_entry) {
506 tt_global_entry =
507 kmalloc(sizeof(*tt_global_entry),
508 GFP_ATOMIC);
509 if (!tt_global_entry)
7683fdc1
AQ
510 goto out;
511
48100bac
AQ
512 memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
513 tt_global_entry->common.flags = NO_FLAGS;
514 atomic_set(&tt_global_entry->common.refcount, 2);
a73105b8
AQ
515 /* Assign the new orig_node */
516 atomic_inc(&orig_node->refcount);
2dafb49d 517 tt_global_entry->orig_node = orig_node;
a73105b8 518 tt_global_entry->ttvn = ttvn;
cc47f66e 519 tt_global_entry->roam_at = 0;
7683fdc1 520
48100bac
AQ
521 hash_add(bat_priv->tt_global_hash, compare_tt,
522 choose_orig, &tt_global_entry->common,
523 &tt_global_entry->common.hash_entry);
7683fdc1 524 atomic_inc(&orig_node->tt_size);
a73105b8
AQ
525 } else {
526 if (tt_global_entry->orig_node != orig_node) {
527 atomic_dec(&tt_global_entry->orig_node->tt_size);
528 orig_node_tmp = tt_global_entry->orig_node;
529 atomic_inc(&orig_node->refcount);
530 tt_global_entry->orig_node = orig_node;
a73105b8
AQ
531 orig_node_free_ref(orig_node_tmp);
532 atomic_inc(&orig_node->tt_size);
533 }
48100bac 534 tt_global_entry->common.flags = NO_FLAGS;
cc47f66e 535 tt_global_entry->ttvn = ttvn;
cc47f66e 536 tt_global_entry->roam_at = 0;
a73105b8 537 }
c6c8fea2 538
bc279080 539 if (wifi)
48100bac 540 tt_global_entry->common.flags |= TT_CLIENT_WIFI;
bc279080 541
a73105b8
AQ
542 bat_dbg(DBG_TT, bat_priv,
543 "Creating new global tt entry: %pM (via %pM)\n",
48100bac 544 tt_global_entry->common.addr, orig_node->orig);
c6c8fea2 545
a73105b8 546 /* remove address from local hash if present */
48100bac 547 tt_local_remove(bat_priv, tt_global_entry->common.addr,
7683fdc1
AQ
548 "global tt received", roaming);
549 ret = 1;
550out:
551 if (tt_global_entry)
552 tt_global_entry_free_ref(tt_global_entry);
553 return ret;
c6c8fea2
SE
554}
555
2dafb49d 556int tt_global_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea2
SE
557{
558 struct net_device *net_dev = (struct net_device *)seq->private;
559 struct bat_priv *bat_priv = netdev_priv(net_dev);
2dafb49d 560 struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac 561 struct tt_common_entry *tt_common_entry;
2dafb49d 562 struct tt_global_entry *tt_global_entry;
32ae9b22 563 struct hard_iface *primary_if;
7aadf889 564 struct hlist_node *node;
c6c8fea2 565 struct hlist_head *head;
c90681b8
AQ
566 uint32_t i;
567 int ret = 0;
32ae9b22
ML
568
569 primary_if = primary_if_get_selected(bat_priv);
570 if (!primary_if) {
571 ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
572 "specify interfaces to enable it\n",
573 net_dev->name);
574 goto out;
575 }
c6c8fea2 576
32ae9b22
ML
577 if (primary_if->if_status != IF_ACTIVE) {
578 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
579 "primary interface not active\n",
580 net_dev->name);
581 goto out;
c6c8fea2
SE
582 }
583
2dafb49d
AQ
584 seq_printf(seq,
585 "Globally announced TT entries received via the mesh %s\n",
c6c8fea2 586 net_dev->name);
df6edb9e
AQ
587 seq_printf(seq, " %-13s %s %-15s %s %s\n",
588 "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
c6c8fea2 589
c6c8fea2
SE
590 for (i = 0; i < hash->size; i++) {
591 head = &hash->table[i];
592
7aadf889 593 rcu_read_lock();
48100bac 594 hlist_for_each_entry_rcu(tt_common_entry, node,
7aadf889 595 head, hash_entry) {
48100bac
AQ
596 tt_global_entry = container_of(tt_common_entry,
597 struct tt_global_entry,
598 common);
d099c2c5 599 seq_printf(seq, " * %pM (%3u) via %pM (%3u) "
48100bac
AQ
600 "[%c%c%c]\n",
601 tt_global_entry->common.addr,
a73105b8
AQ
602 tt_global_entry->ttvn,
603 tt_global_entry->orig_node->orig,
604 (uint8_t) atomic_read(
605 &tt_global_entry->orig_node->
df6edb9e 606 last_ttvn),
48100bac 607 (tt_global_entry->common.flags &
df6edb9e 608 TT_CLIENT_ROAM ? 'R' : '.'),
48100bac 609 (tt_global_entry->common.flags &
df6edb9e 610 TT_CLIENT_PENDING ? 'X' : '.'),
48100bac 611 (tt_global_entry->common.flags &
df6edb9e 612 TT_CLIENT_WIFI ? 'W' : '.'));
c6c8fea2 613 }
7aadf889 614 rcu_read_unlock();
c6c8fea2 615 }
32ae9b22
ML
616out:
617 if (primary_if)
618 hardif_free_ref(primary_if);
619 return ret;
c6c8fea2
SE
620}
621
a73105b8
AQ
622static void _tt_global_del(struct bat_priv *bat_priv,
623 struct tt_global_entry *tt_global_entry,
624 const char *message)
c6c8fea2 625{
a73105b8 626 if (!tt_global_entry)
7683fdc1 627 goto out;
a73105b8
AQ
628
629 bat_dbg(DBG_TT, bat_priv,
2dafb49d 630 "Deleting global tt entry %pM (via %pM): %s\n",
48100bac 631 tt_global_entry->common.addr, tt_global_entry->orig_node->orig,
c6c8fea2
SE
632 message);
633
a73105b8 634 atomic_dec(&tt_global_entry->orig_node->tt_size);
7683fdc1 635
48100bac
AQ
636 hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
637 tt_global_entry->common.addr);
7683fdc1
AQ
638out:
639 if (tt_global_entry)
640 tt_global_entry_free_ref(tt_global_entry);
c6c8fea2
SE
641}
642
a73105b8
AQ
643void tt_global_del(struct bat_priv *bat_priv,
644 struct orig_node *orig_node, const unsigned char *addr,
cc47f66e 645 const char *message, bool roaming)
a73105b8 646{
7683fdc1 647 struct tt_global_entry *tt_global_entry = NULL;
a73105b8 648
a73105b8 649 tt_global_entry = tt_global_hash_find(bat_priv, addr);
7683fdc1
AQ
650 if (!tt_global_entry)
651 goto out;
a73105b8 652
7683fdc1 653 if (tt_global_entry->orig_node == orig_node) {
cc47f66e 654 if (roaming) {
48100bac 655 tt_global_entry->common.flags |= TT_CLIENT_ROAM;
cc47f66e
AQ
656 tt_global_entry->roam_at = jiffies;
657 goto out;
658 }
a73105b8
AQ
659 _tt_global_del(bat_priv, tt_global_entry, message);
660 }
cc47f66e 661out:
7683fdc1
AQ
662 if (tt_global_entry)
663 tt_global_entry_free_ref(tt_global_entry);
a73105b8
AQ
664}
665
2dafb49d 666void tt_global_del_orig(struct bat_priv *bat_priv,
a73105b8 667 struct orig_node *orig_node, const char *message)
c6c8fea2 668{
2dafb49d 669 struct tt_global_entry *tt_global_entry;
48100bac 670 struct tt_common_entry *tt_common_entry;
c90681b8 671 uint32_t i;
a73105b8
AQ
672 struct hashtable_t *hash = bat_priv->tt_global_hash;
673 struct hlist_node *node, *safe;
674 struct hlist_head *head;
7683fdc1 675 spinlock_t *list_lock; /* protects write access to the hash lists */
c6c8fea2 676
6e801494
SW
677 if (!hash)
678 return;
679
a73105b8
AQ
680 for (i = 0; i < hash->size; i++) {
681 head = &hash->table[i];
7683fdc1 682 list_lock = &hash->list_locks[i];
c6c8fea2 683
7683fdc1 684 spin_lock_bh(list_lock);
48100bac 685 hlist_for_each_entry_safe(tt_common_entry, node, safe,
a73105b8 686 head, hash_entry) {
48100bac
AQ
687 tt_global_entry = container_of(tt_common_entry,
688 struct tt_global_entry,
689 common);
7683fdc1
AQ
690 if (tt_global_entry->orig_node == orig_node) {
691 bat_dbg(DBG_TT, bat_priv,
692 "Deleting global tt entry %pM "
87944973 693 "(via %pM): %s\n",
48100bac 694 tt_global_entry->common.addr,
87944973
AQ
695 tt_global_entry->orig_node->orig,
696 message);
7683fdc1
AQ
697 hlist_del_rcu(node);
698 tt_global_entry_free_ref(tt_global_entry);
699 }
a73105b8 700 }
7683fdc1 701 spin_unlock_bh(list_lock);
c6c8fea2 702 }
a73105b8 703 atomic_set(&orig_node->tt_size, 0);
c6c8fea2
SE
704}
705
cc47f66e
AQ
706static void tt_global_roam_purge(struct bat_priv *bat_priv)
707{
708 struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac 709 struct tt_common_entry *tt_common_entry;
cc47f66e
AQ
710 struct tt_global_entry *tt_global_entry;
711 struct hlist_node *node, *node_tmp;
712 struct hlist_head *head;
7683fdc1 713 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 714 uint32_t i;
cc47f66e 715
cc47f66e
AQ
716 for (i = 0; i < hash->size; i++) {
717 head = &hash->table[i];
7683fdc1 718 list_lock = &hash->list_locks[i];
cc47f66e 719
7683fdc1 720 spin_lock_bh(list_lock);
48100bac 721 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
cc47f66e 722 head, hash_entry) {
48100bac
AQ
723 tt_global_entry = container_of(tt_common_entry,
724 struct tt_global_entry,
725 common);
726 if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
cc47f66e
AQ
727 continue;
728 if (!is_out_of_time(tt_global_entry->roam_at,
729 TT_CLIENT_ROAM_TIMEOUT * 1000))
730 continue;
731
7683fdc1
AQ
732 bat_dbg(DBG_TT, bat_priv, "Deleting global "
733 "tt entry (%pM): Roaming timeout\n",
48100bac 734 tt_global_entry->common.addr);
7683fdc1
AQ
735 atomic_dec(&tt_global_entry->orig_node->tt_size);
736 hlist_del_rcu(node);
737 tt_global_entry_free_ref(tt_global_entry);
cc47f66e 738 }
7683fdc1 739 spin_unlock_bh(list_lock);
cc47f66e
AQ
740 }
741
cc47f66e
AQ
742}
743
a73105b8 744static void tt_global_table_free(struct bat_priv *bat_priv)
c6c8fea2 745{
7683fdc1
AQ
746 struct hashtable_t *hash;
747 spinlock_t *list_lock; /* protects write access to the hash lists */
48100bac 748 struct tt_common_entry *tt_common_entry;
7683fdc1
AQ
749 struct tt_global_entry *tt_global_entry;
750 struct hlist_node *node, *node_tmp;
751 struct hlist_head *head;
c90681b8 752 uint32_t i;
7683fdc1 753
2dafb49d 754 if (!bat_priv->tt_global_hash)
c6c8fea2
SE
755 return;
756
7683fdc1
AQ
757 hash = bat_priv->tt_global_hash;
758
759 for (i = 0; i < hash->size; i++) {
760 head = &hash->table[i];
761 list_lock = &hash->list_locks[i];
762
763 spin_lock_bh(list_lock);
48100bac 764 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
7683fdc1
AQ
765 head, hash_entry) {
766 hlist_del_rcu(node);
48100bac
AQ
767 tt_global_entry = container_of(tt_common_entry,
768 struct tt_global_entry,
769 common);
7683fdc1
AQ
770 tt_global_entry_free_ref(tt_global_entry);
771 }
772 spin_unlock_bh(list_lock);
773 }
774
775 hash_destroy(hash);
776
2dafb49d 777 bat_priv->tt_global_hash = NULL;
c6c8fea2
SE
778}
779
59b699cd
AQ
780static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
781 struct tt_global_entry *tt_global_entry)
782{
783 bool ret = false;
784
48100bac
AQ
785 if (tt_local_entry->common.flags & TT_CLIENT_WIFI &&
786 tt_global_entry->common.flags & TT_CLIENT_WIFI)
59b699cd
AQ
787 ret = true;
788
789 return ret;
790}
791
747e4221 792struct orig_node *transtable_search(struct bat_priv *bat_priv,
3d393e47 793 const uint8_t *src, const uint8_t *addr)
c6c8fea2 794{
3d393e47
AQ
795 struct tt_local_entry *tt_local_entry = NULL;
796 struct tt_global_entry *tt_global_entry = NULL;
7b36e8ee 797 struct orig_node *orig_node = NULL;
c6c8fea2 798
3d393e47
AQ
799 if (src && atomic_read(&bat_priv->ap_isolation)) {
800 tt_local_entry = tt_local_hash_find(bat_priv, src);
801 if (!tt_local_entry)
802 goto out;
803 }
7aadf889 804
3d393e47 805 tt_global_entry = tt_global_hash_find(bat_priv, addr);
2dafb49d 806 if (!tt_global_entry)
7b36e8ee 807 goto out;
7aadf889 808
3d393e47
AQ
809 /* check whether the clients should not communicate due to AP
810 * isolation */
811 if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
812 goto out;
813
2dafb49d 814 if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
3d393e47 815 goto out;
c6c8fea2 816
980d55b2
AQ
817 /* A global client marked as PENDING has already moved from that
818 * originator */
48100bac 819 if (tt_global_entry->common.flags & TT_CLIENT_PENDING)
3d393e47 820 goto out;
980d55b2 821
2dafb49d 822 orig_node = tt_global_entry->orig_node;
c6c8fea2 823
7b36e8ee 824out:
3d393e47
AQ
825 if (tt_global_entry)
826 tt_global_entry_free_ref(tt_global_entry);
827 if (tt_local_entry)
828 tt_local_entry_free_ref(tt_local_entry);
829
7b36e8ee 830 return orig_node;
c6c8fea2 831}
a73105b8
AQ
832
833/* Calculates the checksum of the local table of a given orig_node */
834uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
835{
836 uint16_t total = 0, total_one;
837 struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac 838 struct tt_common_entry *tt_common_entry;
a73105b8
AQ
839 struct tt_global_entry *tt_global_entry;
840 struct hlist_node *node;
841 struct hlist_head *head;
c90681b8
AQ
842 uint32_t i;
843 int j;
a73105b8
AQ
844
845 for (i = 0; i < hash->size; i++) {
846 head = &hash->table[i];
847
848 rcu_read_lock();
48100bac 849 hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8 850 head, hash_entry) {
48100bac
AQ
851 tt_global_entry = container_of(tt_common_entry,
852 struct tt_global_entry,
853 common);
a73105b8
AQ
854 if (compare_eth(tt_global_entry->orig_node,
855 orig_node)) {
cc47f66e
AQ
856 /* Roaming clients are in the global table for
857 * consistency only. They don't have to be
858 * taken into account while computing the
859 * global crc */
48100bac 860 if (tt_common_entry->flags & TT_CLIENT_ROAM)
cc47f66e 861 continue;
a73105b8
AQ
862 total_one = 0;
863 for (j = 0; j < ETH_ALEN; j++)
864 total_one = crc16_byte(total_one,
48100bac 865 tt_common_entry->addr[j]);
a73105b8
AQ
866 total ^= total_one;
867 }
868 }
869 rcu_read_unlock();
870 }
871
872 return total;
873}
874
875/* Calculates the checksum of the local table */
876uint16_t tt_local_crc(struct bat_priv *bat_priv)
877{
878 uint16_t total = 0, total_one;
879 struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac 880 struct tt_common_entry *tt_common_entry;
a73105b8
AQ
881 struct hlist_node *node;
882 struct hlist_head *head;
c90681b8
AQ
883 uint32_t i;
884 int j;
a73105b8
AQ
885
886 for (i = 0; i < hash->size; i++) {
887 head = &hash->table[i];
888
889 rcu_read_lock();
48100bac 890 hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8 891 head, hash_entry) {
058d0e26
AQ
892 /* not yet committed clients have not to be taken into
893 * account while computing the CRC */
48100bac 894 if (tt_common_entry->flags & TT_CLIENT_NEW)
058d0e26 895 continue;
a73105b8
AQ
896 total_one = 0;
897 for (j = 0; j < ETH_ALEN; j++)
898 total_one = crc16_byte(total_one,
48100bac 899 tt_common_entry->addr[j]);
a73105b8
AQ
900 total ^= total_one;
901 }
a73105b8
AQ
902 rcu_read_unlock();
903 }
904
905 return total;
906}
907
908static void tt_req_list_free(struct bat_priv *bat_priv)
909{
910 struct tt_req_node *node, *safe;
911
912 spin_lock_bh(&bat_priv->tt_req_list_lock);
913
914 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
915 list_del(&node->list);
916 kfree(node);
917 }
918
919 spin_unlock_bh(&bat_priv->tt_req_list_lock);
920}
921
922void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
923 const unsigned char *tt_buff, uint8_t tt_num_changes)
924{
925 uint16_t tt_buff_len = tt_len(tt_num_changes);
926
927 /* Replace the old buffer only if I received something in the
928 * last OGM (the OGM could carry no changes) */
929 spin_lock_bh(&orig_node->tt_buff_lock);
930 if (tt_buff_len > 0) {
931 kfree(orig_node->tt_buff);
932 orig_node->tt_buff_len = 0;
933 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
934 if (orig_node->tt_buff) {
935 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
936 orig_node->tt_buff_len = tt_buff_len;
937 }
938 }
939 spin_unlock_bh(&orig_node->tt_buff_lock);
940}
941
942static void tt_req_purge(struct bat_priv *bat_priv)
943{
944 struct tt_req_node *node, *safe;
945
946 spin_lock_bh(&bat_priv->tt_req_list_lock);
947 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
948 if (is_out_of_time(node->issued_at,
949 TT_REQUEST_TIMEOUT * 1000)) {
950 list_del(&node->list);
951 kfree(node);
952 }
953 }
954 spin_unlock_bh(&bat_priv->tt_req_list_lock);
955}
956
957/* returns the pointer to the new tt_req_node struct if no request
958 * has already been issued for this orig_node, NULL otherwise */
959static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
960 struct orig_node *orig_node)
961{
962 struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
963
964 spin_lock_bh(&bat_priv->tt_req_list_lock);
965 list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
966 if (compare_eth(tt_req_node_tmp, orig_node) &&
967 !is_out_of_time(tt_req_node_tmp->issued_at,
968 TT_REQUEST_TIMEOUT * 1000))
969 goto unlock;
970 }
971
972 tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
973 if (!tt_req_node)
974 goto unlock;
975
976 memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
977 tt_req_node->issued_at = jiffies;
978
979 list_add(&tt_req_node->list, &bat_priv->tt_req_list);
980unlock:
981 spin_unlock_bh(&bat_priv->tt_req_list_lock);
982 return tt_req_node;
983}
984
058d0e26
AQ
985/* data_ptr is useless here, but has to be kept to respect the prototype */
986static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
987{
48100bac 988 const struct tt_common_entry *tt_common_entry = entry_ptr;
058d0e26 989
48100bac 990 if (tt_common_entry->flags & TT_CLIENT_NEW)
058d0e26
AQ
991 return 0;
992 return 1;
993}
994
a73105b8
AQ
995static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
996{
48100bac
AQ
997 const struct tt_common_entry *tt_common_entry = entry_ptr;
998 const struct tt_global_entry *tt_global_entry;
a73105b8
AQ
999 const struct orig_node *orig_node = data_ptr;
1000
48100bac 1001 if (tt_common_entry->flags & TT_CLIENT_ROAM)
cc47f66e
AQ
1002 return 0;
1003
48100bac
AQ
1004 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
1005 common);
1006
a73105b8
AQ
1007 return (tt_global_entry->orig_node == orig_node);
1008}
1009
1010static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
1011 struct hashtable_t *hash,
1012 struct hard_iface *primary_if,
1013 int (*valid_cb)(const void *,
1014 const void *),
1015 void *cb_data)
1016{
48100bac 1017 struct tt_common_entry *tt_common_entry;
a73105b8
AQ
1018 struct tt_query_packet *tt_response;
1019 struct tt_change *tt_change;
1020 struct hlist_node *node;
1021 struct hlist_head *head;
1022 struct sk_buff *skb = NULL;
1023 uint16_t tt_tot, tt_count;
1024 ssize_t tt_query_size = sizeof(struct tt_query_packet);
c90681b8 1025 uint32_t i;
a73105b8
AQ
1026
1027 if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
1028 tt_len = primary_if->soft_iface->mtu - tt_query_size;
1029 tt_len -= tt_len % sizeof(struct tt_change);
1030 }
1031 tt_tot = tt_len / sizeof(struct tt_change);
1032
1033 skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
1034 if (!skb)
1035 goto out;
1036
1037 skb_reserve(skb, ETH_HLEN);
1038 tt_response = (struct tt_query_packet *)skb_put(skb,
1039 tt_query_size + tt_len);
1040 tt_response->ttvn = ttvn;
a73105b8
AQ
1041
1042 tt_change = (struct tt_change *)(skb->data + tt_query_size);
1043 tt_count = 0;
1044
1045 rcu_read_lock();
1046 for (i = 0; i < hash->size; i++) {
1047 head = &hash->table[i];
1048
48100bac 1049 hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8
AQ
1050 head, hash_entry) {
1051 if (tt_count == tt_tot)
1052 break;
1053
48100bac 1054 if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
a73105b8
AQ
1055 continue;
1056
48100bac
AQ
1057 memcpy(tt_change->addr, tt_common_entry->addr,
1058 ETH_ALEN);
a73105b8
AQ
1059 tt_change->flags = NO_FLAGS;
1060
1061 tt_count++;
1062 tt_change++;
1063 }
1064 }
1065 rcu_read_unlock();
1066
9d852393
AQ
1067 /* store in the message the number of entries we have successfully
1068 * copied */
1069 tt_response->tt_data = htons(tt_count);
1070
a73105b8
AQ
1071out:
1072 return skb;
1073}
1074
a943cac1
ML
1075static int send_tt_request(struct bat_priv *bat_priv,
1076 struct orig_node *dst_orig_node,
1077 uint8_t ttvn, uint16_t tt_crc, bool full_table)
a73105b8
AQ
1078{
1079 struct sk_buff *skb = NULL;
1080 struct tt_query_packet *tt_request;
1081 struct neigh_node *neigh_node = NULL;
1082 struct hard_iface *primary_if;
1083 struct tt_req_node *tt_req_node = NULL;
1084 int ret = 1;
1085
1086 primary_if = primary_if_get_selected(bat_priv);
1087 if (!primary_if)
1088 goto out;
1089
1090 /* The new tt_req will be issued only if I'm not waiting for a
1091 * reply from the same orig_node yet */
1092 tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
1093 if (!tt_req_node)
1094 goto out;
1095
1096 skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
1097 if (!skb)
1098 goto out;
1099
1100 skb_reserve(skb, ETH_HLEN);
1101
1102 tt_request = (struct tt_query_packet *)skb_put(skb,
1103 sizeof(struct tt_query_packet));
1104
1105 tt_request->packet_type = BAT_TT_QUERY;
1106 tt_request->version = COMPAT_VERSION;
1107 memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1108 memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
1109 tt_request->ttl = TTL;
1110 tt_request->ttvn = ttvn;
1111 tt_request->tt_data = tt_crc;
1112 tt_request->flags = TT_REQUEST;
1113
1114 if (full_table)
1115 tt_request->flags |= TT_FULL_TABLE;
1116
1117 neigh_node = orig_node_get_router(dst_orig_node);
1118 if (!neigh_node)
1119 goto out;
1120
1121 bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
1122 "[%c]\n", dst_orig_node->orig, neigh_node->addr,
1123 (full_table ? 'F' : '.'));
1124
1125 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1126 ret = 0;
1127
1128out:
1129 if (neigh_node)
1130 neigh_node_free_ref(neigh_node);
1131 if (primary_if)
1132 hardif_free_ref(primary_if);
1133 if (ret)
1134 kfree_skb(skb);
1135 if (ret && tt_req_node) {
1136 spin_lock_bh(&bat_priv->tt_req_list_lock);
1137 list_del(&tt_req_node->list);
1138 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1139 kfree(tt_req_node);
1140 }
1141 return ret;
1142}
1143
1144static bool send_other_tt_response(struct bat_priv *bat_priv,
1145 struct tt_query_packet *tt_request)
1146{
1147 struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
1148 struct neigh_node *neigh_node = NULL;
1149 struct hard_iface *primary_if = NULL;
1150 uint8_t orig_ttvn, req_ttvn, ttvn;
1151 int ret = false;
1152 unsigned char *tt_buff;
1153 bool full_table;
1154 uint16_t tt_len, tt_tot;
1155 struct sk_buff *skb = NULL;
1156 struct tt_query_packet *tt_response;
1157
1158 bat_dbg(DBG_TT, bat_priv,
1159 "Received TT_REQUEST from %pM for "
1160 "ttvn: %u (%pM) [%c]\n", tt_request->src,
1161 tt_request->ttvn, tt_request->dst,
1162 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1163
1164 /* Let's get the orig node of the REAL destination */
eb7e2a1e 1165 req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst);
a73105b8
AQ
1166 if (!req_dst_orig_node)
1167 goto out;
1168
eb7e2a1e 1169 res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src);
a73105b8
AQ
1170 if (!res_dst_orig_node)
1171 goto out;
1172
1173 neigh_node = orig_node_get_router(res_dst_orig_node);
1174 if (!neigh_node)
1175 goto out;
1176
1177 primary_if = primary_if_get_selected(bat_priv);
1178 if (!primary_if)
1179 goto out;
1180
1181 orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1182 req_ttvn = tt_request->ttvn;
1183
015758d0 1184 /* I don't have the requested data */
a73105b8
AQ
1185 if (orig_ttvn != req_ttvn ||
1186 tt_request->tt_data != req_dst_orig_node->tt_crc)
1187 goto out;
1188
015758d0 1189 /* If the full table has been explicitly requested */
a73105b8
AQ
1190 if (tt_request->flags & TT_FULL_TABLE ||
1191 !req_dst_orig_node->tt_buff)
1192 full_table = true;
1193 else
1194 full_table = false;
1195
1196 /* In this version, fragmentation is not implemented, then
1197 * I'll send only one packet with as much TT entries as I can */
1198 if (!full_table) {
1199 spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1200 tt_len = req_dst_orig_node->tt_buff_len;
1201 tt_tot = tt_len / sizeof(struct tt_change);
1202
1203 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1204 tt_len + ETH_HLEN);
1205 if (!skb)
1206 goto unlock;
1207
1208 skb_reserve(skb, ETH_HLEN);
1209 tt_response = (struct tt_query_packet *)skb_put(skb,
1210 sizeof(struct tt_query_packet) + tt_len);
1211 tt_response->ttvn = req_ttvn;
1212 tt_response->tt_data = htons(tt_tot);
1213
1214 tt_buff = skb->data + sizeof(struct tt_query_packet);
1215 /* Copy the last orig_node's OGM buffer */
1216 memcpy(tt_buff, req_dst_orig_node->tt_buff,
1217 req_dst_orig_node->tt_buff_len);
1218
1219 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1220 } else {
1221 tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
1222 sizeof(struct tt_change);
1223 ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1224
1225 skb = tt_response_fill_table(tt_len, ttvn,
1226 bat_priv->tt_global_hash,
1227 primary_if, tt_global_valid_entry,
1228 req_dst_orig_node);
1229 if (!skb)
1230 goto out;
1231
1232 tt_response = (struct tt_query_packet *)skb->data;
1233 }
1234
1235 tt_response->packet_type = BAT_TT_QUERY;
1236 tt_response->version = COMPAT_VERSION;
1237 tt_response->ttl = TTL;
1238 memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
1239 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1240 tt_response->flags = TT_RESPONSE;
1241
1242 if (full_table)
1243 tt_response->flags |= TT_FULL_TABLE;
1244
1245 bat_dbg(DBG_TT, bat_priv,
1246 "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
1247 res_dst_orig_node->orig, neigh_node->addr,
1248 req_dst_orig_node->orig, req_ttvn);
1249
1250 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1251 ret = true;
1252 goto out;
1253
1254unlock:
1255 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1256
1257out:
1258 if (res_dst_orig_node)
1259 orig_node_free_ref(res_dst_orig_node);
1260 if (req_dst_orig_node)
1261 orig_node_free_ref(req_dst_orig_node);
1262 if (neigh_node)
1263 neigh_node_free_ref(neigh_node);
1264 if (primary_if)
1265 hardif_free_ref(primary_if);
1266 if (!ret)
1267 kfree_skb(skb);
1268 return ret;
1269
1270}
1271static bool send_my_tt_response(struct bat_priv *bat_priv,
1272 struct tt_query_packet *tt_request)
1273{
1274 struct orig_node *orig_node = NULL;
1275 struct neigh_node *neigh_node = NULL;
1276 struct hard_iface *primary_if = NULL;
1277 uint8_t my_ttvn, req_ttvn, ttvn;
1278 int ret = false;
1279 unsigned char *tt_buff;
1280 bool full_table;
1281 uint16_t tt_len, tt_tot;
1282 struct sk_buff *skb = NULL;
1283 struct tt_query_packet *tt_response;
1284
1285 bat_dbg(DBG_TT, bat_priv,
1286 "Received TT_REQUEST from %pM for "
1287 "ttvn: %u (me) [%c]\n", tt_request->src,
1288 tt_request->ttvn,
1289 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1290
1291
1292 my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1293 req_ttvn = tt_request->ttvn;
1294
eb7e2a1e 1295 orig_node = orig_hash_find(bat_priv, tt_request->src);
a73105b8
AQ
1296 if (!orig_node)
1297 goto out;
1298
1299 neigh_node = orig_node_get_router(orig_node);
1300 if (!neigh_node)
1301 goto out;
1302
1303 primary_if = primary_if_get_selected(bat_priv);
1304 if (!primary_if)
1305 goto out;
1306
1307 /* If the full table has been explicitly requested or the gap
1308 * is too big send the whole local translation table */
1309 if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
1310 !bat_priv->tt_buff)
1311 full_table = true;
1312 else
1313 full_table = false;
1314
1315 /* In this version, fragmentation is not implemented, then
1316 * I'll send only one packet with as much TT entries as I can */
1317 if (!full_table) {
1318 spin_lock_bh(&bat_priv->tt_buff_lock);
1319 tt_len = bat_priv->tt_buff_len;
1320 tt_tot = tt_len / sizeof(struct tt_change);
1321
1322 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1323 tt_len + ETH_HLEN);
1324 if (!skb)
1325 goto unlock;
1326
1327 skb_reserve(skb, ETH_HLEN);
1328 tt_response = (struct tt_query_packet *)skb_put(skb,
1329 sizeof(struct tt_query_packet) + tt_len);
1330 tt_response->ttvn = req_ttvn;
1331 tt_response->tt_data = htons(tt_tot);
1332
1333 tt_buff = skb->data + sizeof(struct tt_query_packet);
1334 memcpy(tt_buff, bat_priv->tt_buff,
1335 bat_priv->tt_buff_len);
1336 spin_unlock_bh(&bat_priv->tt_buff_lock);
1337 } else {
1338 tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
1339 sizeof(struct tt_change);
1340 ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1341
1342 skb = tt_response_fill_table(tt_len, ttvn,
1343 bat_priv->tt_local_hash,
058d0e26
AQ
1344 primary_if, tt_local_valid_entry,
1345 NULL);
a73105b8
AQ
1346 if (!skb)
1347 goto out;
1348
1349 tt_response = (struct tt_query_packet *)skb->data;
1350 }
1351
1352 tt_response->packet_type = BAT_TT_QUERY;
1353 tt_response->version = COMPAT_VERSION;
1354 tt_response->ttl = TTL;
1355 memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1356 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1357 tt_response->flags = TT_RESPONSE;
1358
1359 if (full_table)
1360 tt_response->flags |= TT_FULL_TABLE;
1361
1362 bat_dbg(DBG_TT, bat_priv,
1363 "Sending TT_RESPONSE to %pM via %pM [%c]\n",
1364 orig_node->orig, neigh_node->addr,
1365 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1366
1367 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1368 ret = true;
1369 goto out;
1370
1371unlock:
1372 spin_unlock_bh(&bat_priv->tt_buff_lock);
1373out:
1374 if (orig_node)
1375 orig_node_free_ref(orig_node);
1376 if (neigh_node)
1377 neigh_node_free_ref(neigh_node);
1378 if (primary_if)
1379 hardif_free_ref(primary_if);
1380 if (!ret)
1381 kfree_skb(skb);
1382 /* This packet was for me, so it doesn't need to be re-routed */
1383 return true;
1384}
1385
1386bool send_tt_response(struct bat_priv *bat_priv,
1387 struct tt_query_packet *tt_request)
1388{
1389 if (is_my_mac(tt_request->dst))
1390 return send_my_tt_response(bat_priv, tt_request);
1391 else
1392 return send_other_tt_response(bat_priv, tt_request);
1393}
1394
1395static void _tt_update_changes(struct bat_priv *bat_priv,
1396 struct orig_node *orig_node,
1397 struct tt_change *tt_change,
1398 uint16_t tt_num_changes, uint8_t ttvn)
1399{
1400 int i;
1401
1402 for (i = 0; i < tt_num_changes; i++) {
5fbc1598 1403 if ((tt_change + i)->flags & TT_CLIENT_DEL)
a73105b8
AQ
1404 tt_global_del(bat_priv, orig_node,
1405 (tt_change + i)->addr,
cc47f66e
AQ
1406 "tt removed by changes",
1407 (tt_change + i)->flags & TT_CLIENT_ROAM);
a73105b8
AQ
1408 else
1409 if (!tt_global_add(bat_priv, orig_node,
bc279080
AQ
1410 (tt_change + i)->addr, ttvn, false,
1411 (tt_change + i)->flags &
1412 TT_CLIENT_WIFI))
a73105b8
AQ
1413 /* In case of problem while storing a
1414 * global_entry, we stop the updating
1415 * procedure without committing the
1416 * ttvn change. This will avoid to send
1417 * corrupted data on tt_request
1418 */
1419 return;
1420 }
1421}
1422
1423static void tt_fill_gtable(struct bat_priv *bat_priv,
1424 struct tt_query_packet *tt_response)
1425{
1426 struct orig_node *orig_node = NULL;
1427
1428 orig_node = orig_hash_find(bat_priv, tt_response->src);
1429 if (!orig_node)
1430 goto out;
1431
1432 /* Purge the old table first.. */
1433 tt_global_del_orig(bat_priv, orig_node, "Received full table");
1434
1435 _tt_update_changes(bat_priv, orig_node,
1436 (struct tt_change *)(tt_response + 1),
1437 tt_response->tt_data, tt_response->ttvn);
1438
1439 spin_lock_bh(&orig_node->tt_buff_lock);
1440 kfree(orig_node->tt_buff);
1441 orig_node->tt_buff_len = 0;
1442 orig_node->tt_buff = NULL;
1443 spin_unlock_bh(&orig_node->tt_buff_lock);
1444
1445 atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
1446
1447out:
1448 if (orig_node)
1449 orig_node_free_ref(orig_node);
1450}
1451
a943cac1
ML
1452static void tt_update_changes(struct bat_priv *bat_priv,
1453 struct orig_node *orig_node,
1454 uint16_t tt_num_changes, uint8_t ttvn,
1455 struct tt_change *tt_change)
a73105b8
AQ
1456{
1457 _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
1458 ttvn);
1459
1460 tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
1461 tt_num_changes);
1462 atomic_set(&orig_node->last_ttvn, ttvn);
1463}
1464
1465bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
1466{
7683fdc1
AQ
1467 struct tt_local_entry *tt_local_entry = NULL;
1468 bool ret = false;
a73105b8 1469
a73105b8 1470 tt_local_entry = tt_local_hash_find(bat_priv, addr);
7683fdc1
AQ
1471 if (!tt_local_entry)
1472 goto out;
058d0e26
AQ
1473 /* Check if the client has been logically deleted (but is kept for
1474 * consistency purpose) */
48100bac 1475 if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
058d0e26 1476 goto out;
7683fdc1
AQ
1477 ret = true;
1478out:
a73105b8 1479 if (tt_local_entry)
7683fdc1
AQ
1480 tt_local_entry_free_ref(tt_local_entry);
1481 return ret;
a73105b8
AQ
1482}
1483
1484void handle_tt_response(struct bat_priv *bat_priv,
1485 struct tt_query_packet *tt_response)
1486{
1487 struct tt_req_node *node, *safe;
1488 struct orig_node *orig_node = NULL;
1489
1490 bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
1491 "ttvn %d t_size: %d [%c]\n",
1492 tt_response->src, tt_response->ttvn,
1493 tt_response->tt_data,
1494 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1495
1496 orig_node = orig_hash_find(bat_priv, tt_response->src);
1497 if (!orig_node)
1498 goto out;
1499
1500 if (tt_response->flags & TT_FULL_TABLE)
1501 tt_fill_gtable(bat_priv, tt_response);
1502 else
1503 tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
1504 tt_response->ttvn,
1505 (struct tt_change *)(tt_response + 1));
1506
1507 /* Delete the tt_req_node from pending tt_requests list */
1508 spin_lock_bh(&bat_priv->tt_req_list_lock);
1509 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1510 if (!compare_eth(node->addr, tt_response->src))
1511 continue;
1512 list_del(&node->list);
1513 kfree(node);
1514 }
1515 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1516
1517 /* Recalculate the CRC for this orig_node and store it */
a73105b8 1518 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
cc47f66e
AQ
1519 /* Roaming phase is over: tables are in sync again. I can
1520 * unset the flag */
1521 orig_node->tt_poss_change = false;
a73105b8
AQ
1522out:
1523 if (orig_node)
1524 orig_node_free_ref(orig_node);
1525}
1526
1527int tt_init(struct bat_priv *bat_priv)
1528{
1529 if (!tt_local_init(bat_priv))
1530 return 0;
1531
1532 if (!tt_global_init(bat_priv))
1533 return 0;
1534
1535 tt_start_timer(bat_priv);
1536
1537 return 1;
1538}
1539
cc47f66e 1540static void tt_roam_list_free(struct bat_priv *bat_priv)
a73105b8 1541{
cc47f66e 1542 struct tt_roam_node *node, *safe;
a73105b8 1543
cc47f66e 1544 spin_lock_bh(&bat_priv->tt_roam_list_lock);
a73105b8 1545
cc47f66e
AQ
1546 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1547 list_del(&node->list);
1548 kfree(node);
1549 }
1550
1551 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1552}
1553
1554static void tt_roam_purge(struct bat_priv *bat_priv)
1555{
1556 struct tt_roam_node *node, *safe;
1557
1558 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1559 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1560 if (!is_out_of_time(node->first_time,
1561 ROAMING_MAX_TIME * 1000))
1562 continue;
1563
1564 list_del(&node->list);
1565 kfree(node);
1566 }
1567 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1568}
1569
1570/* This function checks whether the client already reached the
1571 * maximum number of possible roaming phases. In this case the ROAMING_ADV
1572 * will not be sent.
1573 *
1574 * returns true if the ROAMING_ADV can be sent, false otherwise */
1575static bool tt_check_roam_count(struct bat_priv *bat_priv,
1576 uint8_t *client)
1577{
1578 struct tt_roam_node *tt_roam_node;
1579 bool ret = false;
1580
1581 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1582 /* The new tt_req will be issued only if I'm not waiting for a
1583 * reply from the same orig_node yet */
1584 list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
1585 if (!compare_eth(tt_roam_node->addr, client))
1586 continue;
1587
1588 if (is_out_of_time(tt_roam_node->first_time,
1589 ROAMING_MAX_TIME * 1000))
1590 continue;
1591
1592 if (!atomic_dec_not_zero(&tt_roam_node->counter))
1593 /* Sorry, you roamed too many times! */
1594 goto unlock;
1595 ret = true;
1596 break;
1597 }
1598
1599 if (!ret) {
1600 tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
1601 if (!tt_roam_node)
1602 goto unlock;
1603
1604 tt_roam_node->first_time = jiffies;
1605 atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
1606 memcpy(tt_roam_node->addr, client, ETH_ALEN);
1607
1608 list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
1609 ret = true;
1610 }
1611
1612unlock:
1613 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1614 return ret;
1615}
1616
1617void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
1618 struct orig_node *orig_node)
1619{
1620 struct neigh_node *neigh_node = NULL;
1621 struct sk_buff *skb = NULL;
1622 struct roam_adv_packet *roam_adv_packet;
1623 int ret = 1;
1624 struct hard_iface *primary_if;
1625
1626 /* before going on we have to check whether the client has
1627 * already roamed to us too many times */
1628 if (!tt_check_roam_count(bat_priv, client))
1629 goto out;
1630
1631 skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
1632 if (!skb)
1633 goto out;
1634
1635 skb_reserve(skb, ETH_HLEN);
1636
1637 roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
1638 sizeof(struct roam_adv_packet));
1639
1640 roam_adv_packet->packet_type = BAT_ROAM_ADV;
1641 roam_adv_packet->version = COMPAT_VERSION;
1642 roam_adv_packet->ttl = TTL;
1643 primary_if = primary_if_get_selected(bat_priv);
1644 if (!primary_if)
1645 goto out;
1646 memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1647 hardif_free_ref(primary_if);
1648 memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
1649 memcpy(roam_adv_packet->client, client, ETH_ALEN);
1650
1651 neigh_node = orig_node_get_router(orig_node);
1652 if (!neigh_node)
1653 goto out;
1654
1655 bat_dbg(DBG_TT, bat_priv,
1656 "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
1657 orig_node->orig, client, neigh_node->addr);
1658
1659 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1660 ret = 0;
1661
1662out:
1663 if (neigh_node)
1664 neigh_node_free_ref(neigh_node);
1665 if (ret)
1666 kfree_skb(skb);
1667 return;
a73105b8
AQ
1668}
1669
1670static void tt_purge(struct work_struct *work)
1671{
1672 struct delayed_work *delayed_work =
1673 container_of(work, struct delayed_work, work);
1674 struct bat_priv *bat_priv =
1675 container_of(delayed_work, struct bat_priv, tt_work);
1676
1677 tt_local_purge(bat_priv);
cc47f66e 1678 tt_global_roam_purge(bat_priv);
a73105b8 1679 tt_req_purge(bat_priv);
cc47f66e 1680 tt_roam_purge(bat_priv);
a73105b8
AQ
1681
1682 tt_start_timer(bat_priv);
1683}
cc47f66e
AQ
1684
1685void tt_free(struct bat_priv *bat_priv)
1686{
1687 cancel_delayed_work_sync(&bat_priv->tt_work);
1688
1689 tt_local_table_free(bat_priv);
1690 tt_global_table_free(bat_priv);
1691 tt_req_list_free(bat_priv);
1692 tt_changes_list_free(bat_priv);
1693 tt_roam_list_free(bat_priv);
1694
1695 kfree(bat_priv->tt_buff);
1696}
058d0e26 1697
697f2531
AQ
1698/* This function will enable or disable the specified flags for all the entries
1699 * in the given hash table and returns the number of modified entries */
1700static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags,
1701 bool enable)
058d0e26 1702{
c90681b8 1703 uint32_t i;
697f2531 1704 uint16_t changed_num = 0;
058d0e26
AQ
1705 struct hlist_head *head;
1706 struct hlist_node *node;
48100bac 1707 struct tt_common_entry *tt_common_entry;
058d0e26
AQ
1708
1709 if (!hash)
697f2531 1710 goto out;
058d0e26
AQ
1711
1712 for (i = 0; i < hash->size; i++) {
1713 head = &hash->table[i];
1714
1715 rcu_read_lock();
48100bac 1716 hlist_for_each_entry_rcu(tt_common_entry, node,
058d0e26 1717 head, hash_entry) {
697f2531
AQ
1718 if (enable) {
1719 if ((tt_common_entry->flags & flags) == flags)
1720 continue;
1721 tt_common_entry->flags |= flags;
1722 } else {
1723 if (!(tt_common_entry->flags & flags))
1724 continue;
1725 tt_common_entry->flags &= ~flags;
1726 }
1727 changed_num++;
058d0e26
AQ
1728 }
1729 rcu_read_unlock();
1730 }
697f2531
AQ
1731out:
1732 return changed_num;
058d0e26
AQ
1733}
1734
1735/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
1736static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
1737{
1738 struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac 1739 struct tt_common_entry *tt_common_entry;
058d0e26
AQ
1740 struct tt_local_entry *tt_local_entry;
1741 struct hlist_node *node, *node_tmp;
1742 struct hlist_head *head;
1743 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 1744 uint32_t i;
058d0e26
AQ
1745
1746 if (!hash)
1747 return;
1748
1749 for (i = 0; i < hash->size; i++) {
1750 head = &hash->table[i];
1751 list_lock = &hash->list_locks[i];
1752
1753 spin_lock_bh(list_lock);
48100bac 1754 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
058d0e26 1755 head, hash_entry) {
48100bac 1756 if (!(tt_common_entry->flags & TT_CLIENT_PENDING))
058d0e26
AQ
1757 continue;
1758
1759 bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
48100bac 1760 "(%pM): pending\n", tt_common_entry->addr);
058d0e26
AQ
1761
1762 atomic_dec(&bat_priv->num_local_tt);
1763 hlist_del_rcu(node);
48100bac
AQ
1764 tt_local_entry = container_of(tt_common_entry,
1765 struct tt_local_entry,
1766 common);
058d0e26
AQ
1767 tt_local_entry_free_ref(tt_local_entry);
1768 }
1769 spin_unlock_bh(list_lock);
1770 }
1771
1772}
1773
1774void tt_commit_changes(struct bat_priv *bat_priv)
1775{
697f2531
AQ
1776 uint16_t changed_num = tt_set_flags(bat_priv->tt_local_hash,
1777 TT_CLIENT_NEW, false);
1778 /* all the reset entries have now to be effectively counted as local
1779 * entries */
1780 atomic_add(changed_num, &bat_priv->num_local_tt);
058d0e26
AQ
1781 tt_local_purge_pending_clients(bat_priv);
1782
1783 /* Increment the TTVN only once per OGM interval */
1784 atomic_inc(&bat_priv->ttvn);
1785 bat_priv->tt_poss_change = false;
1786}
59b699cd
AQ
1787
1788bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
1789{
1790 struct tt_local_entry *tt_local_entry = NULL;
1791 struct tt_global_entry *tt_global_entry = NULL;
1792 bool ret = true;
1793
1794 if (!atomic_read(&bat_priv->ap_isolation))
1795 return false;
1796
1797 tt_local_entry = tt_local_hash_find(bat_priv, dst);
1798 if (!tt_local_entry)
1799 goto out;
1800
1801 tt_global_entry = tt_global_hash_find(bat_priv, src);
1802 if (!tt_global_entry)
1803 goto out;
1804
1805 if (_is_ap_isolated(tt_local_entry, tt_global_entry))
1806 goto out;
1807
1808 ret = false;
1809
1810out:
1811 if (tt_global_entry)
1812 tt_global_entry_free_ref(tt_global_entry);
1813 if (tt_local_entry)
1814 tt_local_entry_free_ref(tt_local_entry);
1815 return ret;
1816}
a943cac1
ML
1817
1818void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
1819 const unsigned char *tt_buff, uint8_t tt_num_changes,
1820 uint8_t ttvn, uint16_t tt_crc)
1821{
1822 uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
1823 bool full_table = true;
1824
1825 /* the ttvn increased by one -> we can apply the attached changes */
1826 if (ttvn - orig_ttvn == 1) {
1827 /* the OGM could not contain the changes due to their size or
1828 * because they have already been sent TT_OGM_APPEND_MAX times.
1829 * In this case send a tt request */
1830 if (!tt_num_changes) {
1831 full_table = false;
1832 goto request_table;
1833 }
1834
1835 tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
1836 (struct tt_change *)tt_buff);
1837
1838 /* Even if we received the precomputed crc with the OGM, we
1839 * prefer to recompute it to spot any possible inconsistency
1840 * in the global table */
1841 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1842
1843 /* The ttvn alone is not enough to guarantee consistency
1844 * because a single value could represent different states
1845 * (due to the wrap around). Thus a node has to check whether
1846 * the resulting table (after applying the changes) is still
1847 * consistent or not. E.g. a node could disconnect while its
1848 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
1849 * checking the CRC value is mandatory to detect the
1850 * inconsistency */
1851 if (orig_node->tt_crc != tt_crc)
1852 goto request_table;
1853
1854 /* Roaming phase is over: tables are in sync again. I can
1855 * unset the flag */
1856 orig_node->tt_poss_change = false;
1857 } else {
1858 /* if we missed more than one change or our tables are not
1859 * in sync anymore -> request fresh tt data */
1860 if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
1861request_table:
1862 bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
1863 "Need to retrieve the correct information "
1864 "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
1865 "%u num_changes: %u)\n", orig_node->orig, ttvn,
1866 orig_ttvn, tt_crc, orig_node->tt_crc,
1867 tt_num_changes);
1868 send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
1869 full_table);
1870 return;
1871 }
1872 }
1873}
This page took 0.159994 seconds and 5 git commands to generate.